五子棋AI的思路


隔了一年才把AI思路給寫了。。。

需求分析與設計方案:http://www.cnblogs.com/songdechiu/p/4951634.html

如需整個工程,移步http://download.csdn.net/detail/sdzuiaidanpianji/9452789

如沒有積分,可在百度網盤下載:

鏈接: https://pan.baidu.com/s/1UXzhEDWXfsb6EbFOzRVuqg 提取碼: ezm6

注:全文,都默認以黑方為己方。

一、五子棋基本棋型

參考資料:http://game.onegreen.net/wzq/HTML/142336.html

最常見的基本棋型大體有以下幾種:連五,活四,沖四,活三,眠三,活二,眠二

①連五:顧名思義,五顆同色棋子連在一起,不需要多講。
圖2-1  

②活四:有兩個連五點(即有兩個點可以形成五),圖中白點即為連五點。
稍微思考一下就能發現活四出現的時候,如果對方單純過來防守的話,是已經無法阻止自己連五了。
圖2-2  


③沖四:有一個連五點,如下面三圖,均為沖四棋型。圖中白點為連五點。
相對比活四來說,沖四的威脅性就小了很多,因為這個時候,對方只要跟着防守在那個唯一的連五點上,沖四就沒法形成連五。
圖2-3  圖2-4  圖2-5  


④活三:可以形成活四的三,如下圖,代表兩種最基本的活三棋型。圖中白點為活四點。
活三棋型是我們進攻中最常見的一種,因為活三之后,如果對方不以理會,將可以下一手將活三變成活四,而我們知道活四是已經無法單純防守住了。所以,當我們面對活三的時候,需要非常謹慎對待。在自己沒有更好的進攻手段的情況下,需要對其進行防守,以防止其形成可怕的活四棋型。
圖2-6  圖2-7 

其中圖2-7中間跳着一格的活三,也可以叫做跳活三

⑤眠三只能夠形成沖四的三,如下各圖,分別代表最基礎的六種眠三形狀。圖中白點代表沖四點。眠三的棋型與活三的棋型相比,危險系數下降不少,因為眠三棋型即使不去防守,下一手它也只能形成沖四,而對於單純的沖四棋型,我們知道,是可以防守住的。
圖2-8  圖2-9  圖2-10 

2-11 圖2-12 圖2-13 

如上所示,眠三的形狀是很豐富的。對於初學者,在下棋過程中,很容易忽略不常見的眠三形狀,例如圖2-13所示的眠三。

有新手學了活三眠三后,會提出疑問,說活三也可以形成沖四啊,那豈不是也可以叫眠三?
會提出這個問題,說明對眠三定義看得不夠仔細:眠三的的定義是,只能夠形成沖四的三。而活三可以形成眠三,但也能夠形成活四。

此外,在五子棋中,活四棋型比沖四棋型具有更大的優勢,所以,我們在既能夠形成活四又能夠形成沖四時,會選擇形成活四。

溫馨提示:學會判斷一個三到底是活三還是眠三是非常重要的。所以,需要好好體會。
后邊禁手判斷的時候也會有所應用。 

⑥活二:能夠形成活三的二,如下圖,是三種基本的活二棋型。圖中白點為活三點。
活二棋型看起來似乎很無害,因為他下一手棋才能形成活三,等形成活三,我們再防守也不遲。但其實活二棋型是非常重要的,尤其是在開局階段,我們形成較多的活二棋型的話,當我們將活二變成活三時,才能夠令自己的活三綿綿不絕微風里,讓對手防不勝防。
圖2-14  圖2-15  圖2-16 

⑦眠二:能夠形成眠三的二。圖中四個為最基本的眠二棋型,細心且喜歡思考的同學會根據眠三介紹中的圖2-13找到與下列四個基本眠二棋型都不一樣的眠二。圖中白點為眠三點。
圖2-17 圖2-18  
圖2-19  圖2-20 

二、打分機制

1、打分思路

(1)先對整個棋盤形勢進行打分,存在兩個矩陣(二維數組)上

(2)一個為我方的形勢分數,一個為敵方的形勢分數

(3)找出我方形勢分數的最大值mymaxscore及其對應的位置,找出敵方形勢的最大值hismaxscore及其對應的位置

(4)判斷是進攻還是防守:

