上一章我們已經搭好了出牌演算法的基本框架,本章主要實現優先處理的三帶、飛機等牌型。
首先定義一些基本變數:
[cpp]view plain
copy
//暫存最佳的價值
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;
因為列舉了牌型,所以實際和被動出牌邏輯都差不多,且沒有nmaxcard的限制,所以我們要從3開始遍歷。且上一章我們提到,不考慮炸彈拆分的情況。故value_ahandcardlist[i]不能等於4。
[cpp]view plain
copy
for (int i = 3; i < 16; i++)
} } clshandcarddata.value_ahandcardlist[i] += 3;
} //出三帶二
if (clshandcarddata.value_ahandcardlist[i] > 2)
} clshandcarddata.value_ahandcardlist[i] += 3;
} }
//出四帶二單
if (clshandcarddata.value_ahandcardlist[i] > 3)
//出四帶二對
if (clshandcarddata.value_ahandcardlist[i] > 3)
//出三帶一單連
if (clshandcarddata.value_ahandcardlist[i] > 2)
else
/*本來想做全排列選取帶出的牌然後列舉出最**值的,但考慮到當飛機長度也就是在2-4之間
所以乾脆做三個分支處理算了*/
//為兩連飛機
if (prov == 2)
clshandcarddata.nhandcardcount -= prov * 4;
for (int tmp1 = 3; tmp1 < 18; tmp1++)
clshandcarddata.value_ahandcardlist[tmp2] += 1;
} }
clshandcarddata.value_ahandcardlist[tmp1] += 1;
} }
for (int k = i; k <= j; k++)
clshandcarddata.nhandcardcount += prov * 4;
} //為三連飛機
if (prov == 3)
clshandcarddata.nhandcardcount -= prov * 4;
for (int tmp1 = 3; tmp1 < 18; tmp1++)
clshandcarddata.value_ahandcardlist[t***] += 1;
} }
clshandcarddata.value_ahandcardlist[tmp2] += 1;
} }
clshandcarddata.value_ahandcardlist[tmp1] += 1;
} }
for (int k = i; k <= j; k++)
clshandcarddata.nhandcardcount += prov * 4;
} //為四連飛機
if (prov == 4)
clshandcarddata.nhandcardcount -= prov * 4;
for (int tmp1 = 3; tmp1 < 18; tmp1++)
clshandcarddata.value_ahandcardlist[tmp4] += 1;
} }
clshandcarddata.value_ahandcardlist[t***] += 1;
} }
clshandcarddata.value_ahandcardlist[tmp2] += 1;
} }
clshandcarddata.value_ahandcardlist[tmp1] += 1;
} }
for (int k = i; k <= j; k++)
clshandcarddata.nhandcardcount += prov * 4;
} //若prov==5,則是地主可以直接出去,在剪枝部分已經處理
} }
//出三帶一雙連
if (clshandcarddata.value_ahandcardlist[i] > 2)
else
/*本來想做全排列選取帶出的牌然後列舉出最**值的,但考慮到當飛機長度也就是在2-4之間
所以乾脆做三個分支處理算了*/
//為兩連飛機
if (prov == 2)
clshandcarddata.nhandcardcount -= prov * 5;
for (int tmp1 = 3; tmp1 < 16; tmp1++)
clshandcarddata.value_ahandcardlist[tmp2] += 2;
} }
clshandcarddata.value_ahandcardlist[tmp1] += 2;
} }
for (int k = i; k <= j; k++)
clshandcarddata.nhandcardcount += prov * 5;
} //為三連飛機
if (prov == 3)
clshandcarddata.nhandcardcount -= prov * 5;
for (int tmp1 = 3; tmp1 < 16; tmp1++)
clshandcarddata.value_ahandcardlist[t***] += 2;
} }
clshandcarddata.value_ahandcardlist[tmp2] += 2;
} }
clshandcarddata.value_ahandcardlist[tmp1] += 2;
} }
for (int k = i; k <= j; k++)
clshandcarddata.nhandcardcount += prov * 5;
} //若prov==4,則是地主可以直接出去,在剪枝部分已經處理
} }
} }
這個迴圈結束後,若有好的選擇,則bestcardgroup會保留出牌的型別,在迴圈外進行出牌處理。
[cpp]view plain
copy
if (bestcardgroup.cgtype == cgthree_take_one)
else if (bestcardgroup.cgtype == cgthree_take_two)
else if (bestcardgroup.cgtype == cgthree_take_one_line)
if (bestcardgroup.ncount / 4 == 2)
if (bestcardgroup.ncount / 4 == 3)
if (bestcardgroup.ncount / 4 == 4)
clshandcarddata.uctputcardtype = bestcardgroup;
return;
} else if (bestcardgroup.cgtype == cgthree_take_two_line)
if (bestcardgroup.ncount / 5 == 2)
if (bestcardgroup.ncount / 5 == 3)
clshandcarddata.uctputcardtype = bestcardgroup;
return;
}
因為回溯遍歷部分與被動出牌完全一樣,這裡就不再贅述。飛機在出牌階段的處理比較麻煩,要根據牌數進行判斷是幾連飛機。
下一章,我們將實現打出當前最小值牌部分。
鬥地主AI演算法 第十四章 主動出牌 3
上一章已經排除了飛機 三帶等牌型,那麼除去炸彈王炸以外,我們只剩下單牌 對牌 三牌以及單順 雙順 三順了。首先說單牌 對牌 三牌。其邏輯基本一樣,只是出牌的個數有差別,即 如果該i牌數量滿足這種牌型要求,即先打出,計算其剩餘價值。出單牌 if clshandcarddata.value ahandc...
鬥地主AI演算法 第十二章 主動出牌 1
本章開始,我們介紹主動出牌的演算法,和被動出牌類似,我們第一步把主要架子搭起來。首先清空出牌序列 cpp view plain copy clshandcarddata.clearputcardlist 主動出牌的策略按照優先順序大體可以分為三類 一 能直接一手牌出去,優先出。二 兩手牌出去且有絕對...
鬥地主AI演算法 第十二章 主動出牌 1
本章開始,我們介紹主動出牌的演算法,和被動出牌類似,我們第一步把主要架子搭起來。首先清空出牌序列 clshandcarddata.clearputcardlist 主動出牌的策略按照優先順序大體可以分為三類 一 能直接一手牌出去,優先出。二 兩手牌出去且有絕對大牌,先出絕對大牌。三 出一手牌使得接下...