鬥地主AI-拆牌篇03
在《鬥地主ai-拆牌篇01》中介紹了拆牌相關的術語和基本邏輯。
玩樂兒童程式設計:鬥地主AI-拆牌篇01在《鬥地主ai-拆牌篇02》中介紹了利用遞迴思想,將手牌拆分為除可帶牌型外的所有可能套牌的邏輯。
玩樂兒童程式設計:鬥地主AI-拆牌篇02本篇就來闡述一下拆牌邏輯的第三步,根據上一步拆分的結果,對每種結果進行帶牌處理,生成所有可帶牌組合的邏輯,第三步結束後,拆牌的工作就算完成了。
- 計算帶牌邏輯輸入:除可帶牌型外的所有可能套牌
- 計算帶牌邏輯輸出:所有可能的拆牌組合構成的套牌
繼續上一篇中使用的手牌:3344555。
經過遞迴拆牌後輸入為:
[5,554433]
[555,44,33]
[555,44,3,3]
[555,4,4,33]
[5,55,44,33]
[555,4,4,3,3]
[5,5,5,44,33]
[55,5,44,3,3]
[5,55,4,4,33]
[5,55,4,4,3,3]
[5,5,5,44,3,3]
[5,5,5,4,4,33]
[5,5,5,4,4,3,3]
計算帶牌帶牌邏輯,遍歷每一種拆牌結果
1、檢視拆牌結果中套牌是否包括:三張、炸彈和飛機,並且有可以被帶的套牌:單張和對子。如果沒有可帶牌或被帶牌直接返回。否則,進行下一步。
2、計算可帶牌套牌的數量為(dpNum),從1遍歷到dpNum,求出每種可帶牌數量下的所有帶牌組合。意思是如果有3個套牌可以帶牌,那麼帶牌的結果可能是有1個套牌帶牌(三選一),有2個套牌帶牌(三選2),有3個套牌帶牌(三選三)。這也對應了真實對局中,即使多手可帶套牌,但是不一定全部按照帶牌的方式走出去。
舉例,[555,777,J,QQ]中有dpNum為2(555、777為可帶牌套牌),在真實對局中,不一定是按照555J、777QQ這樣出牌;也有可能是跟牌出了QQ,最後出555J和777。所以在計算可帶牌的第一步,就是每種可帶牌數量下的帶牌組合。
以[555,777,J,QQ]為例,有1個可帶牌套牌進行帶牌的可能包括:
- [555J,777,QQ]
- [555QQ,777,J]
- [555,777J,QQ]
- [555,777QQ,J]
以[555,777,J,QQ]為例,有2個可帶牌套牌進行帶牌的可能包括:
- [555J,777QQ]
- [555QQ,777J]
搞清楚了,為什麼要計算每種可帶牌數量後,進入下一步看如何確保每種情況都被考慮到。
3、為可帶牌套牌選擇被帶牌
3.1 首先,是從備選可帶牌中進行Cnm的選擇,其中C代表組合公式,n是bpNum,m是要選出來進行帶牌的數量。以上面[555,777,J,QQ]為例,就是C21等於2
3.2 對上面的組合計算出需要的帶牌數,如果被帶牌不能滿足則返回;如果能滿足,則按照需要的被帶牌數量對可帶牌套牌進行排序後,進入帶牌遞迴邏輯
3.3 帶牌遞迴邏輯,是帶牌的核心邏輯,明確遞迴的幾個要素:
- 遞迴結束邏輯:所有可帶牌套牌都已匹配到被帶牌
- 遞迴範圍減少:每匹配好一組可帶牌+被帶牌,就其從待匹配可帶牌套牌和待匹配被帶牌的列表中刪除,並生成匹配好的新套牌
- 遞迴返回結果:在遞迴過程中記錄,在遞迴結束時返回所有匹配好的新套牌。
以[555,777,J,QQ]為例,首先選擇1套可帶牌出來匹配,可選列表為[555,777],被帶列表為[J,QQ],進入遞迴
555可選的被帶牌列表為[J,QQ],555匹配J,記錄新套牌555J,更新可選列表[777],被帶列表為[QQ],進入遞迴
777可選的被帶牌列表為[QQ],777匹配QQ,記錄新套牌777QQ,更新可選列表[],被帶列表為[],結束遞迴,返回記錄到的新套牌[555J,777QQ]。
以上只是種一個遞迴分支,下面用示意圖的方式來表現遞迴。
最後,以文章開頭的輸入計算可帶牌的輸出(可粗部分為可帶牌的拆法):
- [5,554433]
- [555,44,33]
- [55544,33]
- [55533,44]
- [555,44,3,3]
- [55544,3,3]
- [5553,44,3]
- [555,4,4,33]
- [5554,4,33]
- [55533,4,4]
- [5,55,44,33]
- [555,4,4,3,3]
- [5554,4,3,3]
- [5553,4,4,3]
- [5,5,5,44,33]
- [55,5,44,3,3]
- [5,55,4,4,33]
- [5,55,4,4,3,3]
- [5,5,5,44,3,3]
- [5,5,5,4,4,33]
- [5,5,5,4,4,3,3]
到這裡AI的拆牌邏輯就告一段落了,如果有興趣瞭解完整的拆牌邏輯可以給我留言。