鬥地主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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 模擬鬥地主
- 聯眾鬥地主計牌器V2.2註冊演算法分析演算法
- 自己實現鬥地主引擎
- 練習4. 鬥地主遊戲遊戲
- Android鬥地主遊戲原始碼Android遊戲原始碼
- 破解鬥地主1。0 (932字)
- Java寫的鬥地主遊戲原始碼Java遊戲原始碼
- 用Python破解鬥地主殘局Python
- JAVA集合練習:鬥地主發牌Java
- 鬥地主老是輸?一起用Python做個AI出牌器!PythonAI
- Python 三人鬥地主程式碼Python
- Golang多執行緒簡單鬥地主Golang執行緒
- 請教如何破解鬥地主 (269字)
- 使用Java實現簡單的鬥地主案例Java
- Map實現鬥地主發牌有序版二
- 遊戲《鬥遊鬥地主》被撤銷出版物號,為今年首款遊戲
- 集合框架-模擬鬥地主洗牌和發牌案例框架
- 8、用java的ArrayList集合完成模擬鬥地主案例Java
- 鬥地主4.0註冊演算法,序號產生器在OCG論壇 (22千字)演算法
- 【計算機演算法】 求字首表示式的值計算機演算法
- 計算PI值到一億位的演算法 (轉)演算法
- 用鬥地主的例項學會使用java Collections工具類Java
- “歡喜鬥地主”等44款App存違規行為APP
- 1.cocos2d-x鬥地主實現-發牌
- 計算機視覺 の1. 影像預處理計算機視覺
- 第五章與JS(奸商)鬥爭的日子JS
- 平行計算π值
- 位元組跳動入股《芒果鬥地主》開發商林子互娛
- 插值演算法總結演算法
- Octave 數值計算
- 演算法題:如何判斷計算的 π 值是否精確?演算法
- 開心鬥地主1.7S4非法註冊破解 (512字)
- 數值計算 插值與擬合
- 上班划水神器:一個可以在控制檯玩鬥地主的專案!
- 開心鬥地主1.6標準版 註冊碼破解 (4千字)
- 數值計算基礎
- 使用 Python 計算 π 值Python
- AI計算,風起歐洲AI