日麻折騰筆記Java篇(1)——和牌的判斷
手牌和牌時(shí)的組成
日本麻將除了特殊牌形(七對(duì)和國(guó)士)以外,都是?a個(gè)順子+b個(gè)刻子+1個(gè)雀頭
?的形狀,這里不管是門(mén)清還是非門(mén)清,都是這樣。其中a、b均大于等于0。
我們可以將手牌分解成上面的形式,如果能夠滿足條件,則為和牌,然而手牌的組成有很多種,比如下面的手牌(九蓮寶燈):
11123455678999s
我們可以分解為
111 234 55 678 999
可以和牌
也可以分解為
11 123 345 567 8 999
無(wú)法和牌
可以看到關(guān)鍵在于怎么對(duì)手牌中的順子和刻子分組
從雀頭入手
不管怎么分組,手牌都要有一個(gè)雀頭
,所以我們先確定雀頭
手牌中,數(shù)量大于等于2的牌都能作為雀頭
當(dāng)確定好雀頭之后,就要將剩余的手牌分解為 順子+刻子的情況,在上面的示例中,當(dāng)選取5s作為雀頭后,剩余的牌為 111234678999 ,我可以將 11123 認(rèn)為是 111+23的形式,也可以是 11+123的形式,用程序也是比較方便實(shí)現(xiàn)的。
我的思路
將手牌排序后,找到n個(gè)雀頭
對(duì)于每個(gè)雀頭,都執(zhí)行下面的判斷邏輯
去除雀頭,得到剩余手牌P
對(duì)P按照牌進(jìn)行分組后排序
對(duì)于排序后的牌,如果是連續(xù)三張牌,則將這三張牌作為一個(gè)順子
將順子的三張牌從P中刪除
重復(fù)2-3-4步驟,直到無(wú)順子
對(duì)P進(jìn)行分組
如果某牌數(shù)量是3,則將這三張牌作為一個(gè)刻子
將刻子從P中刪除
重復(fù)6-7-8步驟,直到無(wú)刻子
如果P現(xiàn)在無(wú)牌,則表示此時(shí)能夠和牌,如果有牌,表示不能和牌
是否聽(tīng)牌的判斷
和牌和聽(tīng)牌不太一樣,和牌是14張,聽(tīng)牌是13張,不管是不是門(mén)清狀態(tài),聽(tīng)牌必定幣和牌少一張,少的是哪張牌呢?必定是下面三種情況中的其中一種
聽(tīng)雀頭
聽(tīng)刻子中的一張
聽(tīng)順子中的一張
也就是已有的手牌,加上上面三種中的其中一種,能夠和牌,那我只需要將可能和牌的牌都列出來(lái),每種都判斷是否和牌就可以了。
對(duì)于自己的程序?qū)懙挠袥](méi)有問(wèn)題,可以用九蓮寶燈來(lái)驗(yàn)證一下
類的定義
首先是類型的枚舉,定義了萬(wàn)、索、筒、字四種牌
public enum Type {
? ? m,
? ? s,
? ? p,
? ? z;
}
一張牌是由數(shù)字+類型組成的,所以牌類如下
public class Pai implements Comparable<Pai> {
? ? private Integer number;
? ? private Type type;
? ? ... getters
? ? ... setters
對(duì)于字牌,一共有東南西北中發(fā)白,七種類型,對(duì)應(yīng)的number取值為1到7,在編碼時(shí)還需要注意字牌是無(wú)法組成順子的。
對(duì)于一場(chǎng)比賽,牌的數(shù)量類型都是早就決定好不會(huì)變的,唯一變的就是牌的順序,我們只需定義好一個(gè)所有牌的集合,在有需要生成牌山的時(shí)候,直接將其打亂使用即可。
寶牌是否要在class Pai
中定義?由于每場(chǎng)比賽,寶牌是變化的,與場(chǎng)況有關(guān),所以不太適合放在其中。但是有一個(gè)例外——赤寶牌,我本想在Pai中增加一個(gè)屬性aka/red,標(biāo)示是否是赤寶牌,但想到現(xiàn)在只是在對(duì)手牌進(jìn)行和牌、聽(tīng)牌的判斷,增加這個(gè)字段與否和現(xiàn)在要解決的問(wèn)題無(wú)關(guān),索性就不管了,寶牌之類,留著后面再統(tǒng)一處理吧。
