最近在玩一款編程類的游戲,叫做《程序員升職記》勘畔,steam 平臺(tái)只需¥36所灸。通過(guò)組合幾條非常基本的指令炫七,例如加減爬立、自加、自減万哪、比較懦尝、跳轉(zhuǎn),實(shí)現(xiàn)一些小功能壤圃,例如簡(jiǎn)單的數(shù)值絕對(duì)值輸出、兩數(shù)乘法琅轧、階乘運(yùn)算伍绳、反轉(zhuǎn)字符串等。游戲的本質(zhì)是一款支持 11 條指令乍桂,最多支持 24 字節(jié)內(nèi)存的 8 位 cpu 的運(yùn)行冲杀。
這款游戲前面的一些關(guān)卡主要在引導(dǎo)和介紹游戲,同時(shí)不斷給出新的指令睹酌,開(kāi)始只有簡(jiǎn)單的幾條指令权谁,后面會(huì)加入對(duì)內(nèi)存的使用,間接尋址的使用憋沿,因此可以實(shí)現(xiàn)指針的操作旺芽。每一關(guān)都會(huì)給出隨機(jī)的輸入,經(jīng)過(guò)你編寫的程序后辐啄,算出符合要求的輸出采章。編寫程序的過(guò)程可以通過(guò)單步運(yùn)行來(lái)調(diào)試,所以可以很快知道程序在哪里出錯(cuò)壶辜,并修改悯舟。
這款游戲可以很好地幫助你理解 CPU 的運(yùn)行原理,編寫的程序其實(shí)就是匯編程序砸民,每一條指令都可以對(duì)應(yīng)到一條匯編指令抵怎。通過(guò)復(fù)制指令到記事本也可以看出奋救。關(guān)卡的輸入每一次都是隨機(jī)出現(xiàn)的,這就要求程序要在任何合理的輸入下都可以正確運(yùn)行反惕,而不是當(dāng)前給定的輸入尝艘。這款游戲又不像我之前玩過(guò)的另一款手機(jī)上的編程類游戲--light robot。這款游戲在指令的條數(shù)上沒(méi)有任何限制承璃,也就是說(shuō)你可以使用不限數(shù)量的指令來(lái)實(shí)現(xiàn)你的程序利耍,但另一方面游戲非常鼓勵(lì)你找到一種最優(yōu)解,使得指令條數(shù)和運(yùn)算次數(shù)都盡可能的少盔粹,這意味著程序所需的代碼空間很少隘梨,同時(shí)運(yùn)算速度又最快。所以你可以先按照你對(duì)這個(gè)題目的解題思路來(lái)實(shí)現(xiàn)這個(gè)程序舷嗡,等程序完美運(yùn)行沒(méi)有出錯(cuò)后轴猎,再來(lái)考慮怎么優(yōu)化程序。light robot 是一款通過(guò)組合指令來(lái)實(shí)現(xiàn)不同的點(diǎn)燈效果的游戲进萄,但是這個(gè)游戲是限制指令數(shù)量的捻脖,因此你不能先實(shí)現(xiàn)再進(jìn)行優(yōu)化,你必須一來(lái)就找到最優(yōu)解中鼠,這讓我在后面的關(guān)卡無(wú)法繼續(xù)可婶。
這款游戲還有一個(gè)特點(diǎn)就是支持單步調(diào)試,通過(guò)單步運(yùn)行援雇,可以很快看出運(yùn)行出錯(cuò)的地方矛渴,結(jié)合指令,可以很快看出錯(cuò)誤惫搏。在簡(jiǎn)單的測(cè)試沒(méi)有出錯(cuò)之后具温,又可以全速運(yùn)行程序,完成題目筐赔。因?yàn)樗械念}目基本上都是需要通過(guò)跳轉(zhuǎn)來(lái)實(shí)現(xiàn)循環(huán)結(jié)構(gòu)的铣猩,這樣可以實(shí)現(xiàn)不停的輸入。而在你剛開(kāi)始編寫的程序中茴丰,很可能是沒(méi)有考慮到所有情況的达皿,可能這組輸入運(yùn)算正確,而到了下一組就不正確了较沪。因此通過(guò)單步鳞绕,中斷運(yùn)行,回退指令可以查看運(yùn)算錯(cuò)誤的原因尸曼,這和平常的開(kāi)發(fā)也很像们何。
開(kāi)頭說(shuō)了,這款游戲的解題過(guò)程其實(shí)就是一款簡(jiǎn)單 CPU 運(yùn)行的過(guò)程控轿。這款 CPU 最多支持11條指令冤竹,可以分為四類拂封。第一類基本輸入輸出 input/output,第二類對(duì)內(nèi)存的讀寫 copyfrom/copyto鹦蠕,第三類加減運(yùn)算冒签,包括加減一個(gè)數(shù),和一個(gè)數(shù)自加一和自減一钟病,第四類跳轉(zhuǎn)指令萧恕,包括無(wú)條件跳轉(zhuǎn)、值為零跳轉(zhuǎn)肠阱、值為負(fù)跳轉(zhuǎn)票唆。第一類和第四類指令的運(yùn)行不需要提供參數(shù),指令的運(yùn)行僅影響 CPU 寄存器或者僅受 CPU 寄存器的影響屹徘。而第二類和第三類的指令是需要提供一個(gè)參數(shù)的走趋,剛開(kāi)始這個(gè)參數(shù)是一個(gè)值,后面的關(guān)卡中加入了間接尋址噪伊,可以通過(guò)類似指針的操作來(lái)實(shí)現(xiàn)更多的功能簿煌,因此第二類和第三類指令的參數(shù)也支持地址參數(shù)。
根據(jù)關(guān)卡的不同鉴吹,可以用的內(nèi)存大幸涛啊(地毯數(shù)量)是不同的,最多的時(shí)候有 24 字節(jié)豆励,有時(shí)候地毯上是有值的授滓,類似于C語(yǔ)言中帶初值的全局變量。對(duì)內(nèi)存的使用主要是讀寫肆糕,而且不允許對(duì)一個(gè)空的內(nèi)存執(zhí)行讀操作,因?yàn)榇藭r(shí)該值是未知的在孝。內(nèi)存用來(lái)暫存一些程序運(yùn)行時(shí)的中間數(shù)據(jù)诚啃。很多關(guān)卡都會(huì)在內(nèi)存中給一個(gè) 0 值,因?yàn)?CPU 不支持立即尋址私沮,因此將 0 值通過(guò)內(nèi)存的方式給定始赎,0 值經(jīng)常被用于計(jì)數(shù),因此你可能需要在程序的開(kāi)始將其復(fù)制到另一塊內(nèi)存中仔燕,以確保下一次的輸入還是可以拷貝一個(gè) 0造垛,并從 0 開(kāi)始計(jì)數(shù)。
這款游戲的編程語(yǔ)言是匯編晰搀,從程序執(zhí)行結(jié)構(gòu)上來(lái)說(shuō)就只有兩種五辽,一種是順序結(jié)構(gòu),另一種是選擇結(jié)構(gòu)外恕,而循環(huán)結(jié)構(gòu)則是需要通過(guò)選擇結(jié)構(gòu)和跳轉(zhuǎn)指令來(lái)實(shí)現(xiàn)的杆逗。但由于跳轉(zhuǎn)指令只有三條乡翅,帶條件的只有值為零和值為負(fù)兩種,也就是說(shuō)在做某些題是需要判斷值為正的罪郊,則需要進(jìn)行對(duì)應(yīng)的轉(zhuǎn)換蠕蚜。在后面的關(guān)卡中,出現(xiàn)的題目比較復(fù)雜悔橄,需要采用子程序的設(shè)計(jì)來(lái)實(shí)現(xiàn)靶累,類似于函數(shù)的概念。有一關(guān)里面甚至給出了一小段程序癣疟。
這款游戲的關(guān)卡不是很多挣柬,通關(guān)也不會(huì)花費(fèi)很長(zhǎng)的時(shí)間,但是程序給出了一個(gè)最優(yōu)解的標(biāo)準(zhǔn)争舞,對(duì)指令數(shù)量和運(yùn)行次數(shù)的最大值給以限制凛忿,想要每一關(guān)都可以實(shí)現(xiàn)最優(yōu)解也是需要費(fèi)一番功夫的。另外游戲本身是有一條故事線的竞川,雖然關(guān)系并不大店溢,但是聊勝于無(wú)。