Ai鬥地主智能出牌算法

去年有想寫個鬥地主的小遊戲,自己玩玩。找了很多資料,後來好不容易在網上找到了一個AI算法。轉過的的時候是貼在自己電腦的TXT文本上,再次感謝下原作者。現在借花獻佛發給你參考下。 我以前寫過一個鬥地主機器人。思路如下,希望對你有幫助。

鬥地主AI設計

一、牌型

1 火箭:大小王在一起的牌型,即雙王牌,此牌型最大,什麼牌型都可以打。

2 炸彈:相同點數的四張牌在一起的牌型,比如四條A。除火箭外,它可以打任何牌型,炸彈對炸彈時,要比大小。

3 單支(一手牌):單張牌,如一支3。

4 對子(一手牌):相同點數的兩張牌在一起的牌型,比如55。

5 三條:相同點數的三張牌在一起的牌型,比如三條4。

6 三帶一手:三條 + 一手牌的牌型,比如AAA+9或AAA+77。

7 單順:五張或更多的連續單支牌組成的牌型,比如45678或345678910JQKA。2和大小王不可以連。

8 雙順:三對或更多的連續對子組成的牌型,比如334455或445566778899。2和大小王不可以連。

9 三順:二個或更多的連續三條組成的牌型,比如777888或444555666777。2和大小王不可以連。

10 飛機帶翅膀:三順 + 同數量的一手牌,比如777888+3+6或444555666+33+77+88。

11 四帶二:四條+兩手牌。比如AAAA+7+9或9999+33+55。

二、牌型分析

1 單順的確定

a) 選取五連,先取出最小的一個五連,再在剩餘的牌中取出最小的一個五連,依此類推,直到沒有五連爲止。

b) 擴展五連,將剩餘的牌與已經取出的牌進行比對,如果某張剩餘的牌與已知的連牌能組成更大的連牌,則將其合併。一直到無法合併爲止。

c) 合併連牌,如果某兩組連牌能無縫連接成更大的連牌,則將其合併成一組。

經過上述選取、擴展和合並,則將一手牌中的所有連牌提取出來了,舉例如下:

假定一手牌是:2AKQJ1099877766543

第一步,選取出34567,678910兩個連牌組。剩餘的牌還有79JQKA2

第二步,剩餘的JQKA能和678910組成新的連牌678910JQKA。

第三步,已知的兩個連牌組不能合併成新的、更大的連牌組,則這手牌就被分成了34567、678910JQKA兩個連牌組和7、9、2三張單牌。

2 雙順的確定 將一副牌中所有的對子檢測出來,然後將對子排序,按照檢測三連的方式可以將所有的雙順都提取出來。

3 三條的確定 一副牌中的所有三條都能比較方便地提取出來。

4 三順的確定 在三條的基礎上進行比較,如果有相連的三條,則將其合併成(儘可能大的)三順。

5 炸彈的確定 所有的四頭都能很方便地確定。

6 火箭的確定 只要牌張包含大小王,就將其組成火箭。

7 牌張的分類方法

a) 先確定火箭:判斷是否有大小王。

b) 再確定炸彈:判明是否有四頭。

c) 再確定三條:在除了炸彈以外的牌中判斷是否包含三條。

d) 再確定三順:在已經確定的三條中判斷是否包含相鄰的三條,如果有,則將其組成三順。注意,應該使三順的數量儘可能大。即如果有444555666,則將其合成一個三順,而不是分成444555一個三順和666一個三條。

e) 再確定單順:判斷單順時必須去除四個2以外的所有炸彈。首先判斷是否存在除了三條牌(這裏的三條是指所有的三條)以外的連牌,如果有,則將其提取出來。其 次,將剩餘的牌與每一個三條(不包含三順)進行試組合,如果能夠重新組成單順和對子,則將原有的三條取消,重新組合成連牌和單順(例子4566678重新 組成45678和66)。最後,將已知的連牌、三條(不包含三順)和剩下的牌張再試組合,將所有如45678(已知的連牌)999(三條)10J(單 牌),重新組合成45678910J和99。通過以上的方法,就能將連牌和三條很好地重新組合。

f) 再確定雙順:首先,如果兩單順牌完全重合,則將其重新組合成雙順。其次,在除炸彈、三順、三條、單順以外的牌中檢測是否包含雙順。如果有,將其提取出來。

g) 再確定對子:在炸彈、三順、三條、連牌、雙順以外的牌中檢測是否存在對子,如果存在將其提取出來。

h) 再確定單牌:除了炸彈、三順、三條、連牌、雙順、對子以外的所有牌張都是單牌。

8 對子的確定 參見上一節的“再確定對子”。

9 單牌的確定 參見上一節的“再確定單牌”。

