1. 程式人生 > >棋牌遊戲開發之地主AI演算法實現

棋牌遊戲開發之地主AI演算法實現

棋牌遊戲開發疑問交流 QQ:325131039(勿發廣告)

棋牌遊戲開發技術交流群: 490287966(勿發廣告

   ps: 轉載自一位遠古大神的,本博文只適合像我一樣的菜鳥閱讀,高手們請別噴呀,謝謝!

  “人工智慧”(Artificial Intelligence)簡稱AI。它是研究、開發用於模擬、延伸和擴充套件人的智慧的理論、方法、技術及應用系統的一門新的技術科學。人工智慧研究如何用計算機去模擬、延伸和擴充套件人的智慧;如何把計算機用得更聰明;如何設計和建造具有高智慧水平的計算機應用系統;如何設計和製造更聰明的計算機以及智慧水平更高的智慧計算機等

                                                                                                              ----------摘自百度百科

 在這裡我們主要的談論如何電腦來模擬人的思維出牌,並且實現一種具體的演算法。

名詞解釋:

出牌手數:在假設別人都不要並且滿足出牌規則的情況下,最多幾次能把所有的牌出完,這幾次就叫做出牌手數,你可千萬別理解成這個手術喲。

首先我們可以將地主AI演算法分成2部分來討論。

今天我們來討論第一部分:

  拆牌

拆牌是地主AI中比較重要的一部分,拆牌的好壞直接影響著地主AI演算法的高效問題。

我們首先還是上一張圖片,這樣比較直觀,有利於我們以後的討論。


為每一種牌型定義權值的大小:

單張                              1

對子                              2

三帶                              3

連牌                              4  (每多一張牌權值+1)

連對                              5(每多一對牌,權值+2)

飛機                             6(每對以飛機,權值在基礎上+3)

炸彈                             7(包括對王在內) 

看到這副牌,我們先按照人的正常思路來拆牌看是怎麼樣的。

QQQ   222

45678910J

AA 

小鬼 6,4

我們現在就來討論一種方案,看最終能達到這樣的拆牌方案嗎?

我們把拆牌的過程分幾個步驟來討論。

第一步:找牌

定義對應的牌型vector

vector<three> //3條

vector<lianzi> //連子

vector<duizi>//對子

vector<danzhang> //單張

vector<fly> //飛機

       首先 找出一副牌中只能組成一種牌型的牌(3條,對子,單張為一種牌型。)意思就是有一張牌和剩餘牌中的任何一張牌沒有聯絡。當然是否和剩餘的牌有聯絡是需要定義一個規則的:是否和剩餘的牌能組成連子,連隊。如果這2個條件都不滿足那麼我們稱這張牌和剩餘的牌沒有任何聯絡。一般情況下通過這個步驟就能找出幾張牌,這樣能為以後的拆牌減輕任務量。

比如上面我們就能找出:小鬼,2,A,接下來找出牌值和他們一樣的牌。即小鬼,222,AA,剩下的牌就是:QQQJ1098766544,可能有人會問為什麼沒有找出QQQ了,這是因為Q除了能組成3條,對子以外,還能和剩餘的牌組合成連牌。這裡找出來是對子最終的拆牌方案中就為對子,是連3條就是3條。3條>對>單張 於是有了我們接下來的結論。

vector<three> 222

vector<duizi> AA

vector<danzhang>  小鬼

接下來我們就來拆分剩餘的牌:QQQJ1098766544

找出牌中所有的炸彈

找出牌中所有的3個

找出牌中所有的對子

根據剩餘的牌我們首先提出  QQQ              66    44

我們這裡可以定義對應的vector來存入我們臨時找出的牌,注意裡定義的vector和上面的vector是不一樣的。

vector<three> QQQ

vector<two>66,44

第二步:計算每一種牌的手數和權值問題(拆牌中的難點)

分幾種情況來討論,每次只找出剩餘牌中的5張連牌,然後拿這5張連牌和剩餘牌依次拼接看能否組合成更長的連牌

提出牌之後,剩餘的全部牌全部看做為單牌,不管是炸彈,3條,還是對子。

1 在剩餘牌中提出QQQ ,J1098766544  首先找出5張單牌,從最小還是最大由你來決定。我們這裡就以最小來討論。

第一次:45678  剩餘牌為 4 6 9 10 J

第二次:45678910J  46

最後拆出來的2組牌都沒有聯絡,拆牌結束。

方案為:45678910J       4   6   QQQ

對應的權值和手數:7+1+1+3 =12       3(因為3個可以帶一張或者是1對,當有對子和單張張的時候手數要減去1)

以下的幾種方案也是同樣的步驟,我就不寫過程了,直接寫最終的方案。

2在剩餘牌中提出 QQQ 66 

方案為: QQQ 66   78910j   5   44

 對應的權值和手數:  3+2+4+1+2=12            4

3.在剩餘牌中提出 QQQ 44

方案為: QQQ   44  678910j    6

對應的權值和手數:3+2+5+1 =11             3

4 .在剩餘排中提出 66

方案為: 66  78910jQ    QQ     5  44

對應的權值和手數:2+5+2+1+2=10          5

5 .在剩餘牌中提出 44

方案為: 44  5678910JQ     6   QQ

對應的權值和手數:2+7+1+2 =12      4

6 .什麼牌也不提出 

45678910JQ  4  6  Q                 

對應的權值和手數:9+1+1+1=12         4

第三步:選出最優的一組牌作為最後的拆牌方案

通過以上步驟我們確定出了幾種出牌方案,我們最後找出出牌手數最小的方案。

如果手數相同的情況下,找權值最大的一組拆牌方案。

如果2者都相同,就隨機選一種就是了。(這種情況很小很小) 

通過比較我們確定了下面的這一種拆牌方案。

方案為:45678910J       4   6   QQQ

對應的權值和手數:7+1+1+3 =12       3(因為3個可以帶一張或者是1對,當有對子和單張張的時候手數要減去1)

最後加入我們最先找出的牌,最終的拆牌方案為:

vector<three> 222 ,QQQ

vector<duizi> AA

vector<danzhang>  小鬼 ,4,6

vector<lianzi>  45678910J

呵呵,通過這樣拆出來的牌是不是很符合正常人的思維呀。

我們拆這樣一種拆牌方案出來是當電腦出牌的時候用。

當然我們還需要定義一個結構體來存入每張牌能組成的所有牌型。和每種牌型的最大值,這樣供以後的接牌最準備。

好了,就到這裡了,以後再來討論出牌!!