鬥地主AI演算法 第十二章 主動出牌 1

2021-09-19 03:05:52 字數 3722 閱讀 5583

本章開始,我們介紹主動出牌的演算法,和被動出牌類似,我們第一步把主要架子搭起來。

首先清空出牌序列

clshandcarddata.clearputcardlist();

主動出牌的策略按照優先順序大體可以分為三類:

【一】能直接一手牌出去,優先出。

【二】兩手牌出去且有絕對大牌,先出絕對大牌。

【三】出一手牌使得接下來自己手牌價值最大化。

//剪枝:如果能出去最後一手牌直接出

cardgroupdata surcardgroupdata = ins_surcardstype(clshandcarddata.value_ahandcardlist);

//如果能一次性出去且沒有炸彈,因為有炸彈的話權值可能會更大

if (surcardgroupdata.cgtype != cgerror&&!hasboom(clshandcarddata.value_ahandcardlist))

/*王炸——當前策略只處理王炸作為倒數第二手的優先出牌邏輯,後續版本會在此基礎上優化*/

if (clshandcarddata.value_ahandcardlist[

17] >

0 && clshandcarddata.value_ahandcardlist[

16] > 0)}

接下來就是第三步, 就是我們選擇打出一手牌盡量使得接下來自己手牌價值最大化。

與被動出牌不一樣的是,主動出牌我們沒有限制條件,我也嘗試過全部列舉,不過時間消耗肯定是**的。於是我定製了乙個基本的出牌優先順序策略:

①三帶一、飛機等牌優先打出,因為這種牌型可以把小牌帶出。其實這裡對比較大的三帶一不是很公平,後續版本可以在此處做分支處理,比如說三帶一的話只迴圈到10,j以上先不著急打出。飛機倒還好說,那玩意基本管不到別人,所以出了就出了。至於四帶二嘛。。。四帶二是個什麼東西?我不知道,我眼裡只有炸彈。

所以,這部分的架子應該是這樣的。

若可以出這幾種牌型,選擇一種價值最高的打出。因為要列舉所有的牌,所以在迴圈外根據最佳策略進行出牌處理。

②沒有上述牌型後,優先處理當前最小的一張牌。若是該牌有四張,先不處理。

這裡出牌處理就放在迴圈內了,因為當確定了這個i值後無論如何都是要打出一手牌的,且打完牌就可以return了。

③如果沒有從3到2的非炸牌,那麼看看有沒有單王,如果有,可以出。

//如果沒有3-2的非炸牌,則看看有沒有單王

if (clshandcarddata.value_ahandcardlist[

16] ==

1 && clshandcarddata.value_ahandcardlist[

17] ==

0)if (clshandcarddata.value_ahandcardlist[

16] ==

0 && clshandcarddata.value_ahandcardlist[

17] ==

1)

④單王也沒有,出炸彈。

//單王也沒有,出炸彈

for (

int i =

3; i <

16; i++)

}

這裡可能有人會想,需不需要再加上炸彈也沒有,出王炸呢?其實不存在的,因為如果你真的沒牌打了就剩王炸了,早在前面剪枝部分就處理了。

所以如果走到這裡都沒有返回的話,肯定是出現錯誤了。

把上述的各個模組連線起來,即構成主動出牌的基本架子:

void

get_putcardlist_2

(handcarddata &clshandcarddata)

/*王炸——當前策略只處理王炸作為倒數第二手的優先出牌邏輯,後續版本會在此基礎上優化*/

if (clshandcarddata.value_ahandcardlist[

17] >

0 && clshandcarddata.value_ahandcardlist[

16] >

0)//暫存最佳的價值

handcardvalue besthandcardvalue;

besthandcardvalue.needround =

20;besthandcardvalue.sumvalue = mincardsvalue;

//我們認為不出牌的話會讓對手乙個輪次,即加一輪(權值減少7)便於後續的對比參考。

besthandcardvalue.needround +=

1;//暫存最佳的組合

cardgroupdata bestcardgroup;

//帶出去的牌

int tmp_1 =

0;int tmp_2 =

0;int tmp_3 =

0;int tmp_4 =

0;//優先處理三牌、飛機等牌

for (

int i =

3; i <

16; i++)

//這部分出牌處理放到迴圈外

if (bestcardgroup.cgtype == cgthree_take_one)

else

if (bestcardgroup.cgtype == cgthree_take_two)

else

if (bestcardgroup.cgtype == cgthree_take_one_line)

else

if (bestcardgroup.cgtype == cgthree_take_two_line)

//次之處理當前價值最低的牌,現在不必再考慮這張牌可能被三牌帶出等情況

for (

int i =

3; i <

16; i++)

//如果沒有3-2的非炸牌,則看看有沒有單王

if (clshandcarddata.value_ahandcardlist[

16] ==

1 && clshandcarddata.value_ahandcardlist[

17] ==

0)if (clshandcarddata.value_ahandcardlist[

16] ==

0 && clshandcarddata.value_ahandcardlist[

17] ==

1)//單王也沒有,出炸彈

for (

int i =

3; i <

16; i++)

//異常錯誤

clshandcarddata.uctputcardtype = get_groupdata(cgerror,

0, 0);

return;

}

至此主動出牌的架子就搭好了,且除了三帶牌型出牌策略及解決最小值牌出牌策略這兩個大部分,其他部分**本章均已給出,下一章我們開始實現三帶牌型的出牌策略。

鬥地主AI演算法 第十二章 主動出牌 1

本章開始,我們介紹主動出牌的演算法,和被動出牌類似,我們第一步把主要架子搭起來。首先清空出牌序列 cpp view plain copy clshandcarddata.clearputcardlist 主動出牌的策略按照優先順序大體可以分為三類 一 能直接一手牌出去,優先出。二 兩手牌出去且有絕對...

鬥地主AI演算法 第十三章 主動出牌 2

上一章我們已經搭好了出牌演算法的基本框架,本章主要實現優先處理的三帶 飛機等牌型。首先定義一些基本變數 cpp view plain copy 暫存最佳的價值 handcardvalue besthandcardvalue besthandcardvalue.needround 20 besthan...

鬥地主AI演算法 第十四章 主動出牌 3

上一章已經排除了飛機 三帶等牌型,那麼除去炸彈王炸以外,我們只剩下單牌 對牌 三牌以及單順 雙順 三順了。首先說單牌 對牌 三牌。其邏輯基本一樣,只是出牌的個數有差別,即 如果該i牌數量滿足這種牌型要求,即先打出,計算其剩餘價值。出單牌 if clshandcarddata.value ahandc...