三、一手牌的手數分析 爲 了使鬥地主機器人有一定的智能,必須對一手牌的手數進行分析。所謂一手牌的手數,指的是在沒有別人壓牌的情況下需要出幾把能將牌出完。這個數字在經過上面 的分類後是可以確定的。還以上面的一手牌22AAKQJ9987776654爲例,這手牌按照前面的分析方法可以分析出以下的牌型: 22、AA、K、Q、J、987654、9、77、6的牌型 通過對上面牌型的計算,可以容易得出這手牌需要9手才能出完,因此這手牌的手數就是9。

四、絕對手數和相對手數的概念 因爲在鬥地主遊戲中存在火箭或炸彈的可能,所以理論上只有火箭纔不可能被別人壓住,所以,可以不考慮相對手數的概念。以後都簡稱手數。

五、叫牌原則分析 因爲在鬥地主中,火箭、炸彈、王和2可以認爲是大牌,所以叫牌需要按照這些牌的多少來判斷。下面是一個簡單的原則: 假定火箭爲8分,炸彈爲6分,大王4分,小王3分,一個2爲2分,則當分數 大於等於7分時叫三倍; 大於等於5分時叫二倍; 大於等於3分時叫一倍; 小於三分不叫。

六、出牌的一般原則

1 出牌的原則一般按照從小到大的原則,即首先出包含最小牌的組合(單牌、對子、雙順、連牌、三順、三條等,炸彈、火箭不包括在內)。

2 三條的出牌原則:因爲三條出牌可以帶一張單牌或一個對子,所以在出三條時需要檢測是否有單牌,如果有,則帶一張最小的單牌,如果沒有,則再檢測是否存在對子,如果有,則跟一個最小的對子,如果單牌和對子都沒有,則出三條。 在帶牌時,除非是隻剩兩手牌,否則不能帶王或2。

3 三順的出牌原則:因爲三順出牌可以帶兩張(或更多)單牌或兩個(或更多)對子,所以與出三條一樣,需要檢測是否有單牌或對子。如果有足夠多的單牌或對子, 則將其帶出。如果有單牌,但沒有足夠多的單牌,則檢查是否有6連以上的連牌,如果有將連牌的最小張數當作單牌帶出。如果有對子,但沒有足夠多的對子,則檢 查是否有4連以上的雙順,如果有將雙順的最小對子當作對子帶出。 在帶牌時,除非是隻剩兩手牌,否則不能帶王或2。

4 連牌的出牌原則:直接出。

5 雙順的出牌原則:直接出。

6 對子的出牌原則:因爲對子可以用三條、三順等帶出,所以在出對子時,應該先檢測一下三條+三順(中三條)的數量,如果所有三條數量 <= 對子+單牌數量總和-2時,出對子,否則出三帶2等等。

7 單牌的出牌原則:因爲單牌可以用三條、三順等帶出,所以在出單牌時,應該先檢測一下三條+三順(中三條)的數量,如果所有三條數量 <= 對子+單牌數量總和-2時,出單牌,否則出三帶1等等。

七、跟牌的一般原則

1 如果手中有獨立的,與所出的牌一樣牌型的牌時,先跟之。

2 2可以作爲單牌、對子、三條等形式跟出。

3 當手中沒有相應牌跟時,如果是本方人員出的牌,可以不跟,如果是對方出的牌,則必須拆牌跟,如果再沒有,出炸彈或火箭,否則PASS。

4 如果手中的牌除了炸彈。火箭外還剩一手牌,則如果牌型相符,則先跟之,否則炸之。

5 單牌的跟牌原則:如果手中有單牌,則跟之,否則拆2跟之,否則拆對牌跟之,否則拆6連以上的單順頂張跟之,否則拆三條跟之,否則拆三順跟之,否則拆5連單順跟之,否則拆雙順跟之,否則炸之,否則PASS。

6 對牌的根牌原則:如果手中有對子,則跟之,否則拆4連以上的雙順頂張跟之,否則拆三條跟之,否則拆雙順跟之,否則拆三順跟之,否則炸之,否則PASS。

7 三條、三帶1、三帶2等牌的根牌原則:如果手中有相同牌型的牌則跟之,否則拆三順跟之,否則炸之,否則PASS。注意,只有在手中牌在出了以後還剩一手牌時,或直接出完的情況下,才允許帶王或2。 在沒有足夠牌帶的情況下,參照單牌。對子的拆牌原則進行拆牌處理。

8 三順及三順帶牌的根牌原則:如果有相應的牌型,則跟之,否則可以將大的三順拆成小的三順跟之,否則炸之,否則PASS。注意,只有在手中牌在出了以後還剩一手牌時,或直接出完的情況下,才允許帶王或2。 在沒有足夠牌帶的情況下,參照單牌。對子的拆牌原則進行拆牌處理。

