摘要:如果說「瞠目結(jié)舌」的話,IOCCC 上隨便拿一篇獲獎代碼出來就足以讓人下巴落地了。The International Obfuscated C Code Contest一個比較經(jīng)典的例子是 1988 年得獎的代碼,這個程序直接估算字符面積求圓周率,可讀性算是比較友好的:?westley.c?#define _ F-->00||-F-OO--;int F=00,O
如果說「瞠目結(jié)舌」的話,IOCCC 上隨便拿一篇獲獎代碼出來就足以讓人下巴落地了。
The International Obfuscated C Code Contest
一個比較經(jīng)典的例子是 1988 年得獎的代碼,這個程序直接估算字符面積求圓周率,可讀性算是比較友好的:
?westley.c?
#define _ F-->00||-F-OO--;int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO(){ _-_-_-_ _-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-__-_-_-_-_-_-_-_-_-_-_-_-_-_-_-__-_-_-_-_-_-_-_-_-_-_-_-_-_-_-__-_-_-_-_-_-_-_-_-_-_-_-_-_-_-__-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_ _-_-_-_}
注:這段程序?qū)嶋H上是 1989 年修正過的,由于 88 年原來程序代碼沒有考慮到 ANSI C 的編譯標(biāo)準(zhǔn),導(dǎo)致在處理例如
#define _ -i -_
的時候,老舊的 K&R 框架和 ANSI C 結(jié)果不一樣:K&R 是直接的
--i
而 ANSI C 編譯結(jié)果實(shí)際上等同于
-(-i)
因此之前的程序現(xiàn)在運(yùn)行的話出來的結(jié)果是 0.250,而不是 3.141。修正過的程序就沒有這個問題了。
又比如 13 年有個只有一行的程序,可以判斷從 Franklin Pierce 往后的 31 位美國總統(tǒng)是民主黨還是共和黨,這個就有點(diǎn)不知所云了:
?cable1.c?
main(int riguing,char**acters){puts(1[acters-~!(*(int*)1[acters]%4796%275%riguing)]);}
使用方法:
make cable1 ./cable1 obama republican democrat ./cable1 bush republican democrat
總統(tǒng)名要小寫,republican 和 democrat 順序不能顛倒。
經(jīng) @chua zier 提醒,歷史上的確有重名的美國總統(tǒng),除了 Johnson 之外,還有 Theodore Roosevelt / Franklin D. Roosevelt,程序原作者注明用
./cable1 roosevelt republican democrat
表示 Theodore Roosevelt,而用
./cable1 fdr republican democrat
表示 Franklin D. Roosevelt。
這一行代碼做了這么多事:首先查詢輸入的總統(tǒng)的名字,然后在一個 look-up table 里面找出對應(yīng)的政治陣營,再輸出出來。問題在于這 31 位總統(tǒng)名字存放在哪里?而這個 look-up table 又存放在哪里?
有趣的是,IOCCC 的評委還提到,你甚至可以用這個程序檢測一些 IT 大佬的 Mac / PC 陣營:
./cable1 Cooper Mac PC ./cable1 Noll Mac PC ./cable1 Broukhis Mac PC ./cable1 Jobs Mac PC ./cable1 Gates Mac PC ./cable1 Ballmer Mac PC
難道這個程序暴露了 Ballmer 離開微軟的真相?
最近幾屆比賽的代碼為了增加混亂程度,代碼越來越長,可讀性也越來越差(不過話說回來,讓可讀性變得越來越差其實(shí)原本就是這個比賽的第一宗旨吧),不少代碼甚至本身就是個 ASCII artwork……比如 11 年有一只阿卡林:
?akari.c?
為了保持美觀我就直接上圖了。源代碼見此:http://www.ioccc.org/2011/akari/akari.c
–––––––––– !!! 前方阿卡林軍團(tuán)高能預(yù)警 !!! ––––––––––
這個阿卡林程序?qū)嶋H上是一個圖像 down-sampler,可以接受符合條件的 PGM / PPM 灰度圖像或者 LF 換行(不支持 CR-LF)的 ASCII art 為輸入,然后轉(zhuǎn)換輸出一個處理后的圖像 / ASCII art。不過這個阿卡林最逆天的地方在于,它可以用自身的源代碼文本作為輸入,輸出生成另一個可以編譯運(yùn)行的程序的代碼!而且把這個生成的程序文本繼續(xù)作為輸入做進(jìn)一步 down-sample,又可以生成一段可以編譯的代碼,如此反復(fù),可以套多達(dá)4層!詳細(xì)的食用方法如下:
make akari
./akari akari.c akari2.c
然后生成的阿卡林·2號是這個樣子的:
?akari2.c?
看不清?請摘下眼鏡或者退遠(yuǎn)了看。注意,阿卡林·2號也是可以編譯運(yùn)行的,她的功能是把輸入的 ACSII 文本的每個字符中間插入空格以及每行之間插入空行,生成一段“疏松”了的文本。我們用阿卡林·2號自己做實(shí)驗(yàn)品:
make akari2.c ./akari2 <akari2.c> akari2fat.txt
成功了!生成了一只阿卡林·2號·舒松:
?akari2fat.txt?
阿卡林·2號還能干別的,她支持一個 rot13 參數(shù):
./akari2 rot13 <akari2.c> akari2fat.txt
生成的是經(jīng)過 ROT13 仿射變換的文本,我們稱之為阿卡林·2號·舒松·加蜜吧!
但是還沒完……如果我們把原版阿卡林放進(jìn)去再來一層呢?
./akari < akari.c | ./akari > akari3.c
于是阿卡林·3號誕生:
?akari3.c?
wm_aoi(n) /*ity,,[2*/{}char*y= (")M{lpduKtjsa(v""YY" "*yuruyuri") ;main(/*/",U/ R)U* Y0U= ="/\*/){puts (y+ 17/* "NR{I=" ){/=* =* */);/* **/{ ;;}}
可憐的阿卡林·3號,由于“馬賽克”(down-sample)次數(shù)太多,摘了眼鏡也只能模糊看到一點(diǎn)點(diǎn)……我們來問問阿卡林·3號對于誕生的感受吧:
make akari3 ./akari3
于是她回答:
yuruyuri
居然會說ゆるゆり!
最后,我們嘗試生產(chǎn)一下阿卡林·4號:
./akari < akari.c | ./akari | ./akari > akari4.c
?akari4.c?
main( ){puts ("Y""U RU YU "\"RI" ) /* */ ;}
順利生產(chǎn)!雖然內(nèi)容已經(jīng)直截了當(dāng)了,不過我們還是采訪一下她吧:
make akari4 ./akari4
她的答復(fù)是:
YU RU YU RI
至此,阿卡林軍團(tuán)全部誕生!
不得不佩服作者構(gòu)建代碼的精妙程度。他的個人主頁在這里:uguu... (這位作者其實(shí)已經(jīng)是這比賽的常客了,先后一共拿過 6 次不同的獎項(xiàng)。)
經(jīng) @馬琦明 提醒,我又把上面這位作者的另一個作品搬出來了,13 年的 Most Catty——炮姐程序。這程序的代碼長這個樣子:
?misaka.c?
源代碼:http://www.ioccc.org/2013/misaka/misaka.c
對的,當(dāng)你看到原來是這個“御坂”的時候,你就知道,我們要開始造(kè)人(lóng)了……
make misaka
這個御坂的作用是把輸入的 ASCII 橫向連接起來。首先連接兩個自己試試:
./misaka misaka.c misaka.c > misaka2.c
“把兩個御坂輸入一個御坂,會生成什么?”“兩個御坂?!?br/>
?misaka2.c?
聽起來很不可思議但是在這位作者的構(gòu)建下完全不出意外地,上面這個御坂-2 居然也是可以編譯運(yùn)行的:
make misaka2.c
御坂-2 的功能是把輸入的 ASCII 縱向連接起來。那我們就試著縱向連接兩個御坂:
./misaka2 misaka.c misaka.c > misaka3.c
于是御坂-3 誕生了:
?misaka3.c?
我們來運(yùn)行一下這個御坂-3。你此時腦中的景象可能是這樣的:
但是你錯了,御坂-3 會給你造出來更加精神污染的那只 long cat:
make misaka3
./misaka3
沒錯就是這只喵:
這里其實(shí)有 Unix 的 cat 指令的梗……如果之前你在執(zhí)行御坂-2 的時候,用了更多的御坂作為輸入,例如 4 個:
./misaka2 misaka.c misaka.c misaka.c misaka.c > misaka4.c
make misaka4.c
./misaka4
那么御坂-4 會給你造一只更長的 looooong cat:
按作者的意思,你可以最多疊加 31 個御坂來生成一只 looo....ooong cat(具體上限由編譯器的 sizeof(int) 決定)。
13 年還有浙大教授侯啟明寫的 ray tracer 程序,雖然代碼本身存在爭議是否符合比賽規(guī)則,例如為避免長度超限制而使用了一些壓縮方法、程序是個死循環(huán)。如果這段程序可讀性不是這么惡心的話其實(shí)還是非常值得鉆研的,里面用到了很多有趣的數(shù)據(jù)結(jié)構(gòu)和著色體系。
食用方法也很簡單,把程序掛在那兒跑一晚上,強(qiáng)制退出,就可以看結(jié)果了。由于是無窮盡的遞歸,程序跑的時間越長,圖像就越精致。詳細(xì)的說明和源文件還是參考官網(wǎng)吧:
Previous IOCCC Winners with spoilers
這里有個示例圖。
侯老師還有另外三個作品上榜,一個是極其酷炫的 syntax highlightener,還有一個(源代碼本身就是 GUI 的)科學(xué)計算器,后面這個已經(jīng)有人@paintsnow回答過了。最新一個是上個月剛剛公布的新一屆獲獎作品 MD5 without integers,但是這個的源碼還沒有公布,估計要等到明年了。