【TIS-100 攻略】第 20 關(guān):序列檢索器

本文首發(fā)于 B 站《TIS-100》文集(https://www.bilibili.com/read/readlist/rl626023)。原創(chuàng)不易,轉(zhuǎn)載請(qǐng)注明出處。
第 20 關(guān)《序列檢索器》(Sequence Indexer)關(guān)卡展示

本關(guān)的 IN.V 會(huì)給你 10 個(gè)數(shù)字,最后的?0?是序列末端標(biāo)志。然后你每收到一個(gè) IN.X 里的數(shù)字,就需要向 OUT 端口輸出,IN.V 里的第 X 個(gè)數(shù)是多少。這里的位置是從 0 開始的,比如,當(dāng)你從 IN.V 收到 [860, 215, 230, 784, 900, 978, 945, 124, 432, 697, 0] 時(shí),第 0 個(gè)數(shù)字是 860,第 1 個(gè)數(shù)字是 215,依此類推,直到最后的第 9 個(gè)數(shù)字為 697。
這里我先拋出一個(gè)結(jié)論:當(dāng)棧里有 n 個(gè)數(shù)字,且你要取第 x?個(gè)數(shù)字(和題目一樣,x?從 0 開始到 n-1 結(jié)束),那么你需要彈 n-x 次棧才能取到想要的數(shù)。如下圖所示:當(dāng)一個(gè)棧里有 8 個(gè)數(shù)字,你要取得第 3 個(gè)數(shù)字時(shí),需要彈 5 次棧才能得到:






由此可得,彈棧次數(shù)跟 n 和 x?兩個(gè)量相關(guān)。本關(guān)的 n 固定為 10,那么對(duì)于每個(gè) x,彈棧的次數(shù)都為 10-x。本關(guān)的代碼如下:

IN.V 下方的節(jié)點(diǎn)用于將 IN.V 提供的所有數(shù)字全部壓入棧中,包括最后的 0(mov up right)。所有數(shù)字均壓入棧中后,該節(jié)點(diǎn)會(huì)的任務(wù)就完成了,我們即可放任該節(jié)點(diǎn)被卡住。
IN.X 下方的節(jié)點(diǎn)首先執(zhí)行了一定次數(shù)的空循環(huán),讓 acc 從 11 數(shù)到 0(mov 11 acc, sub 1, jnz 2)。這是為了等待左半邊把 IN.V 里提供的所有數(shù)字都放入棧中。我試出來的最少空循環(huán)次數(shù)是 11 次。空循環(huán)完畢后,我們將最后放入棧中的哨兵 0 彈出(mov left acc)。接下來,這個(gè)節(jié)點(diǎn)不斷從 IN.X 中讀取 x 的值往下發(fā)(mov up down)。注意發(fā)完 x 后要跳回第 5 行,不能放任代碼跳回到第 1 行的空循環(huán)處(jmp 5)。
中央靠右的節(jié)點(diǎn)兩個(gè)任務(wù):一是將收到的 X 傳給正中央的節(jié)點(diǎn)(mov up left),另一個(gè)是把從正中央節(jié)點(diǎn)得到的對(duì)應(yīng)值發(fā)給下面的節(jié)點(diǎn)(mov left down)。
正中央的節(jié)點(diǎn)首先計(jì)算 10-x 的值,這便是我們需要彈棧的次數(shù)(mov 10 acc, sub right)。我們需要先彈出 10-x 個(gè)數(shù)字,待取到對(duì)應(yīng)值后,我們還需要將這 10-x 個(gè)值放回去。因此我們要執(zhí)行兩遍 10-x 次的循環(huán),我們需要將這個(gè)循環(huán)次數(shù)額外復(fù)制一份到 bak 里(sav)。接下來我們就開始彈棧了:每從上方的棧彈出一個(gè)數(shù)字,都將彈出的數(shù)字放到下方的棧里暫存(mov up down),同時(shí)令彈棧的剩余次數(shù)減 1(sub 1)。剩余次數(shù)尚未減到 0 時(shí),跳回到第 4 行繼續(xù)彈(jnz 4),直到剩余次數(shù)為 0 時(shí),我們就成功地將 10-x 個(gè)數(shù)放到了下方的棧里。
此時(shí),下方棧里的第一個(gè)數(shù)就是我們需要發(fā)送給 OUT 的數(shù),將它取出(mov down acc),發(fā)給右邊后(mov acc right)再放回原處(mov acc down)。得到本次的答案后,我們要將下方棧里的 n-x 個(gè)數(shù)原封不動(dòng)地放回去。我們將之前備份到?bak 里的 n-x 重新拿出來(swp),然后開始將下方的 n-x 個(gè)數(shù)歸位。每從下方彈一個(gè)數(shù)回去(mov down up),就令剩余次數(shù)減 1(sub 1),并判斷剩余次數(shù)是否到達(dá)了 0。尚未到達(dá) 0 時(shí),跳回第 11 行繼續(xù)彈(jnz?b),直到剩余次數(shù)歸零為止。
OUT 上方的節(jié)點(diǎn)沒啥說的,它會(huì)從中央靠右的節(jié)點(diǎn)收到所有的輸出值,只要來者不拒,通通送往 OUT 口就完事了(mov up down)。
點(diǎn)擊左下角的【RUN】,稍等片刻,便會(huì)彈出結(jié)算界面:
