三、手牌的掃描

三、手牌的掃描

來自專欄 棋牌遊戲感悟

確定好牌的索引到牌的面值映射關係後,有必要對手牌進行掃描,以利於後續其他演算法的處理。

首先定義一個二維數組, cardsTable[5][20],用於存儲手牌的數目, cardsTable[0][val]表示手牌中面值為val的牌的數目;從1開始到4,cards[x][val]表示張數為x, 以val為結束的序列牌最大數目,即

如果 cardsTable[1][13] = 8, 1表示單張序列(順子),13表示牌值為K,8表示以K為結束的單張順子最長可以從6開始, 即手牌里沒有面值為5的牌,面值6, 7, 8, 9, T, J, Q, K都是有的。

如果 cardsTable[2][13] = 5,2表示連對,13表示結束牌值為K,5表示以K為結束的連對最長可以從9開始,即 9, T, J, Q, K 都有對子。8或者沒有,或者只有一張,無法形成連對。

以此類推,cardsTable[3][val] = n 表示以val為結束的飛機的最大連續數目,cardsTable[4][val]是連續4張牌的最大連續數目。

掃描手牌很簡單,先建立二維數組,統計一下各面值的張數,再累加到相應下標的cardsTable上。

self.scanToTable = function() { this.cardsTable = []; var i, j, val, num, arr; for (i = 0; i < Base.kCard_KindMax; ++i) { arr = []; for (j = 0; j < Base.kCard_TableMax; ++j) { arr[j] = 0; } this.cardsTable[i] = arr; } for (i = 0; i < this.theCards.length; i++) { val = Base.getCardValue(this.theCards[i]); this.cardsTable[0][val]++; } for (i = Base.kCard_Value3; i <= Base.kCard_ValueJoker2; ++i) { for (num = 4; num >= 1; --num) { if (this.cardsTable[0][i] >= num) { if (i <= Base.kCard_ValueA) { this.cardsTable[num][i] = this.cardsTable[num][i - 1] + 1; } else { this.cardsTable[num][i] = 1; } } else { this.cardsTable[num][i] = 0; } } }};

掃描手牌後,可以很快的建立連續牌序列,比如單張順子:

for (len = 1; len <= this.cardsTable[1][i]; len = len + (len == 1 ? 4 : 1))

i 為序列牌結束的面值。類似的連對,飛機等:

// 連對for (len = 1; len <= this.cardsTable[2][i]; len = len + (len == 1 ? 2 : 1))// 飛機查找for (len = 1; len <= this.cardsTable[3][i]; ++len)

len初始值為1,以上查找都包括了不是連續的牌型,比如單張K,一對K,三張K等。


推薦閱讀:

030 Substring with Concatenation of All Words[H]
頂點式線性平均內插擬合演算法
Q-learning 和 DQN
025 Reverse Nodes in k-Group[H]
014 Longest Common Prefix[E]

TAG:棋牌遊戲 | 鬥地主 | 演算法設計 |