Slide 1

Slide 1 text

クックパッド 春の超絶技巧パンまつり 超絶技巧プログラミング編 講師:遠藤 侑介(@mametter) 1

Slide 2

Slide 2 text

講師:遠藤 侑介(@mametter) •プログラミング言語Rubyの開発が仕事です • ちょっと変なプログラムを書きます 2

Slide 3

Slide 3 text

TA:茂呂 智大 (@slightair) • エンジニア統括マネージャー 兼 モバイル基盤部 部長 • エンジニア組織づくり、採用、社内のモバイルアプリ 開発基盤の環境改善が仕事です • Ruby の開発はしていませんが Ruby はよく書きます、 大好きです • 変なプログラムは書けませんが、それがどうして動く のか考えるのは好きです 3

Slide 4

Slide 4 text

4

Slide 5

Slide 5 text

5 eval$s=%q(;eval" "+%w(z=?¥s;t=z+?¥n;$><<( t*5+"eval$s=%q(#{$s.gsub(/#.*/){ $&.tr(z,?¥x21)}})¥n"+t+(0..6).map{|y |(0..47).map{"co@@@@@@okpad¥x21".upcas e["h7sam@@@@@@b@@ @@jw@@@@@@@24yz3n dq4vk3q@@ @ @@ @@tzcro eg26ut5@ @ @2xbkt rzzvizj@ @j1uy1 ubzk8xhw@ @ @fj3q33 0".to_i(3@@ @@@@@@6)[_1*7 +y]>0?_1/7:@@@ @7]}<¥n}*""+ t*5).gsub(/.@ @+/){$&.strip .center(66)@ @@@@@@@@@@@@@@@}.gsub(/./){t =?¥x21==$&@ @;u=$`.size>1 800;"¥e[@ @48;2;#{u&&t| |z==$&?"@@@@@@@@@@@@@@@@@@255;255;255" :u||$&==?¥x40?"64;28;0":"255;153;51" }m#{(t)?z:$&}¥e[0m"};exit).join. ## (C) 2022 Cookpad Inc. gsub(?¥x40,"")) https://gist.github.com/mame/97d352962539d5065e97487d287e74aa

Slide 6

Slide 6 text

6

Slide 7

Slide 7 text

クックパッドロゴのQuine •Quine:ソースコード自身を 出力するプログラム ※特別な許可をもらって作ってます! 会社のロゴは大切な知的財産なので、 他者のロゴを勝手にQuineにするのはやめましょう 7 eval$s=%q(;eval" "+%w(z=?¥s;t=z+?¥n;$><<( t*5+"eval$s=%q(#{$s.gsub(/#.*/){ $&.tr(z,?¥x21)}})¥n"+t+(0..6).map{|y |(0..47).map{"co@@@@@@okpad¥x21".upcas e["h7sam@@@@@@b@@ @@jw@@@@@@@24yz3n dq4vk3q@@ @ @@ @@tzcro eg26ut5@ @ @2xbkt rzzvizj@ @j1uy1 ubzk8xhw@ @ @fj3q33 0".to_i(3@@ @@@@@@6)[_1*7 +y]>0?_1/7:@@@ @7]}<¥n}*""+ t*5).gsub(/.@ @+/){$&.strip .center(66)@ @@@@@@@@@@@@@@@}.gsub(/./){t =?¥x21==$&@ @;u=$`.size>1 800;"¥e[@ @48;2;#{u&&t| |z==$&?"@@@@@@@@@@@@@@@@@@255;255;255" :u||$&==?¥x40?"64;28;0":"255;153;51" }m#{(t)?z:$&}¥e[0m"};exit).join. ## (C) 2022 Cookpad Inc. gsub(?¥x40,""))

Slide 8

Slide 8 text

今日のテーマ:超絶技巧プログラミング •あえて実用性のないプログラムを書いて遊ぼう • ふつうのRubyコードの話はしません • クックパッドの業務の話もしません 8

Slide 9

Slide 9 text

超絶技巧プログラミングで得られるもの •コンピュータ科学の理論にふれるきっかけ •プログラミング言語についての深い理解 9

Slide 10

Slide 10 text

今日の流れ •13:15~14:15:講義 •14:15~17:00:実習 • 17:00~18:00:発表会 •超絶技巧プログラミングコンテストに投稿を! • TRICK 2022(締切:2022/07/31) • https://github.com/tric/trick2022 10

Slide 11

Slide 11 text

講義内容 •➔超絶技巧プログラミングの事例紹介 • 基本テクニック3点 • プログラムをアスキーアートにする • ターミナルで遊ぶ • Quineを書く 11

Slide 12

Slide 12 text

Quineリレー • 自分自身を出力する REXXプログラム、を出力する rcプログラム、を出力する … Scalaプログラム、を出力する Rustプログラム、を出力する Rubyプログラム https://github.com/mame/quine-relay/blob/master/QR.rb 12

Slide 13

Slide 13 text

Green-square Quine • https://github.com/mame?from=1970-01-01&to=1970-12-31 eval s=%q"n=t • https://github.com/mame/green-square-quine 13

Slide 14

Slide 14 text

もっと見たい人は •参考書をみてください 14

Slide 15

Slide 15 text

講義内容 •超絶技巧プログラミングの事例紹介 •➔基本テクニック3点 • プログラムをアスキーアートにする • ターミナルで遊ぶ • Quineを書く 15

Slide 16

Slide 16 text

Tip 1: アスキーアートプログラム 1. 好きなRubyプログラムを書く 2. 空白と改行と円マーク ¥ を避ける 3. おまじないで囲む 16 puts "Hello world!" puts("Hello"+32.chr+"world!") eval(%w( puts("Hello"+32.chr+"world!") )*"") この範囲を自由に整形できる

Slide 17

Slide 17 text

たとえば 17 eval(%w(put s("Hello"+3 2.chr+"worl d!"))*"") eval(%w(puts( "H el lo "+ 32 .c hr +" world!"))*"") eval(%w(p ut s( "H el lo "+ 32 .c hr +" wo rl d!"))*"") つぶしたり 四角にしたり 円にしたり メソッド名や数字の途中で 改行してもOK 文字列の途中に スペースいれてもOK

Slide 18

Slide 18 text

仕組み •Rubyの%w記法は「文字列の配列」を返す • 配列を掛け算すると連結した文字列になる • evalは文字列をコードとして実行する 18 %w(pu ts( 42)) #=> ["pu", "ts(", "42)"] %w(pu ts( 42))*"" #=> "puts(42)" eval(%w(pu ts( 42))*"") #=> 42

Slide 19

Slide 19 text

練習問題(5分) • 自己紹介を出力するプログラムを イニシャル形状にしてみましょう • 余分はコメント(#)などで埋める • 別のメッセージ・形状でも可 •gistに置いてSlackへ提出ください 19 eval(%w( pu ts ("Yusu Ke -E nd oh,h obby:w al ki ng ") ###### ## ).join) eval(%w(puts("YusuKe -E nd oh,h ob by :w alki ng")## ### ##### ## #### ###### ###### #### ## ## ## #############).join)

Slide 20

Slide 20 text

解説 •正解はありません、動けばOK! •手編集が面倒くさいなあと思ったら→自動化 20 code = %q(puts("YusuKe-Endoh,hobby:walking")).chars puts <

Slide 21

Slide 21 text

Tip 2: ターミナルで色の表示 • "¥e[数字m"で色を指定、"¥e[m" で指定解除する • 最近は"¥e[38;2;R;G;Bm"でRGB指定もできる • 注:cmd.exeやTerminal.appでは動かない • Windows TerminalやiTerm2を使ってください 21 puts "¥e[31mfoo¥e[m" #=> foo(赤い字になる) puts "¥e[41mfoo¥e[m" #=> foo(背景が赤くなる) puts "¥e[38;2;255;0;0mfoo¥e[m" #=> foo puts "¥e[48;2;255;0;0mfoo¥e[m" #=> foo 30黒 40黒 31赤 41赤 32緑 42緑 33黄 43黄 34青 44青 35紫 45紫 36水 46水 37白 47白

Slide 22

Slide 22 text

練習問題(5分) •好きな色付きメッセージを出してみましょう •発展:コードをアスキーアート化しましょう • おまじない eval(%w( ... )*"") で囲む • ヒント:"¥e[数字m" のかわりに 27.chr+"[数字m" 22 $ ruby color-message.rb Hello, world!

Slide 23

Slide 23 text

解説 •たとえば • アスキーアート化するには 23 puts "¥e[37;46mHello¥e[m ¥e[33;41mworld!¥e[m" eval(%w( e = 27.chr; puts(e+"[37;46mHello"+e+"[m"+32.chr+e+"[33;41mworld!"+e+"[m") )*"")

Slide 24

Slide 24 text

なぜ円マークは使えない? •¥ と e の間に空白や改行が入ると動かなくなる • 興味があったら実習時に試してみてください 24 eval(%w( puts("¥ e[37;46mHello¥e[m") )*"") ここに空白が入ると意味が変わる

Slide 25

Slide 25 text

Tip 3: Quine •自分自身を出力するプログラム • 哲学者Willard van Orman Quineに由来 25 $ ruby quine.rb > quine2.rb $ diff –s quine.rb quine2.rb ファイル quine.rb と quine2.rb は同一です

Slide 26

Slide 26 text

間違ったQuineの書き方 • …を出力するプログラム • それを出力するプログラム • それを出力するプログラム • この方針は明らかにきりがない 26 puts "..." puts "puts ¥"...¥"" puts "puts ¥"puts ¥¥¥"...¥¥¥"¥""

Slide 27

Slide 27 text

ただしいQuineの書き方(1) •…を出力するプログラム • このコードを eval で包む • %q[...] は文字列リテラル "..." とほぼ同じ 27 puts "..." s = %q[puts "..."]; eval s

Slide 28

Slide 28 text

ただしいQuineの書き方(2) • … の代わりになるべく↑を出力するようにする 28 s = %q[puts "s = %q[...]; eval s"]; eval s s = %q[puts "..."]; eval s

Slide 29

Slide 29 text

ただしいQuineの書き方(3) •… の位置に入るべき文字列は、変数 s そのもの •答え: 29 s = %q[puts "s = %q[" + s + "]; eval s"]; eval s #=> s = %q[puts "s = %q[" + s + "]; eval s"]; eval s s = %q[puts "s = %q[...]; eval s"]; eval s

Slide 30

Slide 30 text

練習問題(10分) • Quineを実際に動かしてみましょう • ちょっと違う形式でQuineを書いてみましょう • 【やや難】自分自身を反転して出力してみましょう • 【難】自分自身を赤字で出力するようにしましょう • ヒント:%q[...] は %q{...} などに置き換えよう 30 eval(s = %q[puts "...ここを埋める..."]) s = %q[puts "s = %q["+s+"]; eval s"]; eval s

Slide 31

Slide 31 text

解説 •答え: • 文字列内の式展開を使ってもいいです •赤字Quine: 31 eval(s = %q[puts "eval(s = %q[" + s + "])"]) eval(s = %q[puts "eval(s = %q[#{ s }])"]) eval(s = %q{puts 27.chr+"[31meval(s = %q{"+s+"})"+27.chr+"[m"})

Slide 32

Slide 32 text

講義はここまで 32

Slide 33

Slide 33 text

実習 • 好きなプログラムを自由に書いてください • 講義内容を参考にしても、しなくてもよいです • 次ページのネタ案も参考に • 15:30ごろから講師とzoom雑談(1人3分くらい) • 何を作ろうとしてるか講師に聞かせてください! • 17時ごろから発表 • githubに置いてSlack提出してください(gistでも可) 33

Slide 34

Slide 34 text

ネタ案:へんな見た目のプログラム •アスキーアートの形をしたQuine • アスキーアート+色+Quine • 今回の講義内容の組み合わせでできる(はず) • ヒント:Quineの中にアスキーアート化のおまじないをうまく混ぜる • 【難】色がついたまま 実行可能なQuine • ヒント:コード中にエスケープ シーケンスを混ぜる 34 $ ruby quine.rb eval(...色つきコード...) $ ruby quine.rb | ruby eval(...色つきコード...)

Slide 35

Slide 35 text

ネタ案:エンコードQuineを極める • 自分自身を難読化して出力するQuine • ヒント:putsの前にBase64.encode64を通せばよい • 【やや難】自分自身を出力するPythonプログラムを 出力するRubyプログラム • ヒント:Pythonの"""文字列リテラルを使うとちょっと簡単かも 35 $ ruby base64-quine.rb | base64 –d > base64-quine2.rb $ ruby base64-quine.rb | python3 > base64-quine2.rb

Slide 36

Slide 36 text

ネタ案:Quineを進化させる •実行のたびに長くなるQuine風コード • ヒント:普通のQuineにコメント # を足すだけでできます •【難】実行のたびに1増えるQuine風コード 36 eval(s=%q[...ここを埋める...]) #=> eval(s=%q[...ここを埋める....])# #=> eval(s=%q[...ここを埋める.....])## n=1;eval(s=%q[...ここを埋める...]) #=> n=2;eval(s=%q[...ここを埋める...]) #=> n=3;eval(s=%q[...ここを埋める...])

Slide 37

Slide 37 text

ネタ案:アスキーアートを極める •【やや難】コードより大きいアスキーアートを 表示する • 300文字のコードで横40 x 縦20(800文字)の アスキーアートを表示するなど • 圧縮を実装する必要がある • ランレングス圧縮、Byte Pair Encodingあたりが簡単 • 基本的な構造→ 37 data = "アスキーアートを圧縮したデータ" print(展開(data))

Slide 38

Slide 38 text

ネタ案:形状を変化させるQuine •【激難】"A"形状と"B"形状を行き来するQuine • 初期状態は"A"形状 • 実行すると自分自身を"B"の形にして出力する • "B"の形を実行すると"A"に戻る • ヒント:アスキーアート化プログラム+圧縮+Quine 全部組み合わせる必要がある 38

Slide 39

Slide 39 text

ネタ案:アニメーション •端末に何回も上書きする •エスケープシーケンスを使う • ¥e[H • カーソルを画面左上に移動する • ¥e[2J • 画面の内容を全部消す • 参考:https://en.wikipedia.org/wiki/ANSI_escape_code 39 print "¥e[H¥e[2J" (0..).each do |i| print "." * (i%10) print ":" print "." * (9-i%10) print "¥e[H" sleep 0.1 end

Slide 40

Slide 40 text

ネタ案:その他 • 【難?】今日の内容をRuby以外の言語で再現する • evalや%w()がとても便利なことがわかる • 【?】自分の得意な技術と今日の内容を組み合わせる • アスキーアート × 競技プログラミングのアルゴリズム • Quine × Next.js、Quine × Unity、Quine × AI • うまくできたら → https://github.com/tric/trick2022 40

Slide 41

Slide 41 text

余談:哲学者QuineとプログラムQuine(1) •命題: • この命題は真とも偽とも言えない •「この命題」で命題自身を参照してるのが肝 • 次のQuineと同じ構造 41 この命題は偽である puts File.read(__FILE__)

Slide 42

Slide 42 text

余談:哲学者QuineとプログラムQuine(2) •哲学者Quineが研究した間接的自己言及の命題 • 「この命題」みたいなインチキなしで 同じ構造を作り出している • expr => v は v = expr と(ほぼ)同じ意味 • s.dumpは文字列を引用形式にする 42 「は、自身の引用を前置されると偽になる」は、 自身の引用を前置されると偽になる " => s; puts s.dump + s" => s; puts s.dump + s

Slide 43

Slide 43 text

余談:哲学者QuineとプログラムQuine(3) • 自己言及は計算機の理論分野でわりと登場する • 停止性問題 • プログラムが有限時間で停止するかどうかを判定するアルゴ リズムは書けない • クリーネの再帰定理 • チューリング完全な言語では自己言及が構成できる • ゲーデルの不完全性定理 • よくわかりません • 興味があったら→理論計算機科学、数理論理学 43

Slide 44

Slide 44 text

おわり •超絶技巧プログラミングとは、 おもしろい理論・技術をおもしろく実践する遊び •作ったものはぜひ発信していきましょう • 感想記事でも、YouTubeでも、GitHubの肥やしでも • うまくできたら → https://github.com/tric/trick2022 44