對局日誌不再什麼都念一遍
過去擲一次骰子就要列印五行,其中兩行說的是同一個格子。現在這條流讀起來像解說而不是筆錄——而且沒有為此刪掉任何東西。
通俗版
棋盤旁邊那塊面板把遊戲做過的每一件事都記了下來。一次普通的擲骰會產生五條獨立的記錄——擲了、移動了、落在哪、結束回合,往往還多一條——其中兩條說的是同一個格子。再乘以四名玩家、三十個回合,這條流就成了你不再去看的一堵牆;這很可惜,因為真正重要的那兩三行就藏在裡面。
現在一次擲骰和它引發的一切合成一行。落格、結束回合、在支付之前先宣佈一筆欠款、在拍賣開始前拒絕購買——這些都不再念出來,因為棋盤或下一行已經說明了。同一塊地上的一連串建造合併成一行,無人競價的拍賣不再把同一個金額報兩遍,而在極速模式裡,抵押倒數計時只在還剩兩回合可以處理時才出聲。
你的聊天訊息也不會再被擠出螢幕。面板以前對所有內容只保留一個歷史視窗,所以繁忙的棋盤會悄悄把別人打的字擠掉。現在活動和聊天分開儲存,再多的骰子也埋不掉一條真人寫下的訊息。
技術細節
在源頭過濾從來都不是一個選項。回放一局遊戲意味著把完整的事件日誌摺疊回一個狀態,而頁面重新整理、旁觀、回放檢視和集錦渲染器都是這麼工作的。為了讓日誌好看而丟掉一個事件,就會把這些全部弄壞。因此日誌保持完整,壓縮只是渲染層的事,放在一個共享的構建器裡,被即時棋盤、旁觀檢視、回放、集錦和離線版本共同使用。
每個事件對日誌的影響是一個覆蓋引擎全部事件型別的窮舉 switch,這意味著新增一種事件在有人決定它該怎麼念之前根本無法通過編譯:
// lib/game/feedDigest.ts — an exhaustive switch over every engine event
case 'dice_rolled':
return 'move'; // the roll opens a line
case 'moved':
case 'passed_start':
case 'jail_attempt_failed':
return 'absorb'; // …and what it caused folds into that line
case 'landed': // names the cell 'moved' just named
case 'turn_ended': // the board already shows whose turn it is (14% of events)
case 'payment_due': // the intent; 'debt_paid' is the settlement, with the amount
case 'buy_declined': // always followed by 'auction_started', which says it better
case 'auction_passed':// carries no information, and outnumbers real bids 2:1
return 'hidden';有兩個缺陷是任何測試都找不出來的,因為它們關乎輸出讀起來如何,而不是輸出包含什麼。無人競價的拍賣會把同一個數字報兩遍——「P1 出價 2600k」,然後「P1 以 2600k 拿下」——所以現在收官那一次出價會被吞掉,而且只吞這一次,真正的競價戰讀起來仍然像一場爭奪。另外,夾在擲骰中間的一個事件會讓每一條移動記錄提前結束,直到構建器學會跨過它。
