聲明
算法並非原創 , 但是來源已經忘記了 , 當時考慮算法的時候看了比較多的麻將胡牌算法 , 想尋找自己比較容易理解的 , 找了幾篇,所以算法的出處已然忘記,不過還是感謝下原創吧 .
算法
1.將麻將抽象爲數字
數字 {01 ~ 09} 表示 {1 ~ 9} 筒
數字 {11 ~ 19} 表示 {1 ~ 9} 條
數字 {21 ~ 29} 表示 {1 ~ 9} 萬
數字 {31 33 35 37 } 表示 { 東 南 西 北 }
數字 {41 43 45} 表示 {中 發 白}
數字10 20 30 32 34 36 40 42 44 46 空出來不代表任何麻將牌
這樣設計的好處就是
使得能夠形成順子的牌在用數字表示出來的時候剛好也是連着的
而不能夠形成順子的牌,在用數字表示的時候並不是順子
便於以後使用代碼進行判斷
2.算法的核心流程
玩過麻將的都知道麻將玩家手上一般有兩種牌 一種是手牌 一種是已經碰牌或者吃牌或者槓牌之後已經明瞭的牌 . 現在以玩家A爲例 , 把牌分的細一點
a. 玩家A的手牌 (數量1 + 3n n < N , n < 4 )
b. 其他玩家打出來的牌 (數量 1)
c. 玩家A從牌面上取出來的牌 (數量 1)
d. 玩家A吃碰槓的牌 (3n + 4*m)
能否胡牌主要是看手牌a 和b/c 的組合能否形成一對加n條順子和m條克子 . 能則能胡 反則不能.
代碼如下:
public static bool IsCanHU(List<int> mah, int ID)
{
List<int> pais = new List<int>(mah);
pais.Add(ID);
//只有兩張牌
if (pais.Count == 2)
{
return pais[0] == pais[1];
}
//先排序
pais.Sort();
//依據牌的順序從左到右依次分出將牌
for (int i = 0; i < pais.Count; i++)
{
List<int> paiT = new List<int>(pais);
List<int> ds = pais.FindAll(delegate (int d)
{
return pais[i] == d;
});
//判斷是否能做將牌
if (ds.Count >= 2)
{
//移除兩張將牌
paiT.Remove(pais[i]);
paiT.Remove(pais[i]);
//避免重複運算 將光標移到其他牌上
i += ds.Count;
if (HuPaiPanDin(paiT))
{
return true;
}
}
}
return false;
}
private static bool HuPaiPanDin(List<int> mahs)
{
if (mahs.Count == 0)
{
return true;
}
List<int> fs = mahs.FindAll(delegate (int a)
{
return mahs[0] == a;
});
//組成克子
if (fs.Count == 3)
{
mahs.Remove(mahs[0]);
mahs.Remove(mahs[0]);
mahs.Remove(mahs[0]);
return HuPaiPanDin(mahs);
}
else
{ //組成順子
if (mahs.Contains(mahs[0] + 1) && mahs.Contains(mahs[0] + 2))
{
mahs.Remove(mahs[0] + 2);
mahs.Remove(mahs[0] + 1);
mahs.Remove(mahs[0]);
return HuPaiPanDin(mahs);
}
return false;
}
}