SlideShare une entreprise Scribd logo
1  sur  69
Télécharger pour lire hors ligne
Cookpad Spring 1day Internship
2018
超絶技巧プログラミングコース
Yusuke Endoh (@mametter)
今日の目的
• 技巧を駆使した実用性のないプログラムを
作成する「超絶技巧プログラミング」を習得する
今日のテーマ
超絶技巧 プログラミング
3
Transcendental Programming
フランツ・リストのピアノ曲
「超絶技巧練習曲」より借用
Transcendental Ètudes
4
今日のテーマ
超絶技巧 プログラミング
=世俗を超越したプログラミング
5
Transcendental Programming
技巧を駆使して
実用性のないプログラムを作成する遊び
超絶技巧プログラミングで得られるもの
• コンピュータ科学の理論を実践する体験
– ×「才能の無駄遣い」
– 〇「コンピュータ科学 50 年の歴史の無駄遣い」
• 知らない技術に触れるきっかけ
• ふつうには出会わない新鮮な制約・価値観
• プログラミング言語の無限の可能性
今日の流れ
• 午前:講義
– 超絶技巧プログラミングのテクニックを駆け足で学ぶ
• 12時~13時:昼食
• 13時~16時:実習
• 16時~:発表会
– 作ったプログラムをお互いに紹介しあう
• うまくできたらコンテストに投稿を!
– TRICK FINAL(締切:2018/03/31)(遠藤が運営メンバ)
– IOCCC25(締切:2018/03/15 03:08:07 UTC)
ここで 15 分くらい?
講義の流れ
• 超絶技巧プログラムの紹介
• 超絶技巧プログラミング入門
• 超絶技巧プログラム事例解説
Quine-relay
eval$s=%q(eval(%w(B=92.chr;g=32.chr;puts(eval(%q(N=10.chr;n=0;e=->s{Q[Q[s,B],?"].K(N,B+?n)};E=->s{'("'+e[s]+'")'};d=->s,t=?"{s.K(t){t+t}};def~f(s,n)s.K(/.{1,#{n*255}}/m){yield$S=E[$s=$&]}end;Q=->s,t=?${s.K(t){B+$&}};R=";return~0;";V=->
s,a,z{s.K(/(#{B*4})+/){a+"#{$&.size/2}"+z}};C=%w(System.Console~Write);$C=C*?.;$D="program~QR";$G="~contents~of"+$F="~the~mix!g~bowl";$L="public~static";rp=->s,r{v="";[r.!ject(s){|s,j|o={};m=n=0;s.size.times{|i|o[f=s[i,2]]||=0;c=o[f]+=
1;m<c&&(m=c;n=f)};v=n+v;s.K(n,(j%256).chr)},v]};%(fn~mX{Z`x21("{}",#{E["object~QR~extends~App{#{f(%((display~"#{e[%(Zf("1d;s/.//;s/1/~the~sum~of~a~son~and0/g;s/0/~twice/g;s/2/`x59ou~are~as~bad~as/g;s/3/~a~son`x21Speak~your~m!d`x21/g^n#
The~Relay~of~Qu!e.^n#Ajax,~a~man.^n#Ford,~a~man.^n#Act~i:~Qu!e.^n#Scene~i:~Relay.^n#[Enter~Ajax~and~Ford]^n#Ajax:^n#");function[]=f(s);for~i=1:2:length(s),Zf("2%s3",part(dec2b!(hex2dec(part(s,i:i+1))),$:-1:2)),end;endfunction`n#{s,v=rp
["Transcript~show:~'#{d["Z"+E[%(fun~p~n=Z(Int.toSJ~n`x5e"~");p~0;p~0;p~130;List.tabulate(127,p);SJ.map(fn~c=>(p(3+ord~c);Z"-1~0~";c))#{E[%(puts~"#{Q[e[%(echo~'a::=`x7e#{Q[Q["let~s=#{E["!t~mX{Z#{d[E[%(module~QR;!itial~beg!~#{f("let~s=#{
E[%(Module~QR:Sub~MX:Dim~s,n,i,c~As~Object:n=Chr(10):For~Each~c~!"#{d["<?xml#{O="~version='1.0'"}?><?xml-#{I="stylesheet"}~type='text/xsl'href='QR.xslt'?><xsl:#{I+O}~xmlns:xsl='http://www.w3.org/1999/`x58SL/Transform'><xsl:output~metho
d='text'/><#{U="xsl:template"}~match='/'><`x21[CDATA[#{%(sub~f(s$,n)Z(s$);:for~i=1to~n~Z("Y");:next:end~sub:f("#{V[e[%(H,format="#{y="";f("^H{-}{txt}{#{Q["echo~-E~$'#{Q[Q[E[%(with~Ada.Text_Io;procedure~qr~is~beg!~Ada.Text_Io.Put("#{d[%
(!terp:library"afnix-sio"`ntrans~O(n){trans~o(afnix:sio:OutputTerm)`no:H(Byte(+~128~n))}`ntrans~f(v~n){`nO(+(/~n~64)107)`nO(n:mod~64)`nO~v}`ntrans~D(n){if(<~n~4){f(+(*~6~n)9)48}{if(n:odd-p){D(-~n~3)`nf~27~48`nf~36~11}{D(/~n~2)`nf~21~48
`nf~48~20}}}`ntrans~S"#{e[%W[STRINGz:=~226+~153,a:=z+~16 6,b:=a+"2 "+z+~160,c:=b+"8"+z+~165,t:="#!clude<iostream>"+~(10)+"!t"+~(32)+"mX{puts#{d[E[%(class~QR{#$L~void~ma!(SJ[]v){System.out.Z(#{E["H('#{Q[e["implement~ma!0()=Z"+E["BEGIN{
Z#{E[%(echo~'#{%(f(s){System.out.Z(s);}s="389 **6+44 *6+0 0p45*,"; for(c:#{E[(s="#!clude<iostream>`n!t~mX{std::cout<<#{E[%(class~Program{#$L~void~MX{#$C("Qu!e~Relay~Coffee.^n^nIngredients.^n");for(!t~i=9;i++<126;)#$C($"{i}~
g~caffe!e~{i}^n");#$C("^nMethod.^n");foreac h(c h ar~c~!#{E[%((doseq[s(lazy-cat["IDENTIFICATION~DIVISION.""PROGRAM-ID.~QR.""PROCEDURE~ DIVISION."'DISPLA`x59](map~#(str"~~~~^""(.replace~%1"^"""
^"^"")"^"&")(re-seq~#".{1,45}""#{e["(f=(n )- >Array(n+1).jo!~'Y');console.log('%s',#{V[E[%((H-l!e"#{e["impor t~std.stdio;void~mX{H(`x60#{%(method~MX{Z(@"#{d["
[#{%(class~QR:Application{void~f(SJ~con st~s,!t~n){for(Pr!t(s);n;n--)Pr!t("Y");}void~MX{#{f("IO.puts "+E[%((pr!c~"#{e["`nma!(_)->`nio:fH#{d[E['Zf
n("""'+d[?"+"%option~noyywrap`n%%`n%%` n!t~mX{puts#{E["echo~'#{Q[Q[%(~:~A~."#{g*9}"~;~:~ B~A~."~WRITE(*,*)'"~A~;~:~C~B~T`x59PE~."
~'"~CR~;~:~D~S"~#$D"~C~S^"~Z~^"(&"~C~ S^"~#{e[%(Z"#{e["s:=OutputTextUser();Write All(s,#{E[%(Zf"#{e[d[f('set~Z"-";Z'+E
[%(package~ma!;import"fmt";func~mX{ fmt.Pr!t#{E[%(236:j;{119:i;{206i-:i;.48<{ 71+}{[i]^48-*}if}%}:t;"algoritmo~Q
R;!"[195][173]++'cio~imprima("'"0 1314 1"t"/12131"t~6*"/1:1918151:??62714 13/4=3626612/2 /353251215/`x5a0`x5a0R"t"#{e[%(
show~"z=new~java.util.zip.G`x5aI POutp utStream(System.out);z.H('#{ "ma!=putStr"+E["class~QR{#$L ~function~mX{neko.Lib.Z#{E[%(p
rocedure~mX;i:=c:=0;s:=#{E[%(.c lass ~public~QR`n.super~#{$T="ja va/io/Pr!tStream"}`n.method~#$L~ma!([L #{S="java/lang/S"}J;)V~;]`n.
limit~stack~2`ngetstatic~#{S}ys tem/out~L#$T;`nldc~"#{ e[%(class~QR{#$L~void~ ma!(SJ[]v){SJ~c[]=new~SJ[99999],y="",z=y,s=" #{z=t=(0..r=q=126).map{|n|
[n,[]]};a="";b=->n{a<<(n%78+55) %84+ 42};(%(P={0:'[+[]]',m:'((+[])'+(C= "['constructor']" )+"+[])['11']"};for(R~!~B=('`x21[]@`x21`x21[]@[][[ ]]@'+(A="[]['fill']")+"@(
[]+[])['fontcolor']([])@(+('11e20 ')+[])['split']([])@"+A+C+"('return~escape')()("+ A+')').split( '@'))for(E~!~D=eval(G='('+B[R]+'+[])'))P[T=D[E]]=P[T]| |G+"['"+E+"']";for(G='[
',B=0;++B<36;)P[D=B.toSJ(36)]= B<10?(G+='+`x21+[]')+']':P[D]||"(+('"+B+"'))['to'+( []+[])"+C+"[ 'name']]('36')";A+=C+"('console.log(unescape(^"";for(E~!~G =#{E[%(A=Z;A("echo~'k`
x60");[(A("`x60`x60s"`x5e8* "i");for~j=6:-1:0;x=(Int(c)>>j)%2+1;A("`x60"*"kki"[x:x+1 ])end)fo r~c~!~jo!(["Section`x48eader+name:=QR;SectionPublic-ma!<-(";[ "^"$(replace(replace(
s,"Y","YY"),"^"","Y^""))^" .Z;"for~s=matchall(r".{1,99}",#{Q[E["console.log"+Q[E[%(@s=g loba l[#{i=(s=%(`x48AI~1.2`nVISIBLE~"#{"x=sJ.K(#{V[E["changequote(<@,@ >)`ndef!e(p,<@#{"all
:`n`t@echo~'#{d["l!el:99 999;Z#{E["solve~satisfy;output~[#{E[%(.assembly~t{}.method~#$L~ vo id~MX{.entrypo!t~ldstr"#{e["m{{`x21:~x`nqr:~|-`n~:db`x60#{e[s="$Z#{E[%(#!clude< stdio.h>`nmodule~QR{
}implementation{!t~mX_ _attribute__((C,spontaneous)){puts#{E["Zf#{E["echo"+E["#import<stdi o.h>#{ N}!t~mX{puts#{E["Z_sJ"+E["s=toascii#{E["Z#{E["$console:l!e[#{"# $D(output);beg!~H(#
{f((p="eval";%($_="#{ s,v=rp["$_='#{Q[%(<?php~$z=3+$w=strlen($s=#{Q[E["!t~mX{H#{E["(#{?_*11} )dup~=/s(|~~~~~.~~~|)def(#{Q["qr:-H('#{Q[e["!it{#{f (%(Z('cat("')`nfor
~c~!"".jo!(["echo~'s ay~''%s'''^n"%l~for~l~!#{E[d[d["eval$s=%q(#$s)",?'],?']]}.split("^n")]): Z('r=fput(char(%d))'%ord(c))`nZ('end^n")')#),6 ){"Zf#{d[$S,?%]};"
}}}"],?']}').",B]}) {9~7{exch~dup~1~and~79~mul~32~add~exch~2~idiv~3~1~roll~s~exch~2~!dex~exch~p ut~1~sub~dup~6~eq{1~sub}if}repeat~s~=~pop ~pop}forall~=~quit
"]+R}}"]]})*3;echo" ^x89PNG^r^n^x1a^n";$m="";$t="^xc0^0^xff";for($i=-1;++$i<128*$z;$m.=$c--?($w- $c||$i>$z)&&$i/$z<($c<$w?ord($s[(!t)( $c/3)]):$c--%3+2)?
$t[2].$t[$c%3%2].$ t[$c%3]:"^0^0^0":"^0")$c=$i%$z;foreach(array("I`x48DR".pack("NNCV",$w+2,128,8,2 ),"IDAT".gzcompress($m),"IEND")as$ d)echo~pack("NA*N
",strlen($d)-4,$d, crc32($d));).K(B,"`x7f"),?']}';s:g/^x7f/Y/;Z~$_",128..287];s="$_='#{Q[s,c=/['Y]/ ]}';$n=32;$s='#{Q[v,c]}';$s=`x7 es{..}{$a=$&;$b=c
hr(--$n&255);`x7e s/$b/$a/g;}eg;Z";(s+N*(-s.size%6)).unpack("B*")[0].K(/.{6}/){n=$&.to_i~2;((n+14)/2 6*6+n+47).chr}}";s|.|$n=ord $&;substr~unpack(
B8,chr$n-!t($n/32 )*6-41),2|eg;eval~pack'B*',$_).scan(/[~,-:A-z]+|(.)/){p="s++#{$1?"chr~#{$1.ord}+e": $&+?+};"+p};p),1){"'#$s' ,"}}'')end.".K(/[:
;()]/){?`x5e+$&}} ]"]};quit"]};t=num2cell(b=11-ceil(s/13));for~n=1:9m={};for~i=1:141f=@(x,y,n)repmat ( ['Ook'~char(x)~'~Ook' ~char(y)~'~'],[1~a
bs(n)]);m(i)=[f(z =46,63,n)~f(q=z-(i<13)*13,q,i-13)~f(33,z,1)~f(63,z,n)];end;t(x)=m(diff([0~s(x=b= =n )])+13);en d;Zf ('%%s',t{:})"]]+R} }"]]}`n"]};return~
0;}~})]};"]}`x60` n~global~_start`n~_start:mov~edx,#{s.size}`n~mov~ecx,m`n~mov~ebx,1`n~mov~eax,4` n ~!t~128`n~mov ~ebx,0`n~mo v~eax,1`n~!t~12 8`nx:~|`n~}}{{{qr}}
}"]}"call~void~[ms corlib]#{C*"::"}(sJ)ret})]}];"]};quit();",?$].K(?'){"'^''"}}'"}@>)`np"],?&,?& ] },'&(%d+)&',fu nction(s)retur n~sJ. rep('Y',tonu mber(s))end);Z(x)".
K(/[:"]/,":^0")}"` n`x4bT`x48`x58B`x59E~B`x59E)).size+1}x~i8]c"#{s.K(/[^"`n`t]/){"^%02`x58"%$ &. ord}}^00"declare~i32@puts(i8*)d ef!e~i32@mX{ %1=call~i 32@puts(i8*getelemen
tptr([#{i}x~i8],[#{ i}x~i8]*@s,i32~0,i32~0))ret~i32~0})],?#]]]})];");"],"^n")];[for~i=0:2:4; x=(( Int(c)%83-10)>>i)%4+1;A("ski`x60 "[x:x])end~for~c ~!"AG- `x48-`x48Fy.IlD==;=jd
lAy=;=jldltldltl{lAu lAy=jtlldlAyFy=?=jdlAyGFyFyG2AFy>zlAFFBCjldGyGFy>GFy.AGy=G==n`x48==nl ldC=j@=j tlldltldlAut11"];A("'"))]})A+="' +`x21[]+'"+G.charCo deA t(E).toSJ(16);for(A+="
^".replace(/'+`x21[] +'/g,^"%^")))')()",R=0;R<9;R++)A=A.replace(/'.*?'/g,function(B){T= [];for(E=1 ;B[E+1];)T.push(P[B[E++]]);return~T.jo!('+')});conso l e.log('"'+A+'"'))).byte
s{|n|r,z=z[n]||(b[r/7 8];b[r];q<6083&&z[n]=[q+=1,[]];t[n])};b[r/78];b[r]}";!t~i=0,n=0 ,q=0;for(;++n< 126;)c[n]=""+(char)n;for(;i<#{a.size};){q=q*78+(s .charAt(i)-13)%84;if(i++
%2>0){y=q<n?c[q]:y;c[n ++]=z+y.charAt(0);System.out.Z(z=c[q]);q=0;}}}})]}"`n!vokevi rtual~#$T/Zln(L#{S }J;)V`nreturn`n.end~method)+N]};H("DO,1<-#"|| *s);s?while~t:=ord(move(1)
)do{i+:=1;u:=-i;every~0t o~7do{u:=u*2+t%2;t/:=2};H("PLEASE")^(i%4/3);H("DO,1SUB# "||i||"<-#"||((c-u)%2 56));c:=u;};H("PLEASEREADOUT,1^nPLEASEG IVEUP");end)]};}}"].tr(?"+B
,"`x21`x7e")}'.tr('`x7e`x 21','YY^u0022')as~byte[]);z.close()"`n)]}"{"W""w"@j ~1+:j^-~118%1+*}%"/35512 416612G61913@921/17A331513"t'") ;fim')]};})],61){"Zn#$S`n"},?
%]]}"`nquit)]});CloseStream (s);QUIT;"]}")]}"~DUP~A~."~DO~10~I=1,"~.~CR~S "~&A,&"~C~."~10~~~~~~CONTINU E"~CR~S^"~&A)^",&" ~C~0~DO~B~."~&char("~COUNT~.~."
~),&'"~CR~LOOP~S^"~&^"^""~C~S "~end~#$D"~C~A~."~STOP"~CR~A~."~END"~CR ~B`x59E~;~D~),B],?`x21].K(?',%('"' "'))}'"]};}".K(?"){'"34,"'}.K(N){
'"10,"'}+?",?%]+'~""")'],?`x7e] }."]}"))],15){"f(#{V[$S[1..-2] ,'",',');f("']},0);"}}}})}]pq"]}");})} `x60);}"]}"))].K(?`x60,"Yx60"),'#{f
(',')}']})"]}"))["~~~~^"~^".""STO P~RUN."])](Zln( str"message(STATUS~^"~~~~~"(.replace(.replac e(str~s)"Y""YY")"^"""Y^"")"^")")))).re
verse]})#$C($"Put~caffe!e~{(!t)c}~!t o#$F.^n");#$C("Liquify#$G.^nPour#$G~!to~the~bak!g~ dish.^n^nServes~1.^n");}})]};}/****//****
/";t={};b="";L="";n=i=0;D=->n{L<<(n+62) %92+35;D};s.bytes{|c|n>0?n-=1:(t[c]=(t[c]||[]).reject{|j| j<i-3560};x=[];t[c].map{|j|k=(0..90).f!d{|k|n
ot~s[i+1+k]==s[j+k]}||91;k>4&&x<<[k,j]};x=x. max)?(n,j=x;x=b.size;(u=[x,3999].m!;D[u%87][u/87];L<<b[0,u];b[0,u ]="";x-=u)while~x>0;x=4001+i-j;D[x%87][x/87][n-5]
):b<<c;t[c]+=[i+=1]};"#!clude<stdio.h>`nchar*p=#{E [L]},s[999999],*q=s;!t~mX{!t~n,m;for(;*p;){n=(*p-5)%92+(p[1]-5)%92*87;p+=2;if(n >3999)for(m=(*p++-5)%92+6;m--;q++)*q=q[4000-n];else~for(
;n--;)*q++=*p++;}puts(s)#{R}}")]}){s+="00g,";for(m=1;m<256;m*=2)s+="00g,4,:"+(c/m%2>0?"4+":"")+",";f(s);s="4,:,";}f(s+s);for(c:Base64.getDecoder().decode("kaARERE`x58/I0ALn3n5ef6l/Pz8+fnz58/BOf5/7/hE`x58/O`x5azM5mC`x58/Oczm`x5azBPn5+`x
58/OczMznBL/nM5m`x5azBPu++fPPOc5zngnnO`x5azO`x5agnBMGAW7A==")){c=c<0?256+c:c;for(i=0;i++<3;c/=8)f(c%8);f("8*+8*+,");}f("@");).K(?',%('"'"'))}'|sed~-e's/Y/YY/g'~-e's/"/Yq/g'~-e's/.*/Z~"&"^nquit/')]}}"]],?']}');".K(B,?`x5e)]}.replace("`x
5e","Y"));}})]]};}";FORiTO`~UPBtDO`~INTn:=ABSt[i];Z(~(50+n%64)+c+~(50+n%8MOD8)+c+~(50+nMOD8)+b+"`x4a"+a)OD]*"REPR"]}"`ntrans~c~0`ndo{D(Integer(S:get~c))`nf~35~39}(<(c:++)(S:length))`nf~24~149)].K(N,'"&Character'+?'+'Val(10)&"')}");end;
)]+"`nsys.exit~0",B],?']}'",/[^{}]/]}}",35){y<<",`n"+$S;"%s"}}")+y],'",','):f("']}",0))}]]></#{U}></xsl:#{I}>"].K~N,'"&~VbLf~&"'}":s="~~~":For~i=0To~7:s~&=Chr(32-(Asc(c)>>7-i~And~1)*23):Next:#$C(s~&n~&Chr(9)&n~&"~~"):Next:#$C(n~&n~&n):
End~Sub:End~Module)]}`nput=s`nZ`nqa`x21",3){%($H("%s",#$S);)+N}}end~endmodule)],?%]+R}}"]},i=0,t='k';while(s[i])t='^x60.'+s[i++]+t;console.log(t)",B],?`x21].K(?',%('"'"'))}'"^n::=^na")],/[`[`]$]/]}")]};Z"0~0~-1";)],?']}';cr",127..255];
f(%(variable~s=`x60#{s.K(/.{1,234}/){$&.K("`x60",%(`x60+"`x60"+`x60))+"`x60+`n`x60"}}`x60,i;for(i=0;i<129;i++)s=strreplace(s,pack("C",255-i),substrbytes(`x60#{v[0,99]}`x60+`n`x60#{v[99..-1]}`x60,i*2+1,2));Zf("%s",s)),7){"f('%s')`n"%$s.
unpack("`x48*")}}Zf("^n#[Exeunt]");quit)]}")),196){%(Z#$S;)}}}"]});})).gsub(/[!HJKXYZ^`~]/){[B*2,:write,B,:tring,:gsub,"ain()",B*4,:print,g,:in][$&.ord%47%12]})))*"")#_buffer_for_future_bug_fixes_#_buffer_for_future_bug_fixes_#_buffer_
############################################################################## Quine Relay -- Copyright (c) 2013, 2014 Yusuke Endoh (@mametter), @hirekoke #############################################################################)
Quine-relay
• A Ruby code
• that generates Rust code
• that generates Scala code
• …
• that generates REXX code
• that generates the original Ruby code
128 languages
involved
in total
Quine-relay
• A Ruby code
• that generates Rust code
• that generates Scala code
• …
• that generates REXX code
• that generates the original Ruby code
128 languages
involved
in total
Merry Quine-mas
https://youtu.be/r0eaf9iLKxg
Merry Quine-mas
https://youtu.be/6xALa5RiKUE
14
15
mquine.rb
16
eval(_=%[b='DEILMQTVY';eval((%[a=(-1)EE0.5;f=->EfVf.each_slice(2)Y;c=->wVz=->dVd.mapVd=d.rotate(1)YY
;Q=->k,l,mV((m-k)E(l-k).conT).arQ<0Y;y=[];x=0.99;o,T=w.partitionV|n|d=0;z[n].mapV|k,l|y<<f[k,x,k,1,l
,1,l,x];d+=k.conTElY;d.arQ<0Y;f[o,T,[[0,d=2IEa,d+15,15]],o.map(Dd=:reverse),T.map(Dd),[]].mapV|o,T|T
.mapV|h|z[h].max_byV|u,|u.realY;Y.sort_byV|i,|-i.realY.mapV|h|i,=h;v=0;o.mapV|n|z[n].mapV|x|m,l,E,k=
x;e=(i-m).arQEE2;v<eDD(d=Q[k,m,l])^(Q[k,m,i]^d|(Q[m,l,i]^d))DDo.allMV|n|z[n].allMV|k,l|[i,m,k,l].uni
q.size<4||Q[i,k,l]==Q[m,k,l]||Q[i,m,k]==Q[i,m,l]YYDD(v=e;w=n;T=Ex,m,Eh,i)YY;w[0..-1]=TY;o.mapV|v|t,=
s=z[v];n=->rVk,m,l=r;k=k[2],l,m[2];r[I]=Q[Ek]DDv.allMV|q|z[k].anyMV|k,l|q==k||Q[k,q,l]YYY;z[s].mapV|
k,l,m|l[0,2]=k,m;n[l]Y;(s[I..-1].mapVt=t[1]until(t[I]);k,m=l=t;m[0],k[1]=t;n[m];n[t=k];lY<<t).mapV|k
,m,l|y<<f[k[2],x,l,x,m[2],x]YY;x=1Y;yY;e=0;%[`^Tx52t<^cd,7/w(kabvbEz5arIwIa17.=c'slxr=-'4|e)EwkMI,_^
pvMVhsnME.rLw_k)^tp>+TIEduE45u>mv%^Y=Vny-`zce)k`heIt%`Vzf;c2nk4d|Vp^D_,,|kDDL2r_sDy%%fiMV6cYE)5`,m/k
YQ/;IEezMVv,QchILY|p%%i<vstDt)=M7vLcT>=4Q2(vwael61//<ck>-l67uQ;2Tq,c_'qEIcm1cL;i++2-tYdbenq%pxr;2'Vn
(uDa)n)zf4w)%5vh;ssV5kI;)z;2=+Toe<VL_D0`VLu;ook_y+eT`>IeT9-(i<MiVdd)ib_y+x`s^_u>M1s/mYQvEY`vMxu%Y0u5
7Qaoh2<Mkd'vtkp^zTc`E->Ep+icop_u0%=-zv,omq`Qz/41DV'`f9L5`M'bVxx%/;qLtq12%q:V'9,fD,ovu%qr|+e+rudI`Ir0
5chVd+Q5`II76rY0laT%b(I>Y%EQ1xf^|r,1)%4--zQa'<qxL-7Y0+|'vvbIxso0usv;%.I:pLQbe5a),Vu|91(0EIv^T>c5Dmd:
9-I15%Lp/>>z57^,Th2>%la0;5`dE1<xvrd09^9zz<.t,LpofrTTsQi'u5;Lwp7+zmm`'>qy;f6)||Ikw_0wdMM5<hmn64wbQ_rD
m'>so7b..4qy`nQrz%Vf7Ii^epY(x=|49Lh(=>sI_sbofb7|qM,unaD%^i:|;_tEEnb-DDt`t%I2h;0x5f^yhs,pbLf+m^e>yqzQ
'%::|^=,5-b=^_1x1se`kp,%wq4T%;'E.:Dsp_V-0||,)=;.a|<%0QY:;t:fEmk:4|_%o-.:aooq/6mThdvz4`uQqY1r'em.5'z1
2p7e%%pp6ebMM,m`5QpYx'd`,`6a4T)6Q.k.E.YsdiE^ox9pyrsr%|(kfn=y9q`6;=V<z%9(0cf^yp=:Irw-c/y>%iie%)y-1i(y
'V-n^uTva%l0Q>,yz;E0:LbV'eTb6MIb``Da.__ihbacxY|fc6>pTtl;ivVt,q>/%w,=hnI+i90>10u59te,Ildw4p94x`iwvs`f
+^)w1M>%wf^].bytesV|i|e=eE59+(i-5)%L9Y;Q=->iVk=e%i;e/=i;kY;d=VI2=>c[[]]Y;54.upto(1I0)V|h|d[h%L9+I7]=
c[(0..Q[5]).mapVl=o=T=[];n=0;(-2..Q[17]).mapV[l=Q[2],o=Q[1I]+Q[21]Ea+1+a]Y.flat_mapV|m,n|E,(h,)=[[o,
l],[(o+o=n)/2,0]][0..lDl=m]Y.mapV|o,l|n=l<1M((n==0ML:1).upto(L)V|k|T<<h+kE(n-h)/4+kEkE(o-2En+h)/64Y;
h=o;0):oY;TY]Y;n=[];m=0;v=aEE0.04;z=15/v.arQ;w=-0.2I;h='eval(_=%['+_+'])';h.tr(b,']+b+%[').bytesV|o|
q=-w+s=wEm+=1;r=vEp=vEEmEz;d[o].mapV|v|n<<v.mapV|v,l|T,k=v.rect;[(p+(r-p)ET/=15)El,q+wET-k]YY;m<101D
Dn+=[f[p,q,r,s,E[r,0]E(m/100),r,2,p,2],f[p,2,r,2,k=rET=0.976,2,TE=p,2],f[T,2,k,2,k,x=-715,T,x],f[T,x
,k,x,r,x,p,x],f[p,x,r,x,r,s-l=690,p,q-l,E[p,x+2]E(1/m)]];Y;T=VY;k=VY;l=''<<I2;m=n.mapV|i|(p,q),(r,s)
,(t,u)=Ei;p-=r;r-=t;Mf+l+i.mapV|m|[[T,:v,Em],[k,:vn,(rE(q-s)-pE(s-u))Ea,(p.conTEr).imaQ]].mapV|T,o,p
,w|T[[o,E(p.rect<<w).mapV|p|(pE500).round/z/10Y]El]||=T.size+1YE'//'YElY;o=''<<I5;puts(%(Q%squine')%
l,o+%V'+(eval(%[Y+h+%V]);exit);'Y,T.keys,k.keys,m,o+M');]).tr(b,'%)27>fiz|'.tr('x%-|','%-'<<125)));'
[[[ Monumental Quine (c) 2015 Yusuke Endoh -- tested with ruby 2.2.1 -- built on 2015/04/01 ]]]'])
実行
17
$ ruby mquine.rb > mquine.obj
mquine.rb: Monumental Quine
自己言及的記念碑
自分自身の作り方を Ruby プログラムとして刻んだ円柱
※Quine:自分自身を出力するプログラムのこと
18
Ruby実行
3Dプリント
rquine.rb : 宇宙線耐性 Quine
19
eval=eval=eval='eval$s=%q(eval(%w(puts((%q(eval=ev
al=eval=^Z^##^_/#{eval@eval@if@eval)+?@*10+%(.size
>#{(s=%(eval$s=%q(#$s)#)).size-1}}}#LMNOPQRS_##thx
.flagitious!## )+?@*12+%(TUVW XY/.i@rescue##
/_3141592653 589793+)+?@* 16+%(+271828
182845904; _987654321 0;;eval)+?
@*18+%("x =((#{s.s um}-eval.
_sum)%256 ).chr; ;eval)+?@
*12+%(.s can(//){ a=$`+x+$
^_a.unpa ck (^ H*^)[0].
hex%999989==#{s.unpac k("H*")[0].hex%999989
}&&eval(a)}#"##"_eval @eval####@(C)@Copyrig
ht@2014@Yusuke@Endoh@# ###)).tr("@_^",32.chr<
<10<<39).sub(?Z,s));e xit#AB CDEFGHIJK)*%()))#'##'
/#{eval eval if eval .size>692}}#LMNOPQRS
##thx.flagitious!## TUVWXY/.i rescue##/
3141592653589793+ +271828182845904;
9876543210;;eval "x=((42737-eval.
sum)%256).chr;;eval .scan(//){a=$`+x+$'
a.unpack('H*')[0].hex%999989==68042&&eval(a)}#"##"
eval eval#### (C) Copyright 2014 Yusuke Endoh ####
実行 (1)
20
$ ruby rquine.rb > rquine2.rb
$ diff -s rquine.rb rquine2.rb
ファイル rquine.rb と rquine2.rb は同一です
broken.rb (適当に1文字消した)
21
val=eval=eval='eval$s=%q(eval(%w(puts((%q(eval=ev
al=eval=^Z^##^_/#{eval@eval@if@eval)+?@*10+%(.size
>#{(s=%(eval$s=%q(#$s)#)).size-1}}}#LMNOPQRS_##thx
.flagitious!## )+?@*12+%(TUVW XY/.i@rescue##
/_3141592653 589793+)+?@* 16+%(+271828
182845904; _987654321 0;;eval)+?
@*18+%("x =((#{s.s um}-eval.
_sum)%256 ).chr; ;eval)+?@
*12+%(.s can(//){ a=$`+x+$
^_a.unpa ck (^ H*^)[0].
hex%999989==#{s.unpac k("H*")[0].hex%999989
}&&eval(a)}#"##"_eval @eval####@(C)@Copyrig
ht@2014@Yusuke@Endoh@# ###)).tr("@_^",32.chr<
<10<<39).sub(?Z,s));e xit#AB CDEFGHIJK)*%()))#'##'
/#{eval eval if eval .size>692}}#LMNOPQRS
##thx.flagitious!## TUVWXY/.i rescue##/
3141592653589793+ +271828182845904;
9876543210;;eval "x=((42737-eval.
sum)%256).chr;;eval .scan(//){a=$`+x+$'
a.unpack('H*')[0].hex%999989==68042&&eval(a)}#"##"
eval eval#### (C) Copyright 2014 Yusuke Endoh ####
e
実行 (2)
22
$ ruby broken.rb > rquine2.rb
$ diff rquine.rb rquine2.rb
ファイル rquine.rb と rquine2.rb は同一です
どの 1 文字を消しても元に戻ります
壊れているのに元のプログラムを出力した!
講義の流れ
• 超絶技巧プログラムの紹介
• 超絶技巧プログラミング入門
• 超絶技巧プログラム事例解説
ここで 40 分くらい?
今日紹介するテクニック
• プログラムのアスキーアート化
• ターミナルでアニメ
• Quine
• その他のテクニック
プログラムのアスキーアート化
• 好きなプログラムを書く
– 空白は使わない
– 改行も使わない
– ¥ も使わない
• おまじないで囲む
p 42 p(42)
p(1)
p(2)
p(1);p(2)
puts("¥¥") puts(92.chr)
eval(%w( puts("Hello,world!") ).join)
この範囲を自由に整形可能
プログラムのアスキーアート化
• 好きなプログラムを書く
– 空白は使わない
– 改行も使わない
– ¥ も使わない
• おまじないで囲む
p 42 p(42)
p(1)
p(2)
p(1);p(2)
puts("¥¥") puts(92.chr)
eval(%w( puts("Hello,world!") ).join)
この範囲を自由に整形可能
eval(%w( p u
t s ( " H
e l l o ,
w o r l d
! " ) ).join)
解説
• %w(foo bar) は
文字列の配列 ["foo", "bar"] を返す
• Array#join は文字列を結合して返す
– 空白や改行が取り除かれる
• eval は文字列を Ruby コードとして実行する
eval(%w( p ( 1 ) ).join) #=> 1 が出力される
%w( p ( 1 ) ).join #=> "p(1)"
%w( p ( 1 ) ) #=> ["p","(","1",")"]
実習(10分)
• 自己紹介を出力するプログラムを
イニシャル形状にしてみましょう
– 元プログラム↓
– 余分は # や ; などで埋める
– 自己紹介やイニシャルではなく、好きなメッセージや
形状でも構いません
eval(%w(
puts("Yusuke-Endoh,hobby:walking")
).join)
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)
実習(発展問題)
• ¥ を含めるとどのような問題が起きるか、
実際に試して調べてみましょう
• これ↑はなぜ動かない?
• 発展:¥ の避け方を考えてみましょう
puts("foo¥nbar")
p("foo1bar2baz".gsub(/¥d/, ","))
p("foobar foo bar".gsub(/¥bfoo¥b/, "FOO"))
eval(%w(puts("¥¥")).join)
発展問題の解答例
• ¥ は %w(…) がエスケープとして消費する
– %w(puts("¥¥")).join は puts("¥") になる
– 宿題:%w(puts("¥¥¥¥")).joinにすればOK?
• "foo¥nbar" は "foo#{ 10.chr }bar" と
書き換えられる
– 各文字には、対応する数字(codepoint)がある
• 調べ方→
– 他の書き換えは宿題 p "¥n".ord #=> 10
p 10.chr #=> "¥n"
ここで 1 時間くらい?
ターミナルで色
• エスケープシーケンスを print することで
ターミナルを制御できる
– 色を変えたり、カーソルを移動したり
• "¥e[数字m" で色を変えられる
– 色以外にもいろんな属性がある
(ANSI エスケープシーケンスで検索)
puts "¥e[34mfoo¥e[0m" #=> foo(青字)
puts "¥e[44mfoo¥e[0m" #=> foo(青地)
30黒 31赤 32緑 33黄 34青 35紫 36水 37白
40黒 41赤 42緑 43黄 44青 45紫 46水 47白
ターミナルでアニメ
• アニメの基本:繰り返し端末に print する
– アスキーアートを見せる→少し待つ
→アスキーアートを見せる→少し待つ→…の繰り返し
– print と sleep を繰り返すだけでも良いが
エスケープシーケンスを使うとより見やすくなる
• アニメに役立つエスケープシーケンス
– "¥e[H" でカーソルをホームに移動
– "¥e[J" で画面の文字を全消去
• 正確には、カーソル位置より後にある文字を消去
アニメの例
• 最初にターミナルをクリアする
• ホームに戻って puts
– を繰り返す
– ポイント:画面のクリアは最初だけ
(毎回やるとちらつく)
print "¥e[H¥e[J"
loop do
print "¥e[H"
puts "<--+"
puts " |"
puts " "
sleep 0.5
print "¥e[H"
puts "+-- "
puts "| "
puts "V "
sleep 0.5
print "¥e[H"
puts " "
puts "| "
puts "+-->"
sleep 0.5
print "¥e[H"
puts " ^"
puts " |"
puts " --+"
sleep 0.5
end
<--+
|
+--
|
V
|
+-->
^
|
--+
実習(10分)
• 波々なアニメプログラムを書いてみましょう
– 土台→
• 波に色を
つけて
みましょう
• 発展:このプログラムをアスキーアート化してみましょう
– ヒント:"¥e" を避ける必要がある
W, H = 60, 20
def print_sine_curve(phase)
s = (0..H).map { " " * W }
W.times do |x|
y = Math.sin((phase+x)/W.to_f*2*Math::PI)
s[((y + 1) * H / 2).round][x] = "o"
end
puts s.join("¥n")
end
print_sine_curve(0) # <= ここの数字を変えてみる
解答例
• 波々アニメプログラム→
• 波に色をつける↓
• 発展問題は宿題("¥e" は 27.chr)
phase = 0.0
print "¥e[H¥e[J"
loop do
print "¥e[H"
print_sine_curve(phase)
phase += 1.5
sleep 0.1
end
def print_sine_curve(phase)
s = (0..H).map { " " * W }
(W - 1).downto(0) do |x| # x を逆順に回す
y = Math.sin((phase+x)/W.to_f*2*Math::PI)
s[((y + 1) * H / 2).round][x] = "¥e[41mo¥e[0m"
end
puts s.join("¥n")
end
Quine
• 自分自身を出力するプログラム
– Quine の名前の由来:間接自己言及を発見した
哲学者 Willard Van Orman Quine
# Quine を実行して、出力を別ファイルに保存する
$ ruby quine.rb > quine2.rb
# 出力と元プログラムを比較する
$ diff –s quine.rb quine2.rb
ファイル quine.rb と quine2.rb は同一です
よくある失敗
• 「何かを出力するプログラム」からQuineを目指す
• 終わりがない
puts "..."
puts "puts ¥"...¥""
puts "puts ¥"puts ¥¥¥"...¥¥¥"¥""
うまくいく方針
• 出力文字列を変数に代入しておく
• 埋め込みをプログラムにやらせる
s="..."; puts s
s="s=¥"…¥"; puts s"; puts s
s = s.sub("…", s)
うまくいく方針
• まとめると
• 出力結果
– ほぼ一致、¥ がないだけ
s="s=¥"...¥"; s=s.sub(¥"...¥"); puts s";
s=s.sub("...", s); puts s
s="s="..."; s=s.sub("..."); puts s";
s=s.sub("..."); puts s
※紙面の都合で改行を入れています
¥ の対処方法
• ¥ を使わずに書く
– ¥ が必要な理由は、 "…" の中に " を入れるため
– ならば、" を使わなければよい
• %[…] という文字列リテラルを使う
– ¥ なしで区切り文字自身を含められるのがポイント
%[foo bar] #=> "foo bar"
%[foo [bar] baz] #=> "foo [bar] baz"
動作する Quine
• 書き直したプログラム
• 出力結果
– 完全一致!
s=%[s=%[…]; s=s.sub(%[…], s); puts s];
s=s.sub(%[…], s); puts s
s=%[s=%[…]; s=s.sub(%[…], s); puts s];
s=s.sub(%[…], s); puts s
実習(15 分)
• Quine を入力して実際に動かしてみましょう
• もう少し短い Quine にしてみましょう
– s=s.sub(%[…], s); puts s をまとめて
puts s.sub(%[…], s) とするとか
– 全部の "…" を %[…] に置き換えましたが、一部は
"…" のままにできます
• 発展:¥ から逃げずにQuineを書いてみましょう
– ヒント:s の中の " をすべて ¥" に置換すればよい
解答
• 短くする
– 文字列の中と外で 2 回変更することがポイント
• 発展問題のヒント:???? を埋める
– ¥ を置換するからと言って ¥ を使うとハマるので…
s=%[s=%[…];puts s.sub("…",s)];
puts s.sub("…",s)
s="s=¥"…¥";
puts s.sub(¥"…¥", s).gsub(????){????}";
puts s.sub("…", s).gsub(????){????}
もっとかんたんな Quine
• いちいち 2 箇所変えないと行けないのはダルい
 eval を使えばもっとシンプルに書ける
• 動作の仕組みを実習時間に考えてみてください
– ポイント:%[…] と %q[…] の違い
eval(s=%q[puts %[eval(s=%q[#{ s }])]])
%[...#{ 42 }...] #=> "...42..."
%q[...#{ 42 }...] #=> "...#{ 42 }..."
ここで 1 時間 40 分くらい?
その他のテクニック
• 画像・動画生成
– 頑張ってデータを生成して出力する
– 書籍の8.3節を参照のこと
• サウンド
– 音声の波形データを生成して、どうにか再生する
– 書籍の8.2節を参照のこと
• プログラムの短縮
– 次ページ以降で解説
コードゴルフ
• プログラムの短さで競う競技
– "Anarchy golf" で検索
• 超絶技巧プログラミングは短さを競うわけではな
いが、同じ挙動なら短いほうが大体エレガント
– TRICK 等のサイズ制限を抜けるために必要なことも
• 今回はRubyに特化した細かいテクニックではなく、
データの圧縮アルゴリズムを紹介します
超絶技巧プログラミングと圧縮
• 超絶技巧プログラムにデータを持たせたいケース
– 形状データ、フォントデータ、楽譜データ、etc.
• 基本的なアプローチ
– 元データと圧縮コードを書いて圧縮データを作る
– 圧縮データと展開コードを最終的なプログラムに入れ
る
• 圧縮データは(通常は)文字列として埋め込む
• 展開コードは Ruby で書いて埋め込む
• 圧縮コードは最終的なプログラムに埋め込む必要がない
トレードオフ
• 単純な圧縮・展開アルゴリズム
– 圧縮データは長い(低圧縮率)
– 展開コードは短い
• 頭のいい圧縮・展開アルゴリズム
– 圧縮データは短い(高圧縮率)
– 展開コードは長い
• なんとなくの目安
– データが30バイト程度なら無圧縮
– 100 バイト程度なら 36 進数
– 1000 バイト程度なら Byte-pair Encoding
36進数の例
● 元データ (横 3 × 縦 5 × 文字数 11 = 165 バイト)
● 空白を 0 、# を 1 にして二進数に
● 10 進表示に (50 バイト)
– 1073733623, 2905756245, 1063256021, 2371130133, 1063231487
● to_s(36)で36進数にすればさらに小さく(35バイト)
– 0hr9u5z, 1c20fv9, 0hl19lh, 137pjpx, 0hl0qnz
### ## ### ### # # ### ### ### ### ###
# # # # # # # # # # # # # #
# # # ### ### ### ### ### # ### ###
# # # # # # # # # # # # #
### ### ### ### # ### ### # ### ###
111 110 111 111 101 111 111 111 111 111
101 010 001 001 101 100 100 001 101 101
101 010 111 111 111 111 111 010 111 111
101 010 100 001 001 001 101 010 101 001
111 111 111 111 001 111 111 010 111 111
BPE (Byte-pair Encoding) (1)
• 繰り返しの多いデータで効く単純な圧縮
• 圧縮方法
– 元データのうち出現頻度の高い 2 連続文字を見つける
• "0000100000100001" の場合、"00" の出現頻度が最大
– その 2 連続文字を、未使用文字に置き換える
• "0000100000100001"  "2212201221"
– 利用した文字と 2 連続文字を先頭にくっつけておく
• "2" + "00" + "2212201221"`
– これを繰り返す
• "2002212201221"  "3"+"22"+"2003130131"`
BPE (Byte-pair Encoding) (2)
• 展開方法
– 圧縮データ "3222003130131"
– 先頭文字と続く 2 文字を取り出す
• "3" と "22"
– "3" を "22" に置換する
• "2003130131".gsub("3", "22")
#=> "2002212201221"`
– これを繰り返す
• "2212201221".gsub("2", "00")
#=> "0000100000100001"`
さまざまな圧縮アルゴリズム
• 超絶技巧プログラミングでは
BPE のコストパフォーマンスが最強な場合が多い
– 簡単、簡単な割に高圧縮、展開コードも短い、形
状・フォントデータ(繰り返しが多い)と相性がよい
• 圧縮アルゴリズムは他にも色々あります
– 定番はランレングス
– LZ77、LZ78、Range Coder 、算術符号など
• GIF 生成では LZ78 の亜種 LZW の知識があるとよい
– 興味がある人は調べて見てください
講義の流れ
• 超絶技巧プログラムの紹介
• 超絶技巧プログラミング入門
• 超絶技巧プログラム事例解説
Quine-relay の解説
• 理論的には、Ruby の Quine そのもの
– 自分自身をそのまま出力するのではなく、
その文字列を出力する別言語プログラム、
にラップして出力する
– このラッピングを 100+ 言語分繰り返すだけ
– 午後の実習ネタにあるので、考えてみてください
Merry Quine-mas の解説
• 本質的には Ruby の Quine そのもの
– 自分自身をそのまま出力する前に、
アニメーションと音楽演奏を行う
– アニメーションの方法はまさに講義で説明した通り
– コードを 80x25 = 2000 文字に収めるのは
種々の圧縮テクニックが必要(収めなくてもよいけど)
Monumental Quine の解説
– mquine.rb
– 縁遠かった技術や、ふつうには出会わない制約を
体験できる
56
eval(_=%[b='DEILMQTVY';eval((%[a=(-1)EE0.5;f=->EfVf.each_slice(2)Y;c=->wVz=->dVd.mapVd=d.rotate(1)YY
;Q=->k,l,mV((m-k)E(l-k).conT).arQ<0Y;y=[];x=0.99;o,T=w.partitionV|n|d=0;z[n].mapV|k,l|y<<f[k,x,k,1,l
,1,l,x];d+=k.conTElY;d.arQ<0Y;f[o,T,[[0,d=2IEa,d+15,15]],o.map(Dd=:reverse),T.map(Dd),[]].mapV|o,T|T
.mapV|h|z[h].max_byV|u,|u.realY;Y.sort_byV|i,|-i.realY.mapV|h|i,=h;v=0;o.mapV|n|z[n].mapV|x|m,l,E,k=
x;e=(i-m).arQEE2;v<eDD(d=Q[k,m,l])^(Q[k,m,i]^d|(Q[m,l,i]^d))DDo.allMV|n|z[n].allMV|k,l|[i,m,k,l].uni
q.size<4||Q[i,k,l]==Q[m,k,l]||Q[i,m,k]==Q[i,m,l]YYDD(v=e;w=n;T=Ex,m,Eh,i)YY;w[0..-1]=TY;o.mapV|v|t,=
s=z[v];n=->rVk,m,l=r;k=k[2],l,m[2];r[I]=Q[Ek]DDv.allMV|q|z[k].anyMV|k,l|q==k||Q[k,q,l]YYY;z[s].mapV|
k,l,m|l[0,2]=k,m;n[l]Y;(s[I..-1].mapVt=t[1]until(t[I]);k,m=l=t;m[0],k[1]=t;n[m];n[t=k];lY<<t).mapV|k
,m,l|y<<f[k[2],x,l,x,m[2],x]YY;x=1Y;yY;e=0;%[`^Tx52t<^cd,7/w(kabvbEz5arIwIa17.=c'slxr=-'4|e)EwkMI,_^
pvMVhsnME.rLw_k)^tp>+TIEduE45u>mv%^Y=Vny-`zce)k`heIt%`Vzf;c2nk4d|Vp^D_,,|kDDL2r_sDy%%fiMV6cYE)5`,m/k
YQ/;IEezMVv,QchILY|p%%i<vstDt)=M7vLcT>=4Q2(vwael61//<ck>-l67uQ;2Tq,c_'qEIcm1cL;i++2-tYdbenq%pxr;2'Vn
(uDa)n)zf4w)%5vh;ssV5kI;)z;2=+Toe<VL_D0`VLu;ook_y+eT`>IeT9-(i<MiVdd)ib_y+x`s^_u>M1s/mYQvEY`vMxu%Y0u5
7Qaoh2<Mkd'vtkp^zTc`E->Ep+icop_u0%=-zv,omq`Qz/41DV'`f9L5`M'bVxx%/;qLtq12%q:V'9,fD,ovu%qr|+e+rudI`Ir0
5chVd+Q5`II76rY0laT%b(I>Y%EQ1xf^|r,1)%4--zQa'<qxL-7Y0+|'vvbIxso0usv;%.I:pLQbe5a),Vu|91(0EIv^T>c5Dmd:
9-I15%Lp/>>z57^,Th2>%la0;5`dE1<xvrd09^9zz<.t,LpofrTTsQi'u5;Lwp7+zmm`'>qy;f6)||Ikw_0wdMM5<hmn64wbQ_rD
m'>so7b..4qy`nQrz%Vf7Ii^epY(x=|49Lh(=>sI_sbofb7|qM,unaD%^i:|;_tEEnb-DDt`t%I2h;0x5f^yhs,pbLf+m^e>yqzQ
'%::|^=,5-b=^_1x1se`kp,%wq4T%;'E.:Dsp_V-0||,)=;.a|<%0QY:;t:fEmk:4|_%o-.:aooq/6mThdvz4`uQqY1r'em.5'z1
2p7e%%pp6ebMM,m`5QpYx'd`,`6a4T)6Q.k.E.YsdiE^ox9pyrsr%|(kfn=y9q`6;=V<z%9(0cf^yp=:Irw-c/y>%iie%)y-1i(y
'V-n^uTva%l0Q>,yz;E0:LbV'eTb6MIb``Da.__ihbacxY|fc6>pTtl;ivVt,q>/%w,=hnI+i90>10u59te,Ildw4p94x`iwvs`f
+^)w1M>%wf^].bytesV|i|e=eE59+(i-5)%L9Y;Q=->iVk=e%i;e/=i;kY;d=VI2=>c[[]]Y;54.upto(1I0)V|h|d[h%L9+I7]=
c[(0..Q[5]).mapVl=o=T=[];n=0;(-2..Q[17]).mapV[l=Q[2],o=Q[1I]+Q[21]Ea+1+a]Y.flat_mapV|m,n|E,(h,)=[[o,
l],[(o+o=n)/2,0]][0..lDl=m]Y.mapV|o,l|n=l<1M((n==0ML:1).upto(L)V|k|T<<h+kE(n-h)/4+kEkE(o-2En+h)/64Y;
h=o;0):oY;TY]Y;n=[];m=0;v=aEE0.04;z=15/v.arQ;w=-0.2I;h='eval(_=%['+_+'])';h.tr(b,']+b+%[').bytesV|o|
q=-w+s=wEm+=1;r=vEp=vEEmEz;d[o].mapV|v|n<<v.mapV|v,l|T,k=v.rect;[(p+(r-p)ET/=15)El,q+wET-k]YY;m<101D
Dn+=[f[p,q,r,s,E[r,0]E(m/100),r,2,p,2],f[p,2,r,2,k=rET=0.976,2,TE=p,2],f[T,2,k,2,k,x=-715,T,x],f[T,x
,k,x,r,x,p,x],f[p,x,r,x,r,s-l=690,p,q-l,E[p,x+2]E(1/m)]];Y;T=VY;k=VY;l=''<<I2;m=n.mapV|i|(p,q),(r,s)
,(t,u)=Ei;p-=r;r-=t;Mf+l+i.mapV|m|[[T,:v,Em],[k,:vn,(rE(q-s)-pE(s-u))Ea,(p.conTEr).imaQ]].mapV|T,o,p
,w|T[[o,E(p.rect<<w).mapV|p|(pE500).round/z/10Y]El]||=T.size+1YE'//'YElY;o=''<<I5;puts(%(Q%squine')%
l,o+%V'+(eval(%[Y+h+%V]);exit);'Y,T.keys,k.keys,m,o+M');]).tr(b,'%)27>fiz|'.tr('x%-|','%-'<<125)));'
[[[ Monumental Quine (c) 2015 Yusuke Endoh -- tested with ruby 2.2.1 -- built on 2015/04/01 ]]]'])
TrueTypeフォントデータの
テキスト圧縮表現+レンダリング
穴ありポリゴンの凸多角形分割
3Dプリント可能なモデルデータ生成
コードを短くする
(世俗的)インセンティブ
3Dプリンタ代:1行あたり約$15!
複雑な字形を使わない
“3”, “8”, “g” などを一切不使用
放射線耐性 Quine の解説
• 文字列 x と y が一致したとき
どちらも破壊されていない  好きな方を eval すればよい
• 文字列 x と y が異なるとき
長い方は破壊されていない  長い方を eval すればよい
57
x = ”…プログラム…”
y = ”…プログラム…”
eval x if x == y
eval [x, y].max_by {|s| s.size }
次の疑問 :
文字列の外が破壊されたら?
たとえば、ここのダブルクォートが消えたら?
プログラムの宇宙線耐性化 (1)
• Ruby の文法を研究・試行錯誤し、
どの文字を消しても意味が変わらない書き方を
発見した
58
x = ”…プログラム…”
eval=eval=eval=”(プログラム;exit)#”##”
書き直し
プログラムの宇宙線耐性化 (2)
59
eval=eval=eval=”(プログラム;exit)#”##”
eval=eval=eval”(プログラム;exit)#”##”
イコールが削除された
メソッド呼び出しに化ける
(Rubyではメソッド呼び出しの括弧を省略可)
これらの eval はメソッドではなく変数
(Rubyでは同名の変数とメソッドが共存できる)
プログラムの宇宙線耐性化 (3)
eval=eval=eval=”(プログラム;exit)#”##”
eval=eval=eval=(プログラム;exit)#”##”
文字列の中身が普通に実行される
(Rubyでは式と文の区別があまりない)
ダブルクォートが削除された
文字列終端のクォートは
コメント化される
プログラムの宇宙線耐性化 (4)
61
eval=eval=eval=”(プログラム;exit)#”##”
eval=eval=eval=”(プログラム;exit)###”
コメントの中のダブルクォートが新しい文字列終端になる
ダブルクォートが削除された
✓ 他のどの文字が消されても、いい感じに動く
✓ プログラム全体にわたって同じような調整を施した
✓ 詳細は書籍の第 7 章を参照してください
講義はここまで
実習(~16時くらいまで)
• 面白いと思うプログラムを自由に書いてください
– 講義内容を参考してもしなくても
– ネタを思いつかない人は次ページ以降の案を参考に
– 質問は随時どうぞ
• 16 時頃から各自作ったもののデモと説明をして
頂きます
– 改良して TRICK などに応募するかもしれない人は
申し出てください
ネタ案
• 色のついたプログラム
– $ cat prog.rb としたら、一部に色がついている
– $ ruby prog.rb としたら、何か動作する
– ヒント1:puts "Hello" の H を赤くしてみるとか
– ヒント2:プログラムを出力する
プログラムを書くと簡単
• 色のついた Quine
puts <<END
puts "Hello"
END
ネタ案
• 自分自身を難読化して出力する Quine
– 難読化は自由、簡単にはBASE64やROT13
• エンコードの方法
• コマンドラインでデコードする例
• ruby prog.rb | base64 –d で自分自身が出たらOK
require "base64"
puts Base64.encode64("foo") #=> Zm9v
$ echo Zm9v | base64 –d
foo
ネタ案
• 自分自身を出力する Pythonプログラムを出力する
Ruby プログラム
– ruby prog.rb | python で自分自身が出たらOK
– (Python 以外の別言語でもご自由に)
– ヒント1:Python の Hello, world
• つまり、出力を print " と " で囲めばよい
– ヒント2:エスケープ回避が必要
• ¥ を書きたくなったら 92.chr と書く
• 興味があれば 3言語版、4言語版、…も
print "Hello, world!"
ネタ案
• もとに戻らず、変わり続ける Quine 風プログラム
– ヒント:ベース形
• 実行するたびに n=1 の部分が n=2 、n=3 、…と変わっ
ていくようにする
• 3 回実行して元に戻る Quine 風プログラム
– n=1 の部分が n=2 、n=3 、n=1 、n=2 、n=3 、
…と変わっていくようにする
• 実行のたびに色が変わる Quine 風プログラム
– N の値を元に色つけを変える
n=1;eval(s=%q[puts %[n=1;eval(s=%q[#{ s }])]])
ネタ案
• 変な形状の Quine
– こんなのとか 
– アスキーアート化と
うまく組み合わせると良い
#
###
#####
#######
#########
###########
#############
###############
#################
###################
ランダムアイデア
• 行単位で sort しても動くプログラム
– ruby prog.rb でも
– sort prog.rb | ruby – でも動作する
• 有名でないオプションを悪用したプログラム
– ruby –x とか ruby –i とか
• 発想法
– 「○○を Quine にするとどうなるか?」
– 過去の TRICK や IOCCC の入賞エントリを
眺めてみるとアイデアが浮かぶかも
• http://magazine.rubyist.net/?0043-TRICK2013
• http://magazine.rubyist.net/?0053-TRICK2015
• http://ioccc.org/years.html
– (遠藤が超絶技巧をはじめたきっかけも IOCCC の
コードリーディングです)

Contenu connexe

Plus de mametter

error_highlight: User-friendly Error Diagnostics
error_highlight: User-friendly Error Diagnosticserror_highlight: User-friendly Error Diagnostics
error_highlight: User-friendly Error Diagnosticsmametter
 
TRICK 2022 Results
TRICK 2022 ResultsTRICK 2022 Results
TRICK 2022 Resultsmametter
 
クックパッド春の超絶技巧パンまつり 超絶技巧プログラミング編 資料
クックパッド春の超絶技巧パンまつり 超絶技巧プログラミング編 資料クックパッド春の超絶技巧パンまつり 超絶技巧プログラミング編 資料
クックパッド春の超絶技巧パンまつり 超絶技巧プログラミング編 資料mametter
 
Enjoy Ruby Programming in IDE and TypeProf
Enjoy Ruby Programming in IDE and TypeProfEnjoy Ruby Programming in IDE and TypeProf
Enjoy Ruby Programming in IDE and TypeProfmametter
 
TypeProf for IDE: Enrich Development Experience without Annotations
TypeProf for IDE: Enrich Development Experience without AnnotationsTypeProf for IDE: Enrich Development Experience without Annotations
TypeProf for IDE: Enrich Development Experience without Annotationsmametter
 
Ruby 3の型解析に向けた計画
Ruby 3の型解析に向けた計画Ruby 3の型解析に向けた計画
Ruby 3の型解析に向けた計画mametter
 
emruby: ブラウザで動くRuby
emruby: ブラウザで動くRubyemruby: ブラウザで動くRuby
emruby: ブラウザで動くRubymametter
 
Type Profiler: Ambitious Type Inference for Ruby 3
Type Profiler: Ambitious Type Inference for Ruby 3Type Profiler: Ambitious Type Inference for Ruby 3
Type Profiler: Ambitious Type Inference for Ruby 3mametter
 
型プロファイラ:抽象解釈に基づくRuby 3の静的解析
型プロファイラ:抽象解釈に基づくRuby 3の静的解析型プロファイラ:抽象解釈に基づくRuby 3の静的解析
型プロファイラ:抽象解釈に基づくRuby 3の静的解析mametter
 
Ruby 3の型推論やってます
Ruby 3の型推論やってますRuby 3の型推論やってます
Ruby 3の型推論やってますmametter
 
マニアックなRuby 2.7新機能紹介
マニアックなRuby 2.7新機能紹介マニアックなRuby 2.7新機能紹介
マニアックなRuby 2.7新機能紹介mametter
 
A Static Type Analyzer of Untyped Ruby Code for Ruby 3
A Static Type Analyzer of Untyped Ruby Code for Ruby 3A Static Type Analyzer of Untyped Ruby Code for Ruby 3
A Static Type Analyzer of Untyped Ruby Code for Ruby 3mametter
 
A Plan towards Ruby 3 Types
A Plan towards Ruby 3 TypesA Plan towards Ruby 3 Types
A Plan towards Ruby 3 Typesmametter
 
Ruby 3 の型解析に向けた計画
Ruby 3 の型解析に向けた計画Ruby 3 の型解析に向けた計画
Ruby 3 の型解析に向けた計画mametter
 
A Type-level Ruby Interpreter for Testing and Understanding
A Type-level Ruby Interpreter for Testing and UnderstandingA Type-level Ruby Interpreter for Testing and Understanding
A Type-level Ruby Interpreter for Testing and Understandingmametter
 
本番環境で使える実行コード記録機能
本番環境で使える実行コード記録機能本番環境で使える実行コード記録機能
本番環境で使える実行コード記録機能mametter
 
Transcendental Programming in Ruby
Transcendental Programming in RubyTranscendental Programming in Ruby
Transcendental Programming in Rubymametter
 
Cookpad Hackarade #04: Create Your Own Interpreter
Cookpad Hackarade #04: Create Your Own InterpreterCookpad Hackarade #04: Create Your Own Interpreter
Cookpad Hackarade #04: Create Your Own Interpretermametter
 
Ruby 3のキーワード引数について考える
Ruby 3のキーワード引数について考えるRuby 3のキーワード引数について考える
Ruby 3のキーワード引数について考えるmametter
 
TRICK 2018 results
TRICK 2018 resultsTRICK 2018 results
TRICK 2018 resultsmametter
 

Plus de mametter (20)

error_highlight: User-friendly Error Diagnostics
error_highlight: User-friendly Error Diagnosticserror_highlight: User-friendly Error Diagnostics
error_highlight: User-friendly Error Diagnostics
 
TRICK 2022 Results
TRICK 2022 ResultsTRICK 2022 Results
TRICK 2022 Results
 
クックパッド春の超絶技巧パンまつり 超絶技巧プログラミング編 資料
クックパッド春の超絶技巧パンまつり 超絶技巧プログラミング編 資料クックパッド春の超絶技巧パンまつり 超絶技巧プログラミング編 資料
クックパッド春の超絶技巧パンまつり 超絶技巧プログラミング編 資料
 
Enjoy Ruby Programming in IDE and TypeProf
Enjoy Ruby Programming in IDE and TypeProfEnjoy Ruby Programming in IDE and TypeProf
Enjoy Ruby Programming in IDE and TypeProf
 
TypeProf for IDE: Enrich Development Experience without Annotations
TypeProf for IDE: Enrich Development Experience without AnnotationsTypeProf for IDE: Enrich Development Experience without Annotations
TypeProf for IDE: Enrich Development Experience without Annotations
 
Ruby 3の型解析に向けた計画
Ruby 3の型解析に向けた計画Ruby 3の型解析に向けた計画
Ruby 3の型解析に向けた計画
 
emruby: ブラウザで動くRuby
emruby: ブラウザで動くRubyemruby: ブラウザで動くRuby
emruby: ブラウザで動くRuby
 
Type Profiler: Ambitious Type Inference for Ruby 3
Type Profiler: Ambitious Type Inference for Ruby 3Type Profiler: Ambitious Type Inference for Ruby 3
Type Profiler: Ambitious Type Inference for Ruby 3
 
型プロファイラ:抽象解釈に基づくRuby 3の静的解析
型プロファイラ:抽象解釈に基づくRuby 3の静的解析型プロファイラ:抽象解釈に基づくRuby 3の静的解析
型プロファイラ:抽象解釈に基づくRuby 3の静的解析
 
Ruby 3の型推論やってます
Ruby 3の型推論やってますRuby 3の型推論やってます
Ruby 3の型推論やってます
 
マニアックなRuby 2.7新機能紹介
マニアックなRuby 2.7新機能紹介マニアックなRuby 2.7新機能紹介
マニアックなRuby 2.7新機能紹介
 
A Static Type Analyzer of Untyped Ruby Code for Ruby 3
A Static Type Analyzer of Untyped Ruby Code for Ruby 3A Static Type Analyzer of Untyped Ruby Code for Ruby 3
A Static Type Analyzer of Untyped Ruby Code for Ruby 3
 
A Plan towards Ruby 3 Types
A Plan towards Ruby 3 TypesA Plan towards Ruby 3 Types
A Plan towards Ruby 3 Types
 
Ruby 3 の型解析に向けた計画
Ruby 3 の型解析に向けた計画Ruby 3 の型解析に向けた計画
Ruby 3 の型解析に向けた計画
 
A Type-level Ruby Interpreter for Testing and Understanding
A Type-level Ruby Interpreter for Testing and UnderstandingA Type-level Ruby Interpreter for Testing and Understanding
A Type-level Ruby Interpreter for Testing and Understanding
 
本番環境で使える実行コード記録機能
本番環境で使える実行コード記録機能本番環境で使える実行コード記録機能
本番環境で使える実行コード記録機能
 
Transcendental Programming in Ruby
Transcendental Programming in RubyTranscendental Programming in Ruby
Transcendental Programming in Ruby
 
Cookpad Hackarade #04: Create Your Own Interpreter
Cookpad Hackarade #04: Create Your Own InterpreterCookpad Hackarade #04: Create Your Own Interpreter
Cookpad Hackarade #04: Create Your Own Interpreter
 
Ruby 3のキーワード引数について考える
Ruby 3のキーワード引数について考えるRuby 3のキーワード引数について考える
Ruby 3のキーワード引数について考える
 
TRICK 2018 results
TRICK 2018 resultsTRICK 2018 results
TRICK 2018 results
 

Cookpad Spring 1day internship 2018 超絶技巧プログラミングコース資料