この記事は Howtelevision Advent Calendar 2022 の2日目の記事です。
1日目は弊社COOの堅苦しい話で息が詰まりそうなので、ゆるーめの技術系の記事を提供できるよう善処します!
弊社では毎年エンジニアインターンを行っており、今年も8月,9月と開催しました。
インターン最終日には、参加いただいた学生の方の成果物の発表と、社員による LT を行うことが習慣となっています。
本記事では、両日程で LT を行ったので、その内容を書き下そうと思います。
発表内容
brainf*ck のお話をしました。
8つの命令からなるプログラミング言語なっています。 (解説ページ)
主要な命令として、1,2はポインタを移動する命令となっており、3,4はポインタの値を増減させ、6はいわゆる print で、7,8はいわゆる for にあたります。
- <
- >
- +
- -
- ,
- .
- [
- ]
これらの命令でポインタの値を増減させ、任意の ASCII コードにさせることで、最終的に文字列を出力することができます。
そして今回の LT では、社名である「Howtelevision」を出力させることを目標としました。
8月の LT
この段階では、brainf*ck の存在は知っていたものの実際に触ったことはありませんでした。
その上準備時間も少なかったため、とりあえず「Howtelevision」を出力してみたくらいの成果物となりました。
とは言え、独特なプログラミング言語を利用したコードは、やはり引きが強いため、コードの綺麗さはさておき好評を博す事ができました。
成果物
//
で始まる箇所は出力したい文字と、その文字の対応する ASCII コードの値 です。
+
や >
などでポインタを行ったり来たりしつつ、ポインタの値を増減させ、.
で文字を出力しようとしていることが見受けられるかと思います。
// H (ASCII = 72)
++++++++[>++++++++<-]>++++++++.
// o (ASCII = 111)
+++++++++++++++++++++++++++++++++++++++.
// w (ASCII = 119)
++++++++.
// t (ASCII = 116)
---.
// e (ASCII = 101)
---------------.
// l (ASCII = 108)
+++++++.
// e (ASCII = 101)
-------.
// v (ASCII = 118)
+++++++++++++++++.
// i (ASCII = 105)
-------------.
// s (ASCII = 115)
++++++++++.
// i (ASCII = 105)
----------.
// o (ASCII = 111)
++++++.
// n (ASCII = 110)
-.
// \n (ASCII = 10)
----------------------------------------------------------------------------------------------------.
解説
ひとまず H
以外についてですが、非常に単純な命令を行うだけのものとなっています。
o
-> w
へポインタの値を8増加させる必要があるため、+
を8つ連続させたり、他の文字についても+
, -
で単純にポインタの値を増減させているだけになっています。
冒頭の H
だけは毛色が異なっています。
ポインタの値を 0 -> 72 にまで増加させるために、8 * 8 + 8
を命令しています。
- 1つ目のポインタの値を8つ増加させ、その後
[ ]
を利用したループに入りますポインタ 0 1 0x 08 00 -
[ ]
内部では、>
により 2つ目のポインタに移動して8増加しますポインタ 0 1 0x 08 08 - 8増加させたのち
<
により1つ目のポインタに移動して1減少させますポインタ 0 1 0x 07 08 -
[ ]
の終端は隣のポインタの値が0になるまでループをします - そのため2週目が終了する際には
ポインタ 0 1 0x 06 16 - 3週目には
ポインタ 0 1 0x 05 24 - 最終的には以下のようになります
ポインタ 0 1 0x 00 64 - その後は
+
で8つ増加させ72とし.
でH
を出力しますポインタ 0 1 0x 00 72
Python では下記のように表現できそうです。
## ++++++++
p1 = 8
p2 = 0
## [>++++++++<-]
for i in range(p1):
p2 += 8
## >++++++++
p2 += 8
## .
print(f"p2: {p2}")
所感
H
は brainf*ck
の命令を多彩に利用することができていますが、それ以外は誉められたコードではないですね。
ポインタをインクリメント・デクリメントしているだけで非常に冗長なコードとなっています。
本当に「Howtelevision」の出力を目的としただけのコードであり、目を背けたくなるようなコードと言えます。
9月の LT
8月の LT の所感にある通り、特定の文字列の出力はできているものの、H
以外は単純な実装となっていて忸怩たる思いが付き纏っていました。
もっとスマートに表現するには如何にしたら良いかを考え、その成果を9月の LT では発表しました。
成果物
文字と ASCII コードに差はないため省略します。
++[>++[>++<-]<-]>>[<<+++[>+++<-]>>-]<.
>++[>++[>++<-]<-]>>[<<<+++++>>>-]<<<-.
<++[>>++[<++>-]<<-]>.
---.
<+++[>-----<-]>.
[>>+>+<<<-]>>>[<<<+>>>-]
<<<<++[>>++[<++>-]<<-]>-.
>>.
<<<++[>+++++<-]>.
<++++[>----<-]>+++.
>++[>++<-]
<<++[>+++++<-]>.
>>.
<<<++[>--<-]>.
-.
[-]<++[>+++++<-]>.
解説
8月の H
で解説したように、任意の ASCII コードを素因数分解したりなんとかして、[ ]
によるループや、単なるポインタのインクリメントだけでなくポインタの移動も積極的に行うようにしました。
また、詳細は省きますが、e
など複数回出てくる文字については、値をポインタにコピーして再利用可能とするなど DRY な brainf*ck の実装を意識しました。
ブラウザで brainf*ck をデバッグできるサイト もあるので、ぜひコードを実行してポインタの値の遷移や、コードの仕組みを観測していただき、ご興味を持っていただければと思います。
所感
8月の悔しさをバネに、かなり brainf*ck
の命令を多岐に渡り利用したコードにできたのではないかと思います。
特筆すべきは、勝手に「インクリメント・デクリメントの連続利用は5回まで」という制約を設けていたのですが、それをきっちり守った実装ができたことです。
これを実現するためには、2^3
のような命令を行う必要があり [ ]
内でポインタを移動させまくるような非常に脳みそがとろけるような工夫も必要でしたが、8月の悔しさをバネに成し遂げることができました。
まとめ
軽めのプログラミングのネタで簡単に LT するためにはということで、brainf*ck
を選びました。
しかし、8月はその通りに軽い発表をできましたが、brainf*ck
という名称から察するとおり、人の判断を歪める何かが brainf*ck
にはあり、9月の LT の発表準備では、ただ「Howtelevision」という文字を出力したいだけなのに、脳汁を垂れ流しながら、また知恵熱を出しながら、何かに取り憑かれたように brainf*ck
を実装する羽目になりました。
この記事を読んだ皆様が brainf*ck
で好きな文字列を出力するきっかけになれば幸いです。
Advent Calendar としてはだいぶラフな技術系記事となってしまいましたが、ハウテレビジョンではがっつり開発もしております!
ぜひ一緒に取り組んでくれるエンジニアの方、募集しております!