ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム...

34
Ruby による超絶技巧プログラミング 遠藤侑介

Upload: mametter

Post on 21-Jan-2017

53.842 views

Category:

Entertainment & Humor


0 download

TRANSCRIPT

Page 1: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

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

遠藤侑介

Page 2: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

宣伝: 翻訳本買ってください

抽象によるソフトウェア設計(Daniel Jackson 著) – 中島震 監訳 ・ 今井健男・酒井政裕・遠藤侑介・片岡欣夫 共訳 (オーム社)

– 会場で買えます!

Types and Programming

Languages (通称 TAPL)

– Benjamin C. Pierce 著

– 絶賛翻訳中!

2

Page 3: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

目次

• 背景: 近年のプログラミングの問題

• 提案: 超絶技巧プログラミング

• 実践

テーマ1: self-descriptive な Ruby プログラム

テーマ2: 文字を制限された Ruby プログラム

• まとめ

3

Page 4: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

近年のプログラミングの問題

• 俗世の欲にまみれすぎ

– 例: プログラミング言語 Ruby の宣伝文句

実用性なんか無くてもプログラミングは楽しい!

4

※個人の感想です

生産性が10倍! 10分でblogが

作れる!

プログラミングが

楽しくなる!

Page 5: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

提案: 超絶技巧プログラミング

• 実用性を無視して美しいプログラムを書く行為

– 普通のプログラミング

– 超絶技巧プログラミング

• 由来: 超絶技巧練習曲 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])

Page 6: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

超絶技巧プログラミングの実践

テーマ 1: self-descriptive な Ruby プログラム

テーマ 2: 文字を制限した Ruby プログラム

6

Page 7: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

例題: 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

Page 8: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

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.@*'')

Page 9: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

self-descriptive FizzBuzz の実装

1. ソースコード自身を文字列として得る

2. 自分自身を次の数字の形に整形する

3. 以上を「実行可能なアスキーアート」として書く

9

1. 自己複製

2. フォント埋め込み

3. 実行可能なアスキーアート

Page 10: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

1. 自己複製

• Quine 、自己出力プログラム、Print Me! とも

• ふつうの自己複製プログラム

※改行は分かりやすさのために入れています

※inspect: 文字列の前後に “ “ をつけるメソッド

• self-descriptive FizzBuzz でも同じ構造

eval s=“

s = ‘eval s=‘ + s.inspect;

puts(s)

10

Page 11: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

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

Page 12: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

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

Page 13: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

以上の技法に基づいた他作品

13

Page 14: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

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

Page 15: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

Qlobe の実装

1. 自己複製する

2. 地球儀をレンダリングして出力する

– 世界地図が zlib 圧縮で埋め込まれてます

3. 邪魔な地球儀はショートカット演算子などで回避

15

“zlib” || “地球部分"

“地球部分” && “H*”

“zlib”

“H*”

Page 16: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

山手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

Page 17: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

自己相似 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'*""

Page 18: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

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

Page 19: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

関連研究

• 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])

Page 20: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

超絶技巧プログラミングの実践

テーマ 1: self-descriptive な Ruby プログラム

テーマ 2: 文字を制限した Ruby プログラム

20

Page 21: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

使える文字を制限して Ruby を書く

• 今日のテーマ: 小文字アルファベット(と空白)だけ

• 実装方針

– 実行したいコードの文字列を構築し、eval する

• 説明の順序

1. アルファベット(大文字含む)+数字だけで書く

2. 大文字を排除する

3. 数字を排除する

21

eval “code”

(Hamaji [2008])

Page 22: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

コード文字列を構築する

• 問題: 文字列リテラルは使えない

• 解決: 文字列を返す組み込み関数を使う

– 例

– nilを文字列に型変換する:空文字列が得られる

– 空文字列に ASCII code で文字を連結していく

22

“code”

クォート使用不可

String nil

“”.concat(65) “A”

“”

“A”.concat(66) “AB”

Page 23: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

ピリオドなしで concat を呼び出す

• 問題: メソッドが呼び出せない

• 解決: String のメソッドからはピリオドなしで呼べる

– Ruby ではカッコは常に省略可能

23

“”.concat(65)

ピリオド・カッコ

使用不可

class String def generate concat 65 concat 66 end end “”.generate

新たな課題: この構築メソッド自身を

どう呼び出すか?

空文字列からコードを

構築するメソッドを定義する

Page 24: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

コード構築メソッドを起動する

• Ruby の for 文

∴ コード構築メソッドを each という名前にすれば

ピリオドなしで呼び出せる

24

for 変数 in コレクション do ... end

コレクション.each do |変数| ... end

for elem in “” do end “”.each ≒

構文糖

Page 25: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

第一段階: アルファベットと数字で 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

Page 26: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

大文字を排除する

• 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

Page 27: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

第二段階: 小文字 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

Page 28: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

数字を排除する(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 が得られる

Page 29: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

数字を排除する(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

Page 30: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

小文字アルファベットだけで 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

Page 31: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

関連研究: 他の文字制限の例

• 記号だけ

• 数字(+ require)だけ

• アンダースコア(+ require) だけ

31

require "1234567890" 3168058133690614704472525542553548167675787479850929569348012322294505786632921189012284531906696218369564670777459615871118090530

require "_" ____ _ _____ ____ __ ____ ____ __ ___ ____ __ __ _ ______ _____ ___ _ _ ___ _____ ______ ____ _ _ ____ _ _ ____ _ ____ __ __ ___ _ ______ ___ ____ __ ______ ____ _ ____ ____ __ _ ____ _ _ ___ _____ _____ _ ______ ____ _ ______ _____

_=[*' '..?~]*'';$><<_[(___=_=~/@/ ).+_=~/¥(/]+_[(__=_=~/_/).+_=~/&/ ]+_[__+@@_=_=~/¥-/]+_[__+@@_]+_[( @_=_=~/~/)-@@_=_=~/¥//]+", "+_[ @_.-_=~/'/]+_[@_-@@_]+_[@_.-_=~ /,/]+_[__.+_=~/¥-/]+_[__.+_=~/%/ ]+?!+$/

(kurimura [2008])

Page 32: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

関連研究: 他言語での文字制限の例

• 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 ?

挑戦者求む!

Page 33: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

目次

• 背景: 近年のプログラミングの問題

• 提案: 超絶技巧プログラミング

–実践1: self-descriptive な Ruby プログラム

–実践2: 文字を制限された Ruby プログラム

• まとめ

33

Page 34: Ruby を用いた超絶技巧プログラミング(夏のプログラミングシンポジウム 2012)

まとめ

• 超絶技巧プログラミングを紹介した

– 実用性を無視して「美しい」プログラミング

• みなさんもいかがでしょうか

– IOCCC開催中

– 9/15 まで

34