鬥地主AI演算法——第五章の總值計算
本章算是比較重點的一章,前一章已經對各個牌型做出了價值定義,本章主要實現計算手牌總價值模組函式。
根據之前的思路,我們設定一下輸入輸出:
輸入:手牌資料類(主要用手牌個數nHandCardCount以及手牌狀態陣列clsHandCardData.value_aHandCardList)
輸出:手牌價值結構 HandCardValue
先處理剪枝部分,如果剩下的手牌是一手牌,我們即直接返回該牌型的價值,這個下一章會寫出,我們先假設存在這個函式ins_SurCardsType。
其返回值設計:若是一手牌,返回牌型,若不是一手牌,返回錯誤牌型。
CardGroupData uctCardGroupData = ins_SurCardsType(clsHandCardData.value_aHandCardList); //如果能一次性出去且沒有炸彈,因為有炸彈的話權值可能會更大 if (uctCardGroupData.cgType != cgERROR&& !HasBoom(clsHandCardData.value_aHandCardList)) { uctHandCardValue.SumValue = uctCardGroupData.nValue; uctHandCardValue.NeedRound = 1; return uctHandCardValue; }
若不是一手牌的情況,我們透過get_PutCardList函式(後續幾章會寫出實現方法)獲取最佳的出牌策略 進行出牌,
/*只是獲取出牌的序列,即clsHandCardData.value_nPutCardList及clsHandCardData.uctPutCardType 其他成員均無改變,也不會呼叫出牌函式,get_PutCardList返回最優方案*/ get_PutCardList_2(clsHandCardData); //要儲存當前的clsHandCardData.value_nPutCardList及clsHandCardData.uctPutCardType用於回溯 CardGroupData NowPutCardType = clsHandCardData.uctPutCardType; vectorNowPutCardList = clsHandCardData.value_nPutCardList; if (clsHandCardData.uctPutCardType.cgType == cgERROR) { cout
獲取完出牌序列後,打出這些牌(只改變value_aHandCardList陣列),再計算剩餘的牌總價值。
for (vector::iterator iter = NowPutCardList.begin(); iter != NowPutCardList.end(); iter++) { clsHandCardData.value_aHandCardList[*iter]--; } clsHandCardData.nHandCardCount -= NowPutCardType.nCount; //---回溯 HandCardValue tmp_SurValue = get_HandCardValue(clsHandCardData);//遞迴剩餘牌價值 //---回溯 for (vector ::iterator iter = NowPutCardList.begin(); iter != NowPutCardList.end(); iter++) { clsHandCardData.value_aHandCardList[*iter]++; } clsHandCardData.nHandCardCount += NowPutCardType.nCount; //---回溯 uctHandCardValue.SumValue = NowPutCardType.nValue + tmp_SurValue.SumValue; uctHandCardValue.NeedRound = tmp_SurValue.NeedRound + 1;
最後將返回的價值與當前打出的牌價值相加即時該階段手牌總價值。
下面給出完整程式碼
/*透過回溯dp的方式獲取手牌價值與get_PutCardList作為交替遞迴呼叫返回:價值結構體HandCardValue權值的計算規則參考標頭檔案評分邏輯思維*/HandCardValue get_HandCardValue(HandCardData &clsHandCardData){ //首先清空出牌佇列,因為剪枝時是不呼叫get_PutCardList的 clsHandCardData.ClearPutCardList(); HandCardValue uctHandCardValue;//出完牌了,其實這種情況只限於手中剩下四帶二且被動出牌的情況,因為四帶二剪枝做了特殊處理。 if (clsHandCardData.nHandCardCount == 0) { uctHandCardValue.SumValue = 0; uctHandCardValue.NeedRound = 0; return uctHandCardValue; } //————以下為剪枝:判斷是否可以一手出完牌 CardGroupData uctCardGroupData = ins_SurCardsType(clsHandCardData.value_aHandCardList); //————不到萬不得已我們都不會出四帶二,都儘量保炸彈 if (uctCardGroupData.cgType != cgERROR&&uctCardGroupData.cgType != cgFOUR_TAKE_ONE&&uctCardGroupData.cgType != cgFOUR_TAKE_TWO) { uctHandCardValue.SumValue = uctCardGroupData.nValue; uctHandCardValue.NeedRound = 1; return uctHandCardValue; } //非剪枝操作,即非一手能出完的牌 /*只是獲取出牌的序列,即clsHandCardData.value_nPutCardList及clsHandCardData.uctPutCardType 其他成員均無改變,也不會呼叫出牌函式,get_PutCardList返回最優方案*/ get_PutCardList_2(clsHandCardData); //要儲存當前的clsHandCardData.value_nPutCardList及clsHandCardData.uctPutCardType用於回溯 CardGroupData NowPutCardType = clsHandCardData.uctPutCardType; vectorNowPutCardList = clsHandCardData.value_nPutCardList; if (clsHandCardData.uctPutCardType.cgType == cgERROR) { cout ::iterator iter = NowPutCardList.begin(); iter != NowPutCardList.end(); iter++) { clsHandCardData.value_aHandCardList[*iter]--; } clsHandCardData.nHandCardCount -= NowPutCardType.nCount; //---回溯 HandCardValue tmp_SurValue = get_HandCardValue(clsHandCardData);//遞迴剩餘牌價值 //---回溯 for (vector ::iterator iter = NowPutCardList.begin(); iter != NowPutCardList.end(); iter++) { clsHandCardData.value_aHandCardList[*iter]++; } clsHandCardData.nHandCardCount += NowPutCardType.nCount; //---回溯 uctHandCardValue.SumValue = NowPutCardType.nValue + tmp_SurValue.SumValue; uctHandCardValue.NeedRound = tmp_SurValue.NeedRound + 1; return uctHandCardValue;}
注:當前出牌策略是2.0版本,所以是get_PutCardList_2,後續還會寫出更多的版本,敬請期待。
如果你之前瞭解回溯演算法的話,那麼應該很好理解上述程式碼,若沒有接觸過回溯,可以看我以前的部落格http://blog.csdn.net/sm9sun/article/details/53244484
總值計算的模組就算完成了,其實並沒有太多東西,除了一個回溯遞迴以外就是裡面呼叫了兩個函式ins_SurCardsType判斷是否是一手牌以及get_PutCardList出牌邏輯。那麼下一章我們便要實現這個ins_SurCardsType函式。
敬請關注下一章:鬥地主AI演算法——第六章の牌型判斷
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/755/viewspace-2804696/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Python鬥地主Python
- 模擬鬥地主
- 自己實現鬥地主引擎
- Java鬥地主專案碎片Java
- 用Python破解鬥地主殘局Python
- 鬥地主老是輸?一起用Python做個AI出牌器!PythonAI
- Python 三人鬥地主程式碼Python
- Java寫的鬥地主遊戲原始碼Java遊戲原始碼
- Golang多執行緒簡單鬥地主Golang執行緒
- 趁老王不在,和隔壁鄰居鬥鬥地主,比比大小
- 使用Java實現簡單的鬥地主案例Java
- Map實現鬥地主發牌有序版二
- 遊戲《鬥遊鬥地主》被撤銷出版物號,為今年首款遊戲
- 【計算機演算法】 求字首表示式的值計算機演算法
- 8、用java的ArrayList集合完成模擬鬥地主案例Java
- 平行計算π值
- 計算機視覺 の1. 影像預處理計算機視覺
- [豪の學習筆記] 計算機網路#003筆記計算機網路
- “歡喜鬥地主”等44款App存違規行為APP
- 用鬥地主的例項學會使用java Collections工具類Java
- P2540 [NOIP2015 提高組] 鬥地主 加強版
- 第五章與JS(奸商)鬥爭的日子JS
- python 計算 sin 值Python
- 位元組跳動入股《芒果鬥地主》開發商林子互娛
- 【恐怖の演算法】 掃描線演算法
- 【恐怖の演算法】 揹包DP演算法
- python計算對數值Python
- 【數值計算方法】數值積分&微分
- 上班划水神器:一個可以在控制檯玩鬥地主的專案!
- 計算機演算法計算機演算法
- 計算機系統002 – 數值運算計算機
- 亞畫素數值極值檢測演算法總結演算法
- springboot+Java+cocos creater鬥地主,麻將非常的完整棋牌遊戲專案Spring BootJava遊戲
- 賽博鬥地主——使用大語言模型扮演Agent智慧體玩牌類遊戲。模型智慧體遊戲
- 桝田省治的JRPG戰鬥數值設計入門
- 【數值計算方法】線性方程組迭代演算法的Python實現演算法Python
- 五種C語言非數值計算的常用經典排序演算法C語言排序演算法
- 計算機視覺逼近賽點,高估值AI公司的焦慮與未來計算機視覺AI