Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rubyによる超絶技巧プログラミング

 Rubyによる超絶技巧プログラミング

夏のプログラミングシンポジウム 2012

Yusuke Endoh

August 25, 2012
Tweet

More Decks by Yusuke Endoh

Other Decks in Programming

Transcript

  1. 宣伝: 翻訳本買ってください 抽象によるソフトウェア設計(Daniel Jackson 著) – 中島震 監訳 ・ 今井健男・酒井政裕・遠藤侑介・片岡欣夫

    共訳 (オーム社) – 会場で買えます! Types and Programming Languages (通称 TAPL) – Benjamin C. Pierce 著 – 絶賛翻訳中! 2
  2. 目次 • 背景: 近年のプログラミングの問題 • 提案: 超絶技巧プログラミング • 実践 テーマ1:

    self-descriptive な Ruby プログラム テーマ2: 文字を制限された Ruby プログラム • まとめ 3
  3. 提案: 超絶技巧プログラミング • 実用性を無視して美しいプログラムを書く行為 – 普通のプログラミング  – 超絶技巧プログラミング •

    由来: 超絶技巧練習曲 Transcendental Études – Transcendental: 「肉体・精神・魂のすべてを超越する」 5 alias|send¥ ;$stdin=GC | "%p?"%def# FALSE.gets();(8 | 64).chr+232424. to_s(25)+", "+%w|w ! | *"orlc". next<<012|| (c).Yusuke end;"oh, 2009" | "stegano-X."[0,4].reverse d,be="whydoes","crypto";:make. | %.mains..tr'eams',be.delete(d) puts “Hello, world!” http://ja.wikipedia.org/wiki/超絶技巧練習曲 (Liszt [1826]) 
  4. 例題: FizzBuzz • 数字を 1 から順に出力する、ただし – 3 で割り切れる場合は "Fizz"

    – 5 で割り切れる場合は "Buzz" – 両方で割り切れる場合は "FizzBuzz" を出力する • 普通の Ruby プログラミングで FizzBuzz 7 n = 1 while true case when n % 15 == 0 then puts "FizzBuzz" when n % 3 == 0 then puts "Fizz" when n % 5 == 0 then puts "Buzz" else puts n end n += 1 end
  5. self-descriptive FizzBuzz 8 eval(s=s= %w@proc{| n|z=32.ch r;k="[#{n +=1}]";u= ":>==;<==?"[m=n**4 %-15,m+13]||"#{$f=

    k}";d="Y.E.#{c=64. chr}*'')";$f||d<<z +k;t="eval(s=s=%w# {c+s=s[0, 334]}#$f# ";25.time s{|y|m=u. bytes.map {|v|t<<s; (0..[62-v ,2].min). map{|x|"i f0zgl11p0 zghuhku744d8hzeg41qtfx7xs7t wflr".to_i(36)[x+32+v*3-y/5 *44]<1?z*9:t.slice!(0,9)}<< z}.join.rstrip;y>23&&m[-9,9 ]=d;puts(m)}}[1]#pY.E.@*'')
  6. 1. 自己複製 • Quine 、自己出力プログラム、Print Me! とも • ふつうの自己複製プログラム ※改行は分かりやすさのために入れています

    ※inspect: 文字列の前後に “ “ をつけるメソッド • self-descriptive FizzBuzz でも同じ構造 eval s=“ s = ‘eval s=‘ + s.inspect; puts(s) “ 10
  7. 2. フォント圧縮 • 元データ (横 3 × 縦 5 ×

    約 15 文字 = 210 バイト) • # を 1、空白を 0 にして二進数に • 10 進表示に (64 バイト) • to_s(36) で36進数に (41 バイト) 11 ### # ### ### # # ### ### ### ### ### ### ## # # ## # # # # # # # # # # # # # # # # # ## # # # # ### ### ### ### ### # ### ### ### ## # # # # # # # # # # # # # # # # # # # # # # # ### ### ### ### # ### ### # ### ### # ## ## ## # 111 010 111 111 101 111 111 111 111 111 111 110 000 00 0 101 110 001 001 101 100 100 101 101 101 100 101 101 11 1 101 010 111 111 111 111 111 001 111 111 111 110 101 01 0 101 010 100 001 001 001 101 010 101 001 100 101 101 10 1 111 111 111 111 001 111 111 010 111 111 100 110 011 11 1 1516849080105099949603183465996815374383250973658966149057739167 8hlduayacv7bl0a0h2m2d2ti20qewh0rrsjcmsgpr
  8. 3. 実行可能なアスキーアート 1. コード全体を と で囲む – %w(...) は文字列の配列のリテラル –

    .join は配列を文字列として連結するメソッド 2. eval する 3. 自由に整形できる! %w(foo bar) [“foo”, “bar”] 12  [“foo”, “bar”].join “foobar”  puts “Hi” eval %w( pu ts “H i” ).join## %w( ).join
  9. Qlobe: self-descriptive 地球儀プログラム 14 v=0000;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP 4ZojjV)O>qIH1/n[|2yE[>:ieC "%.#% :::##" 97N-A&Kj_K_><wS5rtWk@*a+Y5

    yH?b[F^e7C/56j|pmRe+:)B "##% ::##########" O98(Zh)'Iof*nm.,$C5Nyt= PPu01Avw^<IiQ=5$'D-y? "##: ###############" g6`YT+qLw9k^ch|K'),tc 6ygIL8xI#LNz3v}T=4W "# #. .####:#######" lL27FZ0ij)7TQCI)P7u }RT5-iJbbG5P-DHB<. " ##### # :############" R,YvZ_rnv6ky-G+4U' $*are@b4U351Q-ug5 " #######################" 00x8RR%`Om7VDp4M5 PFixrPvl&<p[]1IJ " ############:#### %#####" EGgDt8Lm#;bc4zS^ y]0`_PstfUxOC(q " .#############:##% .## ." /,}.YOIFj(k&q_V zcaAi?]^lCVYp!; " %% .################. #. " ;s="v=%04o;ev"% (;v=(v-($*+[45, ":####: :##############% : " ])[n=0].to_i;)% 360)+"al$s=%q#{ "%######. ######### " ;;"%c"%126+$s<< 126}";d.gsub!(/ "##########. #######% " |¥s|".*"/,"");; require"zlib"|| "########### :######. " ;d=d.unpack"C*" d.map{|c|n=(n|| ":#########: .######: . " )*90+(c-2)%91}; e=["%x"%n].pack " :#######% :###### #: " &&"H*";e=Zlib:: Inflate.inflate( " ######% .####% :: " &&e).unpack("b*" )[0];22.times{|y| " ####% %### " ;w=(Math.sqrt(1-( (y*2.0-21)/22)**(; " .###: .#% " ;2))*23).floor;(w* 2-1).times{|x|u=(e+ " %## " )[y*z=360,z]*2;u=u[ 90*x/w+v+90,90/w];s[( " #. " ;y*80)+120-w+x]=(""<< 32<<".:%#")[4*u.count(( " . " ;"0"))/u.size]}};;puts¥ s+";_ The Qlobe#{" "*18+ ( "# :#######" ;"Copyright(C).Yusuke End¥ oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
  10. Qlobe の実装 1. 自己複製する 2. 地球儀をレンダリングして出力する – 世界地図が zlib 圧縮で埋め込まれてます

    3. 邪魔な地球儀はショートカット演算子などで回避 15 “zlib” || “地球部分" “地球部分” && “H*” “zlib” “H*”  
  11. 山手Quine • 実行すると隣の駅名になる • 29 駅で元に戻る z=27;eval$s=%w!c,s=["H+{K}8k->dXNpv-cD~@?(zhAi~>JOv<-;A(]oH+MFKs*+KOB825i$%QX9~P=HC{iIlj*Sh# v=3U62LhUXhtnCx^{F=nuTtGG}@85_(xVvIWQ|Vllp[Gt22x&`^K3*ui;IW@O9-(`Z6V_T.E]%WHXYGa{O9A#msMgV{5 R3XS/dxI8zM)XrbFom,$Msj8>=ca#i.yOqM-gtf2xH T#2VYW9Koq.)IjS:&n3f6$Q/@4-8m_[(HxaP>n*b]Ih/3`3T

    uG-C~3Bn)d.PSdX8 uvtft?;j%bsM^v&h NcaFzv7)uyD=lkc+eYn5&dN/%.|o@pD|BPi+a`rJCgg>?AE; W~){4l9}","_m?PM(N5L <',.ht}f8B|*o8|Qg?:v '(@LY'1^KvIm8twKZHvU@:&FS)r[N1?t9k26*=tiLQw<Tq$l ]V1@Z3hnQ:cQ'b)>])-p }r'U[8hN 7`j6SW r-ZW m2 3n<ZaJ %C%g @@+DABEERjKj5Yt~&>xL ~8BN`L#u?tE+CH$wM%*J px[D;A t%se'c waI. R; FIn( VUVq{0 6c Y]'1EV sqNd_V1yp8"].map{| s|n=0;s.unpack("C*") .map{| c|n=n* 91+( c-1)%9 2};n}; e= "z=#{z =($*[i=0]?(z+1):z- 1)%29};eval$s=%w"<<3 3<<$s[ 0,903] *3;1 4. time s{|y|b =" ";n=f= proc{|w|b<<e[i,w]; i+=w};t=s;f[4];z.dow nto(0){| a|a<1& &6.t imes {|x| y>1&&y<12&&c[n*60+y* 6-x-67]>0?(b<<32<<32):f[2]}while(0<n=(t/=38)%38)};f[4];y>12& &b[-28,28]=""<<33<<"*''#..(c). Yusuke.Endoh.2010";puts(b)}#c,s=["H+{K}8k->dXNpv-cD~@? (zhAi~>JOv<-;A(]oH+MFKs*+KOB825i $%QX9~P=HC{iIlj*Sh#v=3U62LhUXhtnCx^{F=nuTtGG}@85_(xVvIWQ|Vllp[Gt22x&`^K3*ui;IW@O9-(`Z6V_T.E] %WHXYGa{O9A#msMgV{5R3XS/dxI8zM)XrbFom,$Msj8>=ca#i.yOqM-gtf2xHT#2!*''#..(c).Yusuke.Endoh.2010 16 t="+,m-n./mAm0o1p23a4q56r7sBt89u-t-1:v;A<w4x=y1z>[?]A^@CD_ CD_EsF`GHmIJbKa*l";eval$s=%w{F=%q{ceY8#<DvO1=x&t9CSOqMYkzH U.kCpz+Vo8hB.1AF&tq21+$/IrMY]U.aDd!-1y!4MMGQm6m?bYh($QMYpX s4g,x1UlbNKH?>NzbisMn?sT@m3,F.Abb`xW!r%'%Ybee>xkUfjf[(*^Nd Xo_"@hQh%Fx*q[iB7EM"suSG8GVOIzceg/O=4CL,d[-k]twgVP`&wcfaT` 2M)j8sFY?(HKzOrVCHO_694[Uq8g @i/i;tMBG#;-;B]rV[])`3'<os^. OV(SA<=ok%m[iV#qt[&dJ7SIdB;/ VUnVIrH;hEJ*QWD"E+5)gfrmD"#E XlNVv1j)^^ bCi_gw+s-V J<?fWdtbnxRgJm4J.yHO_ay2e%rc Tj]ALVU'`V=]]W;x&9MP&g5zAVHR ?B,SZA+!_[0f!TUCv$Hin?-G7hAL BW6w1x+F#%@FZ<7!9;vNxsj6HW_O Ao)H5cv`Ves-BQ"Z =K$_[o]Can(;1cJp HV<:4x2,AnZgqvsy >VWDZdF-+^ 46Z^Z@<>1< cJ3E4GYSqGg7$ocX 88=*`RVO*WskDY-# uj$t3$XP#U IH]regXHa_ >sta`lbL+=J3sL3e BYxm/a0]lV1?M4WA u7jCGk`UBzB#*gOJ wHu#gQst^XB0VXjT imG<qb[s!* S#":,frD+N wn=nI<u;#dw*Y?"8 B#G[%YT$mvLd<gUd lN^6#bZX$S a#owd125V! 4d+zL5)I;JD-ToJ" uN?h9Braq+dG4Nr[ ynH,hS?nk4JD^/.q KS&kW@(62e]xb0j2(;4X[ROR2W Ifjf^3vhJ5jb5"sJ(4b6Ek1?Vx %s$^.yD.SY$':h[zd$D7o$n: Zp F= 2bHENRzBQhsd_7Im*HZG3xcx t#KdN4D3tEG%#F[1pbo_6C y;kI "Z`: ]^-/]HnWCrJ^=JBA9%gyIr %Xe,D'&Lmb:S<o_(b4VJ ji*bc# G'#ig: AQR[vp>>Jn;Mf$KRBf&7 [%X34447R.0v"Uz/4F "6Q+0>+1 N3OLCeMn ;8TQ>BHCW1";KrW,%P `C?@?)fz>c3B;r 8Q"QCjmU"3 SXd1Jt1qI; "G7HLO$I*6=fCC o!G6CSm1a] S(S#d#sa#2lXP& 4$L"^ir8_BEmkS vA!f@p!$A6 pE@#u%5QJda>[dT>cc4bYcAY)6uF 9%1C4f?GWDcZR`n,%>JrTqK$eHG2 W)B__.[JP+@2qlsWxug,O60@Nkj6VU#Gqp[fC%XOc`:C!-hbr3C0Dz2aLL RI%*4&Lto'OJxHohC=*H#sc][4ZwId0O,R]s<]D#ykgKY7Oc1`heSG/Xxj LA2aiV!<Q;8G/!8>GlX^T4P-/.oIyvR>kPyJ;lXD1r8n5gHPeuA4%j8*0> Iu^>CRxHz3HYX*#n,t_EjxBRbgFH kj:PmmNq3MA10LXwbAW&S^/0_x,H 4d5"_9>K!n6*b(ij`:HQRKf]EJoM NwY>5Si'd#'5BuS8[sF`_[bf9Z<W vdK3HiV+1L.jL*%;&g.G#?S5:Xh$ /gWw#1U-lHTo"?_dxYHC&UGLa)yn %zdU1KPkrE wXsKbTBBix xh=#es7os:-9<`3Olf(!YN!hK?1a,2UMJ^`IC)oc8Z/TipLWy(%p0qUZoO ;W#bB%8=9CZvoU$eG;kXt[hewZnV!(B(u-[L3)l,6C%3.?u?znQyMgw31s [s4Ne+XNPNcpmuaJ<] Hd:/;va-yp4)mU.&Vr Z@*N3mTZX)0]%^]0d6 a'@njg`2DJ;stf^WTr 3y%gWte5;+Q>ZbENlv rK!4M=y6IQ27&IJm>n w57+;)s=Foy<4pdw5i lSDhJRyao%_Wx+[lx6 D8Goea3uRPpunFulWq 0*3GoGaJyAHF$#bJca 5&Z0K'r[o,K*"/^jv6 m08,PTZy$g?eX[aN4j J]AkXcV72;!};f=0;F .unpack("C*").map{ |c|f=f*89+((c-2)%9 0-1)};require'zlib ';t=t.split*"";$*[0]?(t[/([* -K]+.)([*-K]+.)$/];t=$2+$`+s =$1):(s=t[/.+?[L-z]/];t=$'+s );f=Zlib::Inflate.inflate(Ma rshal.dump(f)[7..-1] );S=%{ t="# {t}";eval$s=%w{#$s}* "";%|}+F*9;P=proc{pu ts(S.s lice!(0, 58));P};P[][][][s. upcase.unpack("C*" ).map{|c |c-=c>92?4 3:42;;P[][][20.t imes{|n|puts(("% 029b"%("¥0 "+f[60*c+3*n ,3]).unpack("N ")[0]).gsub( /./){$&<"1"? (S.slice!(0,2) ):(32.chr*2) })}]}][];puts(*["+"+"-"* 25,"|,##,(c),Yusuke,Endoh,20 09".split(",").join(32.chr)].map{|l|S.slice!(0,32)+l})}*"" ;%|ceY8#<DvO1=x&t9CSOqMYkzHU.kCpz+Vo8hB.1AF&tq21+$/IrMY]U. aDd!-1y!4MMGQm6m?bYh($QMYpXs4g,x1UlbNKH?>NzbisMn?sT@m3,F.A bb`xW!r%'%Ybee>xkUfjf[(*^NdXo_"@+------------------------- hQh%Fx*q[iB7EM"suSG8GVOIzceg/O=4| ## (c) Yusuke Endoh 2009
  12. 自己相似 Quine 17 eval$s=%w'k=0000;f= proc{|x,y,s|x*x+y*y*4<36864 &&(u,v=x.round,y.round;x.abs>21 +s||y.abs>4+s||(x*x+(y*2+6)**2<4?f[ x*96,y*96+288,s*192]:u*u<441&&v*v<25&&" 36effv0qbzox5c3npa191hhgzrio5b3640nv9g9jz vnm8a67su".to_i(36)[u-v*41+143]>0))};k=(k+(

    $*[0]||0).to_i)%99;t=("eval$s=%%w%ck=%04o;"%[ 39,k])<<($s[7,530]<<35<<35)*9;s=8/96**(1-k.to_f /98);o=(-11..11).map{|j|(-28..28).map{|i|f[i*s, j*s-36*(8-s)/95,s/4] ??a:32.chr}*""}*10.c hr;o.sub!(/aaaa((#{" Quine ";(s=92.chr)+?s}+a{1 ,3})*#{s+?s}*)#{s+?z }/){39.chr+%(*"")+$1 .tr(?a,?;)};o.gsub!(/a/){t.slice!(0,1)};puts(*o )##f=proc{|x,y,s|x*x+y*y*4<36864&&(u,v=x.round, y.round;x.abs>21+s||y.abs>4+s||(x*x+(y*2+6)** 2<4?f[x*96,y*96+288,s*192]:u*u<441&&v*v<25& &"36effv0qbzox5c3npa191hhgzrio5b3640nv9g9 jzvnm8a67su".to_i(36)[u-v*41+143]>0))}; k=(k+($*[0]||0).to_i)%99;t=("eval$s =%%w%ck=%04o;"%[39,k])<<($s[7,5 30]<<35<<35)*9;s=8/96**(1-k .to_f/98);o=(-1'*"" eval$s=%w'k=0136;f=proc{|x,y,s|x*x+y* y*4<36864&&(u,v=x.round,y.round;x.abs>21+ s||y.abs>4+s||(x*x+(y*2+6)**2<4?f[x*96,y*96+2 88,s*192]:u*u<441&&v*v<25&&"36effv0qbzox5c3npa1 91hhgzrio5b3640nv9g9jzvnm8a67su".to_i(36)[u-v*41+14 3]>0))};k=(k+($*[0]||0).to_i)%99;t=("eval$s=%%w%ck=%0 4o;"%[39,k])<<($s[7,530]<<35<<35)*9;s=8/96**(1-k.to_f/9 8);o=(-11..11).map{|j|(-28..28).map{|i|f[i*s,j*s-36*(8- s)/95,s/4]??a:32.chr}*""}*10.chr;o.sub!(/aaaa((#{"Quine"; (s=92.chr)+?s}+a{1,3})*#{s+?s}*)#{s+?z}/){39.chr+%(*"")+$ 1.tr(?a,?;)};o.gsub!(/a/){t.slice!(0,1)};puts(*o)##f=proc {|x,y,s|x*x+y*y*4<36864&&(u,v= x.round,y.round;x.abs>21+ s||y.abs>4+s||(x*x+(y*2+6)**2<4?f[x*96,y*96+288,s*192]:u* u<441&&v*v<25&&"36effv0qbzox5c3npa191hhgzrio5b3640nv9g9jz vnm8a67su".to_i(36)[u-v*41+143]>0))};k=(k+($*[0]||0).to_i )%99;t=("eval$s=%%w%ck=%04o;"%[39,k])<<($s[7,530]<<35<< 35)*9;s=8/96**(1-k.to_f/98);o=(-11..11).map{|j|(-28..28 ).map{|i|f[i*s,j*s-36*(8-s)/95,s/4]??a:32.chr}*""}*10 .chr;o.sub!(/aaaa((#{"Quine";(s=92.chr)+?s}+a{1,3}) *#{s+?s}*)#{s+?z}/){39.chr+%(*"")+$1.tr(?a,?;)};o .gsub!(/a/){t.slice!(0,1)};puts(*o)##f=proc{| x,y,s|x*x+y*y*4<36864&&(u,v=x.round,y.round ;x.abs>21+s||y.abs>4+s||(x*x+(y*2'*"" eval$s=%w'k=0067;f=proc{|x,y,s|x*x+y*y*4<36864&&(u,v=x.ro und,y.round;x.abs>21+s||y.abs>4+s||(x*x+(y*2+6)**2<4?f[x* 96,y*96+288,s*192]:u*u<441&&v*v<25&&"36effv0qbzox5c3npa19 1hhgzrio5b3640nv9g9jzvnm8a67su".to_i(36)[u-v*41+143]>0))} ;k=(k+($*[0]||0).to_i)%99;t=("eval$s=%%w%ck=%04o;"%[39,k] )<<($s[7,530]<<35<<35)*9;s=8/96**(1-k.to_f/98);o=(-11..11 ).map{|j|(-28..28).map{|i|f[i*s,j*s-36*(8-s)/95,s/4]??a:3 2.chr}*""}*10.chr;o.sub!(/aaaa((#{"Quine";(s=92.chr)+?s}+ a{1,3})*#{s+?s}*)#{s+?z}/){39.chr+%(*"")+$1.tr(?a,?;)};o. gsub!(/a/){t.slice!(0,1)};puts(*o)##f=proc{|x,y,s|x*x+y*y *4<36864& &(u ,v=x.roun d,y.round ;x.abs>2 1 + s||y.abs> 4+s||(x*x +( y*2 +6)**2<4? f[x*96,y* 96 + 288 ,s *19 2]: u*u<441 &&v* v< 25&&"36ef fv0qbzox5 c3 npa19 1h hgz rio 5b3 640 nv9g9jz vnm8a67su ".to_i(36 )[ u-v* 41 +14 3]> 0)) };k =(k +($*[0]|| 0).to_i)% 99;t=(" ev al$s=% %w% ck= %04 o;"%[3 9,k])<<($ s[7,530]< <35<<35)* 9;s=8/96**(1-k.to_f/98);o=(-11..11).map{|j|(-28..28).map{ |i|f[i*s,j*s-36*(8-s)/95,s/4]??a:32.chr}*""}*10.chr;o.sub !(/aaaa((#{"Quine";(s=92.chr)+?s}+a{1,3})*#{s+?s}*)#{s+?z }/){39.chr+%(*"")+$1.tr(?a,?;)};o.gsub!(/a/){t.slice!(0,1 )};puts(*o)##f=proc{|x,y,s|x*x+y*y*4<36864&&(u,v=x.ro'*"" eval$s=%w'k=0054;f=proc{|x,y,s|x*x+y*y*4<36864&&(u,v=x.ro und,y.round;x.abs>21+s||y.abs>4+s||(x*x+(y*2+6)**2<4?f[x* 96,y*96+288,s*192]:u*u<441&&v*v<25&&"36effv0qbzox5c3npa19 1hhgzrio5b3640nv9g9jzvnm8a67su".to_i(36)[u-v*41+143]>0))} ;k=(k+($*[0]||0).to_i)%99;t=("eval$s=%%w%ck=%04o;"%[39,k] )<<($s[7,530]<<35<<35)*9;s=8/96**(1-k.to_f/98);o=(-11..11 ).map{|j|(-28..28).map{|i|f[i*s,j*s-36*(8-s)/95,s/4]??a:3 2.chr}*""}*10.chr;o.sub!(/aaaa((#{"Quine";(s=92.chr)+?s}+ a{1,3})*#{s+?s}*)#{s+?z}/){39.chr+%(*"")+$1.tr(?a,?;)};o. gsub!(/a/){ t.sli ce!(0,1)};p uts (*o ) ##f= pro c {|x, y,s| x*x+ y*y* 4<36864&&(u ,v=x.rou n d,y. roun d;x. abs> 21+s||y.abs >4+s||(x * x+ (y*2 +6)* *2<4 ?f[x *96,y *96+28 8,s*19 2 ] :u *u<4 41&& v*v< 25&& "36ef fv0qbz ox5c3n p a 191hhgz rio5 b364 0nv9 g9jzv nm8a 67su".to_ i (36)[u -v*4 1+14 3]>0 ))};k =(k+ ($*[ 0 ]||0). to_i )%99 ;t=( "eval $s=% %w%c k=%04o;"% [39 ,k])<<($s[7 ,530 ]<<35 <<35 )*9;s=8/ 96**(1-k.to_f/98);o=(-11..11).map{|j|(-28..28).map{|i'*"" eval$s=%w'k=0026;f=proc{|x,y,s|x*x+y*y*4<36864&&(u,v=x.ro und,y.round;x.abs>21+s||y.abs>4+s||(x*x+(y*2+6)**2<4?f[x* 96,y*96+288,s*192]:u*u<441&&v*v<25&&"36effv0qbzox5c3npa19 1hhgzrio5b3640nv9g9jzvnm8a67su".to_i(36)[u-v*41+143]>0))} ;k=(k+($*[0]||0).to_i)%99;t=("eval$s=%%w%ck=%04o;"%[39,k] )<<($s[7,530]<<35<<35)*9;s=8/96**(1-k.to_f/98);o=(-11..11 ).map{|j|(-28..28).map{|i|f[i*s,j*s-36*(8-s)/95,s/4]??a:3 2.chr}*"" }*10.chr;o.su b!(/aaaa((#{"Qu ine";(s=92.chr)+? s}+a{1, 3})*#{s +?s}*)#{s+?z}/){3 9.chr+%(*"")+$1 .tr(?a,?;)} ;o. g sub!(/a/){t.s lice!(0,1)};p uts(*o)##f=pr o c{|x,y,s|x*x+ y*y*4<36864&& (u,v=x.round, y .round;x.abs> 21+s||y.abs>4 +s||(x*x+(y*2 + 6)**2<4?f[x*9 6,y*96+288,s* 192]:u*u<441& & v*v<25&&"36ef fv0qbzox5c3np a191hhgz'*"" eval$s=%w'k=0013;f=proc{|x,y,s|x*x+y*y*4<36864&&(u,v=x.ro und,y.round;x.abs>21+s||y.abs>4+s||(x*x+(y*2+6)**2<4?f[x* 96,y*96+288,s*192]:u*u<441&&v*v<25&&"36effv0qbzox5c3npa19 1hhgzrio5b3640nv9g9jzvnm8a67su".to_i(36)[u-v*41+143]>0))} ;k=(k+($* [0]||0).to_i)%99; t=("eval$s=%%w%ck=%04 o;"%[39,k])<<($s[7,530]<< 35<<35)*9;s=8/96**(1-k.to_f /98);o=(-11..11).map{|j|(-2 8..28).map{|i|f[i*s,j*s-36*(8 -s)/95,s/4]? ?a: 32.chr}*""}* 10.chr;o.sub!(/aaaa((#{"Quine ";(s=92.chr)+?s}+a{1,3})*#{ s+?s}*)#{s+?z}/){39.chr+% (*"")+$1.tr(?a,?;)};o.g sub!(/a/){t.slice!(0, 1)};puts(*o)##f =pr oc{|x,y,s|x*x+y*y* 4<36864&&(u,v=x.r'*"" ;;; eval$s=%w'k=0000;f= proc{|x,y,s|x*x+y*y*4<36864 &&(u,v=x.round,y.round;x.abs>21 +s||y.abs>4+s||(x*x+(y*2+6)**2<4?f[ x*96,y*96+288,s*192]:u*u<441&&v*v<25&&" 36effv0qbzox5c3npa191hhgzrio5b3640nv9g9jz vnm8a67su".to_i(36)[u-v*41+143]>0))};k=(k+( $*[0]||0).to_i)%99;t=("eval$s=%%w%ck=%04o;"%[ 39,k])<<($s[7,530]<<35<<35)*9;s=8/96**(1-k.to_f /98);o=(-11..11).map{|j|(-28..28).map{|i|f[i*s, j*s-36*(8-s)/95,s/4] ??a:32.chr}*""}*10.c hr;o.sub!(/aaaa((#{" Quine ";(s=92.chr)+?s}+a{1 ,3})*#{s+?s}*)#{s+?z }/){39.chr+%(*"")+$1 .tr(?a,?;)};o.gsub!(/a/){t.slice!(0,1)};puts(*o )##f=proc{|x,y,s|x*x+y*y*4<36864&&(u,v=x.round, y.round;x.abs>21+s||y.abs>4+s||(x*x+(y*2+6)** 2<4?f[x*96,y*96+288,s*192]:u*u<441&&v*v<25& &"36effv0qbzox5c3npa191hhgzrio5b3640nv9g9 jzvnm8a67su".to_i(36)[u-v*41+143]>0))}; k=(k+($*[0]||0).to_i)%99;t=("eval$s =%%w%ck=%04o;"%[39,k])<<($s[7,5 30]<<35<<35)*9;s=8/96**(1-k .to_f/98);o=(-1'*""
  13. 15quzzle Quine でパネル移動後の盤面が出てくる eval$s=%w[b=0 x40e1359a76cb d8f2;i=(m=0.. 15).find{|i|1 >b&m=15<<4*i} ;t=m|n=m<<4*o =("AdABrBlBAu

    A"=~/(.)#{ARG V*''}¥1/||04| |0)-4;(n<1||n >1<<64||[255< <12]&[t>>040| |___________2 |__________15 |___________8 |__________13 |0,t>>16,t]!= [])?t=0:i+=o; ;s="eval$s=%% w[b=0x%016x"% (b^=t.&b|m&b> >o*4)+$s.gsub (/(¥|_+¥d+)+/ ,'')[/;.*/]+" ]*''||0"<<92| |1;z=s=s.scan (/.{13}/);3.t imes{|j|s[(i| |__________11 |__________12 |___________6 |___________7 |0)/4*8+i+j*4 ,0]=m=(z=32.c hr)*13};c=b;4 .times{puts(( 0..3.times{pu ts((s.slice!( 0,4)*z).rstri p)}).map{j=c% 16;c/=16;;(0| |0)<(j)?"|"+j .to_s.rjust(1 2,"_"):m}*(z| |__________10 |___________9 |___________5 |___________3 |0),z)};b==0x fedcba9876543 21&&("%b"%"1t v7c1th0wylel7 3ba35knw3t".t o_i(36)).tr(" 01",".#").sca n(/.{25}/){pu ts$&}]*''||0¥ |___________1 |__________14 |___________4 18
  14. 関連研究 • International Obfuscated C Code Contest (IOCCC) – みにくい

    C コードを書くコンテスト 19 #define _ -F<00||--F-OO--; int F=00,OO=00;main(){F_OO(); printf("%1.3f¥n",4.*-F/OO/OO);}F_OO() { _-_-_-_ _-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_ _-_-_-_ } #include <stdio.h> #include <math.h> (略) int main(int argc,char** argv){ if(argc<2){ puts( usage: calculator 11/26+222/31 +~~~~~~~~~~~~~~~~~~~~~~~~calculator-¥ ! 7.584,367 ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ ! clear ! 0 ||l -x l tan I (/) | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ ! 1 | 2 | 3 ||l 1/x l cos I (*) | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ ! 4 | 5 | 6 ||l exp l sqrt I (+) | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ ! 7 | 8 | 9 ||l sin l log I (-) | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(0 ); } return 0; } 円周率計算プログラム 電卓プログラム (westley [1988]) (hou [2011])
  15. 使える文字を制限して Ruby を書く • 今日のテーマ: 小文字アルファベット(と空白)だけ • 実装方針 – 実行したいコードの文字列を構築し、eval

    する • 説明の順序 1. アルファベット(大文字含む)+数字だけで書く 2. 大文字を排除する 3. 数字を排除する 21 eval “code” (Hamaji [2008])
  16. コード文字列を構築する • 問題: 文字列リテラルは使えない • 解決: 文字列を返す組み込み関数を使う – 例 –

    nilを文字列に型変換する:空文字列が得られる – 空文字列に ASCII code で文字を連結していく 22 “code” クォート使用不可 String nil “”.concat(65) “A”  “”  “A”.concat(66) “AB” 
  17. ピリオドなしで concat を呼び出す • 問題: メソッドが呼び出せない • 解決: String のメソッドからはピリオドなしで呼べる

    – Ruby ではカッコは常に省略可能 23 “”.concat(65) ピリオド・カッコ 使用不可 class String def generate concat 65 concat 66 end end “”.generate 新たな課題: この構築メソッド自身を どう呼び出すか? 空文字列からコードを 構築するメソッドを定義する
  18. コード構築メソッドを起動する • Ruby の for 文 ∴ コード構築メソッドを each という名前にすれば

    ピリオドなしで呼び出せる 24 for 変数 in コレクション do ... end コレクション.each do |変数| ... end for elem in “” do end “”.each ≒ 構文糖
  19. 第一段階: アルファベットと数字で Ruby 例: コード文字列 “p 1” を構築・ eval するコード

    25 class String def each concat 112 concat 32 concat 49 eval self exit end end for i in String nil do end “” “p” “p ” “p 1” concat 112 concat 32 concat 49 文字列を構成する様子 eval
  20. 大文字を排除する • String の ”S” が 2 箇所 • class

    String の箇所 – String クラスには定義できない – トップレベルは Object クラス  トップレベルに定義すればよい • String nil の箇所 – 文字列を返す別のメソッドにする – String#clear で空文字列に 26 class String def each ... end end for i in String nil do end public def each ... end for i in String nil do end public def each ... end for i in inspect do end public def each clear ... end for i in inspect do end
  21. 第二段階: 小文字 alphabetと数字で Ruby 例: “1” を出力するコード 27 public def

    each clear concat 112 concat 32 concat 49 eval self exit end for i in inspect do end class String def each concat 112 concat 32 concat 49 eval self exit end end for i in String nil do end
  22. 数字を排除する(1) • 欲しい数字の長さの文字列を作り size を呼ぶ – 例: 8 を生成するコード •

    今まで構築してきたコードが消えてしまう! 28 clear # “” concat size # “¥0” concat self # “¥0¥0” concat self # “¥0¥0¥0¥0” concat self # “¥0¥0¥0¥0¥0¥0¥0¥0” size # 23 = 8 が得られる
  23. 数字を排除する(2) • 例外処理の構文 – Java の try { A }

    finally { B } みたいなもの • 式全体が A の評価結果を返す – A を評価し – B を評価し – B の評価結果を捨てて A の評価結果を返す構文 • 文字列の先頭に 1 文字追加 するイディオムが作れる 29 begin A ensure B end concat begin dup ensure concat begin 65 を作る ensure clear end end “...” 現在の self “A...” 新しい self
  24. 小文字アルファベットだけで Ruby を書く 30 loop do break public end catch

    inspect do def each loop do break clear end concat begin dup ensure clear concat concat concat concat size loop do break concat concat size end loop do break concat concat size end loop do break concat size end concat begin size ensure clear end end concat begin dup ensure clear concat concat concat concat concat concat size loop do break concat size end concat begin size ensure clear end end concat begin dup ensure clear loop do break concat concat size end concat concat concat concat size concat concat concat size concat begin size ensure clear end end concat begin dup ensure clear loop do break concat concat size end concat concat concat size loop do break concat concat size end concat concat concat size concat begin size ensure clear end end concat begin dup ensure clear loop do break concat concat size end loop do break concat concat size end concat concat concat concat size loop do break concat concat size end concat begin size ensure clear end end concat begin dup ensure clear loop do break concat concat size end concat concat concat size loop do break concat concat size end loop do break concat concat size end loop do break concat concat size end loop do break concat size end concat begin size ensure clear end end concat begin dup ensure clear loop do break concat concat size end loop do break concat concat size end concat concat concat size loop do break concat concat size end loop do break concat concat size end loop do break concat size end concat begin size ensure clear end end concat begin dup ensure clear concat concat concat concat concat concat size concat begin size ensure clear end end concat begin dup ensure clear concat concat concat size loop do break concat concat size end concat concat concat size concat begin size ensure clear end end concat begin dup ensure clear loop do break concat concat size end concat concat concat size loop do break concat concat size end loop do break concat concat size end loop do break concat concat size end loop do break concat size end concat begin size ensure clear end end concat begin dup ensure clear loop do break concat concat size end concat concat concat size loop do break concat concat size end concat concat concat size concat begin size ensure clear end end concat begin dup ensure clear loop do break concat concat size end concat concat concat size loop do break concat concat size end concat concat concat size concat begin size ensure clear end end concat begin dup ensure clear loop do break concat concat size end concat concat concat concat size concat concat concat size loop do break concat size end concat begin size ensure clear end end concat begin dup ensure clear concat concat concat concat size concat concat concat concat size concat begin size ensure clear end end concat begin dup ensure clear concat concat concat concat size loop do break concat concat size end loop do break concat concat size end loop do break concat size end concat begin size ensure clear end end concat begin dup ensure clear loop do break concat concat size end loop do break concat concat size end concat concat concat concat size loop do break concat concat size end loop do break concat size end concat begin size ensure clear end end concat begin dup ensure clear loop do break concat concat size end loop do break concat concat size end concat concat concat size concat concat concat size concat begin size ensure clear end end concat begin dup ensure clear loop do break concat concat size end loop do break concat concat size end concat concat concat size concat concat concat size loop do break concat size end concat begin size ensure clear end end concat begin dup ensure clear loop do break concat concat size end loop do break concat concat size end concat concat concat concat concat size concat begin size ensure clear end end loop do break eval self end loop do exit end end end for each in inspect do copyright mmxii yusuke end o h loop do break public end catch inspect do def each loop do break clear end concat begin dup ensure clear concat concat concat concat size loop do break concat concat size end loop do break concat concat size end loop do break concat size end concat begin size ensure clear end end concat begin dup ensure clear concat concat concat concat concat concat size loop do break concat size end
  25. 関連研究: 他の文字制限の例 • 記号だけ • 数字(+ require)だけ • アンダースコア(+ require)

    だけ 31 require "1234567890" 316805813369061470447252554255354 816767578747985092956934801232229 450578663292118901228453190669621 8369564670777459615871118090530 require "_" ____ _ _____ ____ __ ____ ____ __ ___ ____ __ __ _ ______ _____ ___ _ _ ___ _____ ______ ____ _ _ ____ _ _ ____ _ ____ __ __ ___ _ ______ ___ ____ __ ______ ____ _ ____ ____ __ _ ____ _ _ ___ _____ _____ _ ______ ____ _ ______ _____ _=[*' '..?~]*'';$><<_[(___=_=~/@/ ).+_=~/¥(/]+_[(__=_=~/_/).+_=~/&/ ]+_[__+@@_=_=~/¥-/]+_[__+@@_]+_[( @_=_=~/~/)-@@_=_=~/¥//]+", "+_[ @_.-_=~/'/]+_[@_-@@_]+_[@_.-_=~ /,/]+_[__.+_=~/¥-/]+_[__.+_=~/%/ ]+?!+$/ (kurimura [2008])
  26. 関連研究: 他言語での文字制限の例 • Perl: 記号だけ • Javascript – 記号だけ –

    顔文字だけ 32 (Takesako [2005]) (Hasegawa [?]) (Hasegawa [?]) 2005/08/27 Lightweight Language Day and Night 4 Quiz: これは何をするプログラムでしょう? #!/usr/bin/perl sin cos and s qq qx xor s x x print uc chr lc ord qq sleep times x xor int log cos xor eval and eval and print uc chr ord scalar reverse qq exit binmode xor qq write qw xor print uc chr ord scalar reverse qw tell my print 正解 → 標準出力に “LLDN” という文字列を出力するプログラム 2005/08/27 Lightweight Language Day and Night 18 まとめ  Let’s 予約語プログラミング♪  Perl 以外の言語でも実装できますか?  awk ?  Haskell ?  Lisp ?  ML ?  Perl → OK !  PHP ?  Python ?  Ruby ? 挑戦者求む!
  27. 目次 • 背景: 近年のプログラミングの問題 • 提案: 超絶技巧プログラミング – 実践1: self-descriptive

    な Ruby プログラム – 実践2: 文字を制限された Ruby プログラム • まとめ 33