鬥地主AI演算法——第五章の總值計算

pswyjz發表於2021-09-09

本章算是比較重點的一章,前一章已經對各個牌型做出了價值定義,本章主要實現計算手牌總價值模組函式。

根據之前的思路,我們設定一下輸入輸出:

輸入:手牌資料類(主要用手牌個數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;	vector NowPutCardList = 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;	vector NowPutCardList = 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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章