9 連牌的跟牌原則:如果有相應的牌型,則跟之,否則拆相同張數的雙順,否則拆相同張數的三順,否則拆不同張數的連牌,否則拆不同張數的雙順,否則拆不同張數的三順,否則炸之,否則PASS。

10 雙順的跟牌原則:有相同牌型的牌,則跟之,否則拆不同張數的雙順,否則拆不同張數的三順,否則拆相同張數的三順,否則炸之,否則PASS。

11 炸彈的跟牌原則:有超過所出炸彈的炸彈,或有火箭,則炸之,否則PASS。

12 炸彈帶兩手牌的跟牌原則:如果有炸彈,則炸之,否則PASS。

八、打牌原則解析

1 坐莊打法:因爲坐莊的只是自己一個人,不存在配合問題,所以一般按照前面的原則出牌即可。

a) 在出牌時,如果偏家有一個人只剩一張牌時,儘量不出單牌,否則單牌由大到小出。

b) 在跟牌時,如果偏家有一個人只剩一張牌時,跟手中最大的牌。

2 偏家打法:偏家因爲牽涉到配合問題,所以打法有一些不同。

a) 在出牌時,如果是莊家的上家,且莊家只剩一張牌時,儘量不出單牌,否則單牌由大到小出。

b) 在跟牌時,如果是莊家的上家,且莊家只剩一張牌時,跟手中最大的牌。

c) 當一個偏家打出的是單牌時,一般情況下能跟就跟。如果手中必須跟2或以上的牌時,選擇PASS。

d) 當一個偏家打出的是對子時,一般情況下能跟就跟。如果手中必須跟AA或以上的牌時,選擇PASS。

e) 如果一個偏家打出的牌是除了單牌及對子以外的牌型,則選擇PASS。

f) 如果處在下家的偏家只剩一張牌時,在出牌時出手中最小的牌。跟牌還按照一般的原則。