如果mymaxscore>=hismaxscore,則進攻,下我方形勢最大值mymaxscore對應的位置;如果有多個mymaxscore相等,則下這幾個對應位置上hismaxscore最大的位置。

否則,防守,下敵方形勢最大值hismaxscore對應的位置。如果有多個hismaxscore相等,則下這幾個對應位置上mymaxscore最大的位置。

2、打分方法

(1)在棋盤空位置上添加要判斷放的棋子

(2)取出以空位置為中心的4個方向(上,下,左,右),每個方向以該位置為中心兩邊各取4個格子信息。如下所示:

注:中心位置都是預放置,當前判斷的時候位置還是空的

(3)四個方向都判斷其棋型,是否連五,活四,沖四,活三,眠三,活二,眠二等中的一種

(4)最后綜合四個方向的棋型,對該位置進行打分。

3、打分規定

注:機器方即為本方,人方即為敵方

綜合四個方向后:

判斷是否能5, 如果是機器方的話給予100000分,如果是人方的話給予100000 分;

判斷是否能成4或者是雙死4或者是43,如果是機器方的話給予10000分,如果是人方的話給予10000分;

判斷是否已成雙活3,如果是機器方的話給予5000分,如果是人方的話給予5000 分;

判斷是否成33(高級),如果是機器方的話給予1000分,如果是人方的話給予1000 分;

判斷是否能成4,如果是機器方的話給予500分,如果是人方的話給予500分;

判斷是否能成低級死4,如果是機器方的話給予400分,如果是人方的話給予400分;

判斷是否能成單活3,如果是機器方的話給予100分,如果是人方的話給予100分;

判斷是否能成跳活3,如果是機器方的話給予90分,如果是人方的話給予90分;

判斷是否能成雙活2,如果是機器方的話給予50分,如果是人方的話給予50分;

判斷是否能成2,如果是機器方的話給予10分,如果是人方的話給予10分;

判斷是否能成低級活2,如果是機器方的話給予9分,如果是人方的話給予9分;

判斷是否能成3,如果是機器方的話給予5分,如果是人方的話給予5分;

判斷是否能成2,如果是機器方的話給予2分,如果是人方的話給予2分。

判斷是否其他情況(nothing),如果是機器方的話給予1分,如果是人方的話給予1分。

有棋子,則直接0分。

4、棋型判斷方法

(1)在空位置上添加要判斷色的棋子

(2)取出以空位置為中心的,要判斷單個方向(上,下,左,右中的一種)上的,兩邊各4個位置信息,形成

(3)先找出與中心點相連而成的連續子有多少個

(4)再進行下一步判斷

注:以下說明都以黑方為例子

  •  中心點相連而成的連續子有5個:不管哪種情況,都可以直接判斷為成5

  • 中心點相連而成的連續子有4個

    • 兩邊均空,活4

  • 1、2均非空,則nothing

  • 1、2只有一個為空,則死4

  • 中心點相連而成的連續子有3個:

 

  • 2,3均空時:
    • 1,4均為白子,則為死3

  • 1,4只要有一個空,則為活3

  • 1,4只要有一個黑,則為死4 

 

以此類推,根據第一部分中的五子棋棋型去判斷棋型類型。

具體可直接查看源碼部分。

 單個方向的棋型判斷:

