本章算是比較重點的一章,前一章已經對各個牌型做出了價值定義,本章主要實現計算手牌總價值模組函式。
根據之前的思路,我們設定一下輸入輸出:
輸入:手牌資料類(主要用手牌個數nhandcardcount以及手牌狀態陣列clshandcarddata.value_ahandcardlist)
輸出:手牌價值結構 handcardvalue
先處理剪枝部分,如果剩下的手牌是一手牌,我們即直接返回該牌型的價值,這個下一章會寫出,我們先假設存在這個函式ins_surcardstype。
其返回值設計:若是一手牌,返回牌型,若不是一手牌,返回錯誤牌型。
[cpp]view plain
copy
cardgroupdata uctcardgroupdata = ins_surcardstype(clshandcarddata.value_ahandcardlist);
//如果能一次性出去且沒有炸彈,因為有炸彈的話權值可能會更大
if (uctcardgroupdata.cgtype != cgerror&& !hasboom(clshandcarddata.value_ahandcardlist))
若不是一手牌的情況,我們通過get_putcardlist函式(後續幾章會寫出實現方法)獲取最佳的出牌策略 進行出牌,
[cpp]view plain
copy
/*只是獲取出牌的序列,即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)
獲取完出牌序列後,打出這些牌(只改變value_ahandcardlist陣列),再計算剩餘的牌總價值。
[cpp]view plain
copy
for (vector::iterator iter = nowputcardlist.begin();
iter != nowputcardlist.end(); iter++)
clshandcarddata.nhandcardcount -= nowputcardtype.ncount;
//---回溯↑
handcardvalue tmp_survalue = get_handcardvalue(clshandcarddata);//遞迴剩餘牌價值
//---回溯↓
for (vector::iterator iter = nowputcardlist.begin();
iter != nowputcardlist.end(); iter++)
clshandcarddata.nhandcardcount += nowputcardtype.ncount;
//---回溯↑
ucthandcardvalue.sumvalue = nowputcardtype.nvalue + tmp_survalue.sumvalue;
ucthandcardvalue.needround = tmp_survalue.needround + 1;
最後將返回的價值與當前打出的牌價值相加即時該階段手牌總價值。
下面給出完整**
[cpp]view plain
copy
/* 通過回溯dp的方式獲取手牌價值
與get_putcardlist作為交替遞迴呼叫
返回:價值結構體handcardvalue
權值的計算規則參考標頭檔案評分邏輯思維
*/
handcardvalue get_handcardvalue(handcarddata &clshandcarddata)
//————以下為剪枝:判斷是否可以一手出完牌
cardgroupdata uctcardgroupdata = ins_surcardstype(clshandcarddata.value_ahandcardlist);
//————不到萬不得已我們都不會出四帶二,都盡量保炸彈
if (uctcardgroupdata.cgtype != cgerror&&uctcardgroupdata.cgtype != cgfour_take_one&&uctcardgroupdata.cgtype != cgfour_take_two)
//非剪枝操作,即非一手能出完的牌
/*只是獲取出牌的序列,即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)
//---回溯↓
for (vector::iterator iter = nowputcardlist.begin();
iter != nowputcardlist.end(); iter++)
clshandcarddata.nhandcardcount -= nowputcardtype.ncount;
//---回溯↑
handcardvalue tmp_survalue = get_handcardvalue(clshandcarddata);//遞迴剩餘牌價值
//---回溯↓
for (vector::iterator iter = nowputcardlist.begin();
iter != nowputcardlist.end(); iter++)
clshandcarddata.nhandcardcount += nowputcardtype.ncount;
//---回溯↑
ucthandcardvalue.sumvalue = nowputcardtype.nvalue + tmp_survalue.sumvalue;
ucthandcardvalue.needround = tmp_survalue.needround + 1;
return ucthandcardvalue;
}
如果你之前了解回溯演算法的話,那麼應該很好理解上述**,若沒有接觸過回溯,可以看我以前的部落格
總值計算的模組就算完成了,其實並沒有太多東西,除了乙個回溯遞迴以外就是裡面呼叫了兩個函式ins_surcardstype判斷是否是一手牌以及get_putcardlist出牌邏輯。那麼下一章我們便要實現這個ins_surcardstype函式。
鬥地主AI演算法 第五章 總值計算
本章算是比較重點的一章,前一章已經對各個牌型做出了價值定義,本章主要實現計算手牌總價值模組函式。根據之前的思路,我們設定一下輸入輸出 輸入 手牌資料類 主要用手牌個數nhandcardcount以及手牌狀態陣列clshandcarddata.value ahandcardlist 輸出 手牌價值結構...
演算法第五章實踐
寫在開頭 emm,這一次的上機是目前來說最自閉的一次,因為,居然!只做出了一道!看來最近的學習跟刷題還是怠慢了,要加把勁了 正文 第一題,用回溯法實現0 1揹包。一開始直接貼了乙個dfs然後稍微的剪了一下枝,然後發現無論怎麼剪枝,第三第四個樣例都會tle。沒辦法,只好加乙個限界函式,在每一次遞迴前加...
演算法第五章作業
1.你對回溯演算法的理解 回溯演算法實際上乙個類似列舉的搜尋嘗試過程,主要是在搜尋嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就 回溯 返回,嘗試別的路徑。回溯法是一種選優搜尋法,按選優條件向前搜尋,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通...