五 子棋算法探討(轉貼) 近來隨着計算機的快速發展,各種棋類遊戲被紛紛請進了電腦,使得那些喜愛下棋,又常常苦於沒有對手的棋迷們能隨時過足棋癮。而且這類軟件個個水平頗高,大 有與人腦分庭抗禮之勢。其中戰勝過國際象棋世界冠軍-卡斯帕羅夫的“深藍”便是最具說服力的代表;其它像圍棋的“手淡”、象棋的“將族”等也以其優秀的人 工智能深受棋迷喜愛;而我們今天將向大家介紹的是五子棋的算法。 當我們與電腦對戰時,您知道這些軟件是怎樣象人腦一樣進行思考的嗎? 總的來說(我們假定您熟悉五子棋的基本規則),要讓電腦知道該在哪一點下子,就要根據盤面的形勢,爲每一可能落子的點計算其重要程度,也就是當這子落下後 會形成什麼棋型(如:“衝四”、“活三”等),然後通覽全盤選出最重要的一點,這便是最基本的算法。當然,僅靠當前盤面進行判斷是遠遠不夠的,這樣下棋很 容易掉進玩家設下的陷阱,因爲它沒有考慮以後的變化。所以在此基礎上我們加入遞歸調用,即:在電腦中預測出今後幾步的各種走法,以便作出最佳選擇,這也是 我們下棋時常說的“想了幾步”。如此一來您的程序便具有一定的水平了。什麼?不信!過來試試吧! 總體思路弄清之後,下面進行具體討論:一:數據結構先來看看數據結構,我們需要哪些變量?首先得爲整個棋盤建立一張表格用以記錄棋子信息,我們使用一個 1515的二維數組 Table[15][15] (1515是五子棋棋盤的大小),數組的每一個元素對應棋盤上的一個交叉點,用‘0’表示空位、‘1’代表己方的子、‘2’代表對方的子;這張表也是今 後分析的基礎。在此之後還要爲電腦和玩家雙方各建立一張棋型表Computer[15][15][4]和Player[15][15][4],用來存放棋 型數據,就是剛纔所說的重要程度,比如用‘20’代表“衝四”的點,用‘15’代表“活三”的點,那麼在計算重要性時,就可以根據20>15得出前 者比後者重要,下子時電腦便會自動選擇“衝四”的點。那爲什麼棋型表要使用三維數組呢?因爲棋盤上的每一個點都可以與橫、豎、左斜、右斜四個方向的棋子構 成不同的棋型,所以一個點總共有4個記錄;這樣做的另一個好處是可以輕易判斷出複合棋型,例如:如果同一點上有2個‘15’就是雙三、有一個‘15’和一 個‘20’就是四三。怎麼樣!3個數組構成了程序的基本數據骨架,今後只要再加入一些輔助變量便可以應付自如了。應該不會太難吧?OK!有了這麼多有用的 數據,我們就可以深入到程序的流程中去了。 二:程序流程 我們主要討論五子棋的核心算法,即:人工智能部分,而其他像圖形顯示、鍵盤鼠標控制等,因較爲簡單,所以就不作過多介紹了。 首先,請仔細閱讀圖1: 我們看到本程序由六個基本功能模塊構成,各模塊的詳細分析如下:(1) 初始化:首先,建立盤面數組Table[15][15]、對戰雙方的棋型表Computer[15][15][4]和Player[15][15][4] 並將它們清零以備使用;然後初始化顯示器、鍵盤、鼠等輸入輸出設備並在屏幕上畫出棋盤。(2) 主循環控制模塊:控制下棋順序,當輪到某方下子時,負責將程序轉到相應的模塊中去,主要擔當一個調度者的角色。(3) 玩家下子:當輪到玩家下時,您通過鍵盤或鼠標在棋盤上落子,程序會根據該點的位置,在Table[15][15]數組的相應地方記錄‘2’,以表明該子是 玩家下的。(4) 盤面分析填寫棋型表:本程序核心模塊之一,人工智能算法的根本依據!其具體實現方法如下:您在下五子棋時,一定會先根據棋盤上的情況,找出當前最重要的一 些點位,如“活三”、“衝四”等;然後再在其中選擇落子點。但是,電腦不會像人一樣分析問題,要讓它知道哪是“活三”、哪是“衝四”,就得在棋盤上逐點計 算,一步一步的教它。 先來分析己方的棋型,我們從棋盤左上角出發,向右逐行搜索,當遇到一個空白點時,以它爲中心向左挨個查找,如果遇到己方的子則記錄然後繼續,如果遇到對方 的子、空白點或邊界就停止查找。左邊完成後再向右進行同樣的操作;最後把左右兩邊的記錄合併起來,得到的數據就是該點橫向上的棋型,然後把棋型的編號填入 到Computer[x][y][n]中就行了(x、y代表座標,n=0、1、2、3分別代表橫、豎、左斜、右斜四個方向)。而其他三個方向的棋型也可用 同樣的方法得到,當搜索完整張棋盤後,己方棋型表也就填寫完畢了。然後再用同樣的方法填寫對方棋型表。 注意:所有棋型的編號都要事先定義好,越重要的號數越大! OK! 怎麼樣?有點累了吧?不過千萬別泄氣!因爲好戲還在後頭。 Let’s go!(5) 電腦下子:有了上面填寫的兩張棋型表,現在要作的就是讓電腦知道在哪一點下子了。其中最簡單的計算方法,就是遍歷棋型表Computer[15][15] [4]和Player[15][15][4]找出其中數值最大的一點,在該點下子即可。但這種算法的弱點非常明顯,只顧眼前利益,不能顧全大局,這就和許 多五子棋初學者一樣犯了“目光短淺”的毛病。 要解決這個問題,我們引入‘今後幾步預測法’,具體方法是這樣的: 首先, 讓電腦分析一個可能的點,如果在這兒下子將會形成對手不得不防守的棋型(例如:‘衝四’、‘活三’);那麼下一步對手就會照您的思路下子來防守您,如此一 來便完成了第一步的預測。這時再調用模塊4對預測後的棋進行盤面分析,如果出現了‘四三’、‘雙三’或‘雙四’等制勝點,那麼己方就可以獲勝了(當然對黑 棋而言‘雙三’、‘雙四’是禁手,另當別論);否則照同樣的方法向下分析,就可預測出第二步、第三步…… 等一等,要是盤面上沒有對手必須防的棋型,哪該怎麼辦呢?進攻不成的話就得考慮防守了,將自己和對手調換一下位置,然後用上面的方法來預測對手的棋,這樣 既可以防住對手巧妙的攻擊,又能侍機發動反擊,何樂而不爲呢! 但是必須告訴大家的是:預測法的運算量相當之大,據我的經驗,用Pentium-100預測3步的走法平均需要15秒以上時間,所以建議預測量在5步以 內。可別小瞧了這5步,有時它甚至會走出讓您拍手叫絕的妙着呢!(6) 勝負判斷:務須多言,某方形成五子連即獲勝;若黑棋走出‘雙三’、‘雙四’或長連即以禁手判負。 到現在爲止,整個五子棋軟件就基本完成了,其水平大約在中級上下。當然,這種算法並不是最好的,但我相信它的基本思路是正確的。
鏈接:http://www.360doc.com/content/11/0108/09/2617151_84917660.shtml

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章