if (count >= 5)//中心線5連
        return WIN5;//5連珠

    if (count == 4)//中心線4連
    {
        if (colorleft == NOTHINGFLAG && colorright == NOTHINGFLAG)//兩邊斷開位置均空
            return ALIVE4;//活四
        else if (colorleft == hiscolor && colorright == hiscolor)//兩邊斷開位置均非空
            return NOTHREAT;//沒有威脅
        else if (colorleft == NOTHINGFLAG || colorright == NOTHINGFLAG)//兩邊斷開位置只有一個空
            return DIE4;//死四
    }

    if (count == 3) {//中心線3連
        int colorleft1 = chess[left - 1];
        int colorright1 = chess[right + 1];

        if (colorleft == NOTHINGFLAG && colorright == NOTHINGFLAG)//兩邊斷開位置均空
        {

            if (colorleft1 == hiscolor && colorright1 == hiscolor)//均為對手棋子
                return DIE3;
            else if (colorleft1 == mycolor || colorright1 == mycolor)//只要一個為自己的棋子
                return LOWDIE4;
            else if (colorleft1 == NOTHINGFLAG || colorright1 == NOTHINGFLAG)//只要有一個空
                return ALIVE3;

        }
        else if (colorleft == hiscolor && colorright == hiscolor)//兩邊斷開位置均非空
        {
            return NOTHREAT;//沒有威脅
        }
        else if (colorleft == NOTHINGFLAG || colorright == NOTHINGFLAG)//兩邊斷開位置只有一個空
        {

            if (colorleft == hiscolor) {//左邊被對方堵住
                if (colorright1 == hiscolor)//右邊也被對方堵住
                    return NOTHREAT;
                if (colorright1 == NOTHINGFLAG)//右邊均空
                    return DIE3;
                if (colorright1 == mycolor)
                    return LOWDIE4;

            }
            if (colorright == hiscolor) {//右邊被對方堵住
                if (colorleft1 == hiscolor)//左邊也被對方堵住
                    return NOTHREAT;
                if (colorleft1 == NOTHINGFLAG)//左邊均空
                    return DIE3;
                if (colorleft1 == mycolor)//左邊還有自己的棋子
                    return LOWDIE4;
            }
        }
    }

    if (count == 2) {//中心線2連
        int colorleft1 = chess[left - 1];
        int colorright1 = chess[right + 1];
        int colorleft2 = chess[left - 2];
        int colorright2 = chess[right + 2];

        if (colorleft == NOTHINGFLAG && colorright == NOTHINGFLAG)//兩邊斷開位置均空
        {
            if ((colorright1 == NOTHINGFLAG && colorright2 == mycolor) ||
                (colorleft1 == NOTHINGFLAG && colorleft2 == mycolor))
                return DIE3;//死3
            else if (colorleft1 == NOTHINGFLAG && colorright1 == NOTHINGFLAG)
                return ALIVE2;//活2

            if ((colorright1 == mycolor && colorright2 == hiscolor) ||
                (colorleft1 == mycolor && colorleft2 == hiscolor))
                return DIE3;//死3
             
            if ((colorright1 == mycolor && colorright2 == mycolor) ||
                (colorleft1 == mycolor && colorleft2 == mycolor))
                return LOWDIE4;//死4

            if ((colorright1 == mycolor && colorright2 == NOTHINGFLAG) ||
                (colorleft1 == mycolor && colorleft2 == NOTHINGFLAG))
                return TIAO3;//跳活3
            //其他情況在下邊返回NOTHREAT
        }
        else if (colorleft == hiscolor && colorright == hiscolor)//兩邊斷開位置均非空
        {
            return NOTHREAT;
        }
        else if (colorleft == NOTHINGFLAG || colorright == NOTHINGFLAG)//兩邊斷開位置只有一個空
        {
            if (colorleft == hiscolor) {//左邊被對方堵住
                if (colorright1 == hiscolor || colorright2 == hiscolor) {//只要有對方的一個棋子
                    return NOTHREAT;//沒有威脅
                }
                else if (colorright1 == NOTHINGFLAG && colorright2 == NOTHINGFLAG) {//均空
                    return DIE2;//死2
                }
                else if (colorright1 == mycolor && colorright2 == mycolor) {//均為自己的棋子
                    return LOWDIE4;//死4
                }
                else if (colorright1 == mycolor || colorright2 == mycolor) {//只有一個自己的棋子
                    return DIE3;//死3
                }
            }
            if (colorright == hiscolor) {//右邊被對方堵住
                if (colorleft1 == hiscolor || colorleft2 == hiscolor) {//只要有對方的一個棋子
                    return NOTHREAT;//沒有威脅
                }
                else if (colorleft1 == NOTHINGFLAG && colorleft2 == NOTHINGFLAG) {//均空
                    return DIE2;//死2
                }
                else if (colorleft1 == mycolor && colorleft2 == mycolor) {//均為自己的棋子
                    return LOWDIE4;//死4
                }
                else if (colorleft1 == mycolor || colorleft2 == mycolor) {//只有一個自己的棋子
                    return DIE3;//死3
                }
            }
        }
    }
        
    if (count == 1) {//中心線1連
        int colorleft1 = chess[left - 1];
        int colorright1 = chess[right + 1];
        int colorleft2 = chess[left - 2];
        int colorright2 = chess[right + 2];
        int colorleft3 = chess[left - 3];
        int colorright3 = chess[right + 3];

        if (colorleft == NOTHINGFLAG && colorleft1 == mycolor && 
            colorleft2 == mycolor && colorleft3 == mycolor)
            return LOWDIE4;
        if (colorright == NOTHINGFLAG && colorright1 == mycolor && 
            colorright2 == mycolor && colorright3 == mycolor)
            return LOWDIE4;

        if (colorleft == NOTHINGFLAG && colorleft1 == mycolor && 
            colorleft2 == mycolor && colorleft3 == NOTHINGFLAG && colorright == NOTHINGFLAG)
            return TIAO3;
        if (colorright == NOTHINGFLAG && colorright1 == mycolor &&
            colorright2 == mycolor && colorright3 == NOTHINGFLAG && colorleft == NOTHINGFLAG)
            return TIAO3;

        if (colorleft == NOTHINGFLAG && colorleft1 == mycolor &&
            colorleft2 == mycolor && colorleft3 == hiscolor && colorright == NOTHINGFLAG)
            return DIE3;
        if (colorright == NOTHINGFLAG && colorright1 == mycolor &&
            colorright2 == mycolor && colorright3 == hiscolor && colorleft == NOTHINGFLAG)
            return DIE3;

        if (colorleft == NOTHINGFLAG && colorleft1 == NOTHINGFLAG &&
            colorleft2 == mycolor && colorleft3 == mycolor)
            return DIE3;
        if (colorright == NOTHINGFLAG && colorright1 == NOTHINGFLAG &&
            colorright2 == mycolor && colorright3 == mycolor)
            return DIE3;

        if (colorleft == NOTHINGFLAG && colorleft1 == mycolor &&
            colorleft2 == NOTHINGFLAG && colorleft3 == mycolor)
            return DIE3;
        if (colorright == NOTHINGFLAG && colorright1 == mycolor &&
            colorright2 == NOTHINGFLAG && colorright3 == mycolor)
            return DIE3;

        if (colorleft == NOTHINGFLAG && colorleft1 == mycolor &&
            colorleft2 == NOTHINGFLAG && colorleft3 == NOTHINGFLAG && colorright == NOTHINGFLAG)
            return LOWALIVE2;
        if (colorright == NOTHINGFLAG && colorright1 == mycolor &&
            colorright2 == NOTHINGFLAG && colorright3 == NOTHINGFLAG && colorleft == NOTHINGFLAG)
            return LOWALIVE2;

        if (colorleft == NOTHINGFLAG && colorleft1 == NOTHINGFLAG &&
            colorleft2 == mycolor && colorleft3 == NOTHINGFLAG && colorright == NOTHINGFLAG)
            return LOWALIVE2;
        if (colorright == NOTHINGFLAG && colorright1 == NOTHINGFLAG &&
            colorright2 == mycolor && colorright3 == NOTHINGFLAG && colorleft == NOTHINGFLAG)
            return LOWALIVE2;

        //其余在下邊返回沒有威脅

    }
    return NOTHREAT;//返回沒有威脅

 

綜合四個方向評分:

if (situation.win5 >= 1)
        return LevelOne;//贏5

    if (situation.alive4 >= 1 || die4 >= 2 || (die4 >= 1 && alive3 >= 1))
        return Leveltwo;//活4 雙死4 死4活3

    if (alive3 >= 2)
        return Levelthree;//雙活3

    if (situation.die3 >= 1 && situation.alive3 >= 1)
        return Levelfour;//死3高級活3

    if (situation.die4 >= 1)
        return Levelfive;//高級死4

    if (situation.lowdie4 >= 1)
        return Levelsix;//低級死4

    if (situation.alive3 >= 1)
        return Levelseven;//單活3

    if (situation.tiao3 >= 1)
        return LevelEight;//跳活3

    if (alive2 >= 2)
        return LevelNight;//雙活2

    if (situation.alive2 >= 1)
        return LevelTen;//活2

    if (situation.lowalive2 >= 1)
        return LevelEleven;//低級活2

    if (situation.die3 >= 1)
        return LevelTwelve;//死3

    if (situation.die2 >= 1)
        return LevelThirteen;//死2

    return LevelFourteen;//沒有威脅

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM