大忙人系列-程序猿在想什么 (一中) 禁止套娃
三. brainf**k
為什么叫這個名字呢,因為寫這個語言的代碼就如同在干自己的大腦一樣,故得此名。
邏輯結(jié)構(gòu)上圖靈機有四個部分組成,無限長的存儲帶,可以任意移動增刪改存儲格上的數(shù)字或符號的讀寫頭,狀態(tài)機,以及控制程序指令令機器進入一個新的狀態(tài)或保持狀態(tài)不變。顯然,brainf**k甚至挺契合這原始的定義。
那么,如何用brainf**k正常地寫程序呢?
鑒于說不定有的人不想去百度了,在這里就貼一下brainf**k的指令集。
> 讀寫頭右移
< 讀寫頭左移
+ 當前元素自增
- 當前元素自減
. 打印當前元素
, 輸入到當前元素
[ 若元素為0跳轉(zhuǎn)到匹配的],否則繼續(xù),為循環(huán)開始頭
] 跳轉(zhuǎn)到匹配的[
為了不被說成水字數(shù)(寫這個專欄的還好意思說?),下面一個符號加上一個數(shù)代表重復運算多少次吧。
可預見的是,這破玩意兒似乎連個加法都不太能正常地做到。為了避免因為信息量過大而燒腦,就從最簡單的東西開始做起吧。
第一題,讀入一個字符串以0結(jié)尾。
,[>,]
讀入,不是0就要讀下一個。
第二題,以換行為分界,讀入一個字符串
難度似乎瞬間就上了不少。眾所周知,換行符ASCII是10(不想考慮換行與回車之間的親(P)密(Y)關(guān)系了)。
那么,問題就是當前值不為10,就讀下一個嘍。
-10[+10>,-10]+10
熱身玩了,接下來來看看普通編程語言的各種語句能怎么整。
while(x) {sth}
最簡單的: x[sth x]
brainf**k天然支持while
if(x) {sth.}
temp[-]
x[ sth temp ]x
和while一樣,只不過多一步強制結(jié)束
if(x) {sth1} else {sth2}
temp0[-]+ ;temp0=1
temp1[-] ;temp1=0
x[ ;while(x) {
sth1
temp0- ;temp0=0
x[temp1+x-] ;temp1=x
] ;}
temp1[x+temp1-] ;x=temp1
temp0[
sth2
temp0-]
比較明顯的用了兩個變量來將if-else轉(zhuǎn)為兩個if
有了if有了while,那么任意程序都可以肆無忌憚隨心所欲了。感興趣的不如試著用brainf**k寫個brainf**k?
四. 生命游戲
生命游戲也是個被說爛了的東西。在一個二維平面上,如果一個細胞周圍有3細胞為生(一個細胞周圍共有8個細胞),則該細胞生。如果一個細胞周圍有2個細胞為生,則該細胞的生死狀態(tài)保持不變;其它情況下,該細胞為死。
生命游戲中,一個比較核心的東西是個叫“滑翔機”的由5個活的細胞組成,形狀如下:
001
110
011
可以預見的,如果沒有什么外部干擾,這個滑翔機可以飛到天荒地老。當兩個滑翔機撞在一起的時候,可以調(diào)整距離與周期到最后剛好消失掉(撞機了還想活?)。
有了滑翔機,當然要有個發(fā)射滑翔機的東西——滑翔機槍啦。
那么我們第一個邏輯門非門·of the·生命游戲出來了——一個滑翔機槍不停輸出滑翔機,如果有輸入(滑翔機),那么兩機相撞就會變成無輸出。第一個非門。
想造一個與門的話,先需要一個滑翔機槍加上一個吞噬者。吞噬者形狀大致如下:
0011
0101
0100
1100
假設機槍往右側(cè)發(fā)滑翔機并且被吞噬者吃掉。輸出為向上的方向,那么當且僅當有兩波滑翔機向上飛行,一波抵消,一波出去,這個時候才有輸出。(與門get)
或門類似,一開始兩個滑翔機槍垂直,所有的飛機抵消;兩個輸入中任意一個有飛機過來,抵消其中一個機槍,那么剩下的那個機槍就可以有輸出了。當然,當兩個輸入都有飛機時看情況需要吞噬者把輸入的飛機吃掉。
有了與、或、非,不試試鎖存器啊狀態(tài)機啊什么的神奇玩意兒嗎?