因為玩接龍有時會有按錯步,這時候沒有返回上一步的機制就只能硬著頭皮玩下去或按重置,今天想解決這個問題。
在ReactJS官方學習文件中OOXX遊戲Tic-Tac-Toe也有提到時光旅行的實作,基本上就是每一步更動後的結果狀態都推入(Push)陣列變數history裡面,時光回朔就是將結果狀態直接設為history[index]。
目前開發下來的程式碼大概要回到上一步的只有分數、牌組、發牌的索引,
經過的時間應該就不用上一步。
首先宣告一個負責儲存歷史的ref變數history
const history = ref([]);
宣告函數pushStateToHistory()負責撰寫把最新的狀態推入history
reactive的關係所以不得不手動深度複製每張卡牌,這也是為什麼要做elemFunc的原因/** 儲存當前狀態到歷史紀錄 */
function pushStateToHistory() {
if (history.value.length > 30) {
const startIndex = history.value.length - 30;
history.value = history.value.slice(startIndex, history.value.length);
}
const elemFunc = (card) => ({
"value": card.value,
"isOpen": card.isOpen,
"isDone": card.isDone,
});
history.value = [
...history.value,
{
"cardStacks": {
first: cardStacks.first.slice().map(elemFunc),
second: cardStacks.second.slice().map(elemFunc),
third: cardStacks.third.slice().map(elemFunc),
fourth: cardStacks.fourth.slice().map(elemFunc),
fifth: cardStacks.fifth.slice().map(elemFunc),
sixth: cardStacks.sixth.slice().map(elemFunc),
seventh: cardStacks.seventh.slice().map(elemFunc),
dealerStacks: cardStacks.dealerStacks.slice().map(elemFunc),
club: cardStacks.club.slice().map(elemFunc),
diamond: cardStacks.diamond.slice().map(elemFunc),
heart: cardStacks.heart.slice().map(elemFunc),
spade: cardStacks.spade.slice().map(elemFunc),
},
"gameScore": JSON.parse(JSON.stringify(gameScore.value)),
"dealer": { index: dealer.index },
}
];
}
接著在程式碼中【分數、卡牌有變動】的情況都補上執行pushStateToHistory();去儲存當下的狀態:
發牌區移動/結算牌堆移動/7牌堆移動成功移動後resetGame
clickAutoMove只要成功移動,最後也會執行發牌區
<DealerArea />點擊開牌也會執行pushStateToHistory();,因為發牌索引dealer.index產生變化
返回上一步函數undo的演算法:
history變數的陣列的長度,若長度大於1繼續往下執行,否則不執行後續步驟。history目前最後一個元素就是當下的狀態,所以從history克隆出原本長度減一的陣列暫存至變數prevHistory
history的值更新為prevHistory
prevHistory最後一個元素內的狀態發牌區/結算牌堆/7牌堆/遊戲分數/發牌索引的值全都覆蓋到對應變數/** 返回上一步 */
function undo() {
if (history.value.length > 1) {
const prevHistory = history.value.slice(0, history.value.length - 1);
history.value = prevHistory;
const prevState = prevHistory[prevHistory.length - 1];
cardStacks.dealerStacks = prevState.cardStacks.dealerStacks;
FOUR_SUITS.forEach((deckName) => {
cardStacks[deckName] = prevState.cardStacks[deckName];
})
SEVEN_STACKS.forEach((deckName) => {
cardStacks[deckName] = prevState.cardStacks[deckName];
})
gameScore.value = prevState.gameScore;
dealer = prevState.dealer;
}
}
今日除了完成返回上一步的功能使得遊戲玩起來更有趣😎也盡可能以演算法的角度更明確的步驟去說明程式碼的實現。
程式碼: https://github.com/kabuto412rock/ithelp-pokergame/tree/day26
參考