前言 今天要實作接龍移牌提示,以下是會需要處理的題目:
怎麼取得場上牌的拖曳路線? 找到拖曳路線後,如何顯示要拖曳至哪個地方的提示(文字or動畫)? 取得拖曳路線 目前可知拖曳區塊有7牌堆、發牌區、結算牌堆,其中卡牌可拖曳的方向有:
7牌堆可以內部自拖曳或結算牌堆 發牌區只能拖曳至7牌堆、結算牌堆 結算牌堆只能拖曳至7牌堆 初步分析: 可以先計算可以移入7牌堆、結算牌堆牌尾的撲克牌
預計執行步驟: 計算出7牌堆、結算牌堆各自牌尾後能放什麼牌,儲存在Map 從發牌區/7牌堆/結算牌堆依序判斷可拖曳卡牌的數字是否存在Map中? 是,回傳比對成功的結果: { "可拖曳卡牌所在的牌堆", "拖曳卡牌在牌堆的位置", "預計移入的牌堆"} 否,繼續比對下一張直到無牌可比 實際程式碼 參數帶入要計算的全部牌堆,計算回傳每張牌可被移入的牌堆。 因為有可能出現梅花A可以移入結算牌堆或7牌堆的情況,所以實作設計成一張牌只會對應一個牌堆,此例梅花A會優先被移入結算牌堆。
// utils/poker-helper.js /** * 找出7牌堆、結算牌堆各牌尾後要接的牌 * @param {CardStacks} cardstacks * @returns {Map<Number, String>} Map<撲克牌編號, 目標牌堆名稱> */ function findTailCards(cardstacks) { const result = new Map(); // 找出可拖曳至7牌堆尾巴的牌 SEVEN_STACKS.forEach((name) => { const stack = cardstacks[name]; if (stack.length === 0) { [12, 25, 38, 51].forEach((value) => { result.set(value, name); }); return; } const lastCard = stack[stack.length - 1]; const lastCardNumber = lastCard.value % 13; const lastCardSymbol = Math.floor(lastCard.value / 13); // 檢查是否為A,則跳過 if (lastCardNumber === 0) { return; } const matchNumber = lastCardNumber - 1; const isBlack = lastCardSymbol % 3 == 0; [matchNumber + (isBlack ? 13 : 0), matchNumber + (isBlack ? 26 : 39)].forEach((value) => { result.set(value, name); }); }); // 找出可拖曳至結算牌堆尾巴的牌 FOUR_SUITS.forEach((name, index) => { const stack = cardstacks[name]; if (stack.length === 0) { result.set(0 + index * 13, name); return; } const lastCard = stack[stack.length - 1]; const lastCardNumber = lastCard.value % 13; // 檢查是否為K,則跳過 if (lastCardNumber === 12) { return; } const matchNumber = lastCardNumber + 1; result.set(matchNumber + index * 13, name); }); return result; } 參數帶入要計算的全部牌堆、發牌區發到的位置,一旦檢查到有一個卡牌符合則返回拖曳路線的資訊, 若無則返回null值。 // utils/poker-helper.js /** 取得一個移動提示 * @param {CardStacks} cardStacks * @param {number} dealerIndex * @returns {MoveHint | null} 移動提示 */ function getMoveHint(cardStacks, dealerIndex) { const tailValuesMap = findTailCards(cardStacks); let hintAnswer = null; // 發牌區 let startIndex = dealerIndex < 3 ? 0 : dealerIndex - 3; const dealerCards = cardStacks['dealerStacks'].slice(startIndex, dealerIndex); dealerCards.forEach((card) => { if (tailValuesMap.has(card.value)) { hintAnswer = { fromName: 'dealerStacks', card: card, fromIndex: cardStacks['dealerStacks'].findIndex((c) => c.value === card.value), toName: tailValuesMap.get(card.value), }; } }); if (hintAnswer != null) return hintAnswer; // 7個牌堆 SEVEN_STACKS.forEach((name) => { let len = cardStacks[name].length; for (let i = 0; i < len; i++) { let card = cardStacks[name][i]; // 由上往下找,遇到未開牌就跳過 if (!card.isOpen) continue; if (tailValuesMap.has(card.value)) { const toName = tailValuesMap.get(card.value); // 只能拿最後一張牌放 結算牌堆 if (FOUR_SUITS.includes(toName) && i !== len - 1) continue; hintAnswer = { fromName: name, card: card, fromIndex: i, toName: toName, }; break; } } }); if (hintAnswer != null) return hintAnswer; // 結算牌堆 FOUR_SUITS.forEach((name) => { let len = cardStacks[name].length; if (len == 0) return; let card = cardStacks[name][len - 1]; if (tailValuesMap.has(card.value)) { hintAnswer = { fromName: name, card: card, fromIndex: len - 1, toName: tailValuesMap.get(card.value), }; } }); return hintAnswer; } 執行拖曳提示動畫 目前已經可以呼叫函數getMoveHint取得拖曳路線的資訊
...