zoukankan      html  css  js  c++  java
  • C++ 之 简单的五子棋AI程序

         本人是大一新生,寒假无聊,抱着试试看的心态(没有想到可以完成),写了C++的简单五子棋程序,开心。
         下面是效果图:

         一、首先讲讲大致思路
                五子棋实现的基础
                       二维数组是五子棋实现的基础。二维数组就像一个棋盘,其中0等于空格,1等于黑棋,2等于白棋,这里电脑就好比只能理解0和1的仆人,我们通过映射,使得五子棋变成计算机能够处理的0和1,进而计算机知道做我们要它做什么。
    举例:5个连成水平线的白棋  ———  00022222000;但是无论怎么样,我们不是电脑,必须看到真正棋才会下(除非你会下盲棋),所以我们需要一个函数,把二维数组中的数字信息转化为图像信息。我的代码如下:

    void gobang::display(){
        system("cls");
        for(int i = 0; i < 15; i ++){
            for(int j = 0; j < 15; j ++){
                if(i == Y && j == X){
                    cout << "";
                }
                else if(chessboard[i][j] == 1){
                    cout << "";
                }
                else if(chessboard[i][j] == 2){
                    cout << "";
                }
                else{
                    cout << ". ";
                }
                    
            }
            cout << endl;
        }
    }

    这个显示函数是很“自由”的,你完全可以选择更好的显示方法,甚至有颜色什么的(我还不会...)。                      
     
                    五子棋的类的大致浏览:               

                     数据:int chessboard[15][15]    //存储棋盘信息

                                 int Y, X                            //光标,用于玩家选择位置落子
                                 int player, computer        //记录玩家和电脑棋子的颜色
                                 point laozi                       //记录最新落子位置,便于判断是否连成五子(point 是 创建的一个结构体:struct point{int y, x})
                      最主要函数:void play()                        //最主要的函数,下面是该函数调用的函数
                      次要函数:
                                int selMode()                    //选择模式
                                void turnPlayer()              //玩家操作
                                void turnComputer()        //电脑操作
                                bool isEnd()                     //判断是否连成五子
                      其他函数
                      具体代码如下:

    class gobang{
    private:
        int chessboard[15][15];          //记录棋盘信息 
        int player;                      //玩家棋子 
        int computer;                    //电脑棋子 
        int Y, X;                        //光标位置 
        point laozi;                     //落子位置 
    public:
        void play();
            int selMode();
            void turnPlayer();
            void turnComputer(); 
            bool isEnd();
    protected:
        bool isInBoard(point p); 
        void display();
        int score(point p, int who);
        point newPoint(point p, dir d, int lenth);
    };


               五子棋的步骤(play函数):选择模式(选择电脑先手/玩家先手+数据初始化),循环(玩家/电脑操作 + 判断是否结束,如果是,说明胜利棋方跳出循环,如果不是,交换棋方)
               下面是所需要的代码(除了电脑操作部分,比其他复杂一些,最后说)。
                play函数

    void gobang::play(){
        int i = selMode();
        if(i == 1){
            computer = 1;
            player = 2;
        }
        else{
            player = 1;
            computer = 2;
        }
        int cur = 1;
        while(1){
            if(cur == player){
                turnPlayer();
            }
            else{
                turnComputer();
            }
            if(isEnd()){
                if(cur == player){
                    cout << "Player Win !";
                    system("pause");
                    break;
                }    
                else{
                    cout << "Computer Win !";
                    system("pause");
                       break; 
                }
            }
            else{
                cur = (cur == 1) ? 2 : 1;
            }        
        }
    } 

               选择模式:这个函数包含两个部分,选择 和 数据初始化

    int gobang::selMode(){
        system("cls");
        cout << "*************************************************" << endl;
        cout << "******************0、退出************************" << endl;
        cout << "******************1、电脑先手********************" << endl;
        cout << "******************2、玩家先手********************" << endl;
        cout << "*************************************************" << endl;
        while(1){
            int i;
            cin >> i;
            if(i == 0){
                exit(1);
            }
            else if(i == 1 || i == 2){
                Y = 9;
                X = 9;
                for(int j = 0; j < 15; j ++){
                    for(int k = 0; k < 15; k ++){
                        chessboard[j][k] = 0;
                    }
                }
                display();
                return i;
            }
            else{
                cout << "非法输入,请重新输入!" << endl;
            }
        }
    }

                        玩家操作:玩家操作我采用光标Y,X可视化(display()) 和 键盘操作的方法(w:上 ,s : 下 , a : 左, d : 右, j : 确定落子)。其中操作函数中都会有laozi这个数据,是方便后面的判断是否结束的

    void gobang::turnPlayer(){
        cout << "turn player" << endl;    
        while(1){
            char c = getch();
            if(c == 'w'){
                if(Y != 0){
                    Y --;
                    display();
                }
            }
            else if(c == 's'){
                if(Y != 14){
                    Y ++;
                    display();
                }
                
            }
            else if(c == 'a'){
                if(X != 0){
                    X --;
                    display();
                }
            }
            else if(c == 'd'){
                if(X != 14){
                    X ++;
                    display();
                }
            }
            else if(c == 'j' && chessboard[Y][X] == 0){
                laozi.y = Y;
                laozi.x = X;
                chessboard[Y][X] = player;
                display();
                break;
            }
        } 
    }

                         判断是否结束:

    bool gobang::isEnd(){
        for(int i = 1; i <= 4; i ++){
            dir d;
            int count = 0;
            switch(i){
                case 1:
                    d = d1;
                    break;
                case 2:
                    d = d2;
                    break;
                case 3:
                    d = d3;
                    break;
                case 4:
                    d = d4;
                    break;
            }
            for(int j = -4; j <= 4; j ++){
                point p1 = newPoint(laozi, d, j);
                if(isInBoard(p1) && chessboard[p1.y][p1.x] == chessboard[laozi.y][laozi.x]){
                    count ++;
                }
                else{
                    count = 0;
                }
                if(count == 5){
                    return true;
                }
            }
        }
        return false;
    }

    在这个函数里出现了一个新的函数——newpoint(point p, dir d, int lenth),其中point p 为 点的位置, int lenth 为长度, dir d 为单位向量
    dir d 讲解 :dir 是创建的一个结构体,用来表示单位向量。它有很大的作用,通过它可以把横竖撇捺4个方向用一个简单的dir d 的 方向变量来处理,大大减少了代码量。代码如下:

    struct dir{
        int dy;
        int dx;
    };
    
    const dir d1 = {0, 1};               //
    const dir d2 = {1, 0};               //
    const dir d3 = {1, -1};              //
    const dir d4 = {1, 1};               //
    
    point gobang::newPoint (point p, dir d, int lenth){
        point p1 = {p.y + d.dy * lenth, p.x + d.dx * lenth};
        return p1;
    }

          二、核心部分(电脑操作)讲解
                 电脑的下棋就是要找出最佳点。什么是最佳点,最佳点的判断指标是什么?这就需要给每个点打分。
                 打分的具体方法
                       1.在棋盘空位置上预先添加要判断的棋子;
                       2.选择横竖撇捺中的一个方向(利用dir d);
                       3.找出与中心点相连的棋子数量,并且利用left[5],right[5]数组存储连子左右两边各4个棋子的颜色情况(可能会遇到边界问题,解决办法:通过 isInBoard(point p) 函数判断棋子是否出边界,如果出边界,则棋子颜色视为反方(opp)棋子存储在数组中,如果没有出边界,则棋子按本来情况存储在数组中。
                       4.利用连子数量以及连子左右两边各4个棋子的颜色情况来判断棋型,是否为连五,活四(高级/低级),冲死,活三(高级或低级),眠三(高级或低级),活二,低级活二,眠二中的一种。
                       5.综合四个方向,进行打分:

    情况15给予14分;
    情况2能成4或者是双死4或者是43给予13

    情况3:能双活3给予12

    情况4:能33(高级)给予11

    情况5能成4给予10

    情况6能成低级死4给予9

    情况7能成单活3给予8

    情况8能成跳活3给予7

    情况9能成双活2给予6

    情况10能成2给予5

    情况11能成低级活2给予4

    情况12能成3给予3

    情况13能成2给予2分;

    情况14其他情况(nothing给予1分。


                 五子棋棋型知识(如果不知道可以看这里):

    最常见的基本棋型大体有以下几种:连五,活四,冲四,活三,眠三,活二,眠二

    ①连五:顾名思义,五颗同色棋子连在一起,不需要多讲。
    图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 

    这个部分是网上摘抄,网址:http://game.onegreen.net/wzq/HTML/142336.html   
          既然我们有了给每个点打分的方法,就该寻找最佳点了,但是这还不够,因为我们知道,下棋一般有两个思考方向,进攻或者防守(如果在给某点打分时放入的棋子为电脑棋子,则为进攻,反之,则为防守)。为什么要把进攻和防守分开考虑呢?为什么不可以把进攻得分和防守得分相加起来呢?我也试过,首先要把每种棋型的得分进行更改,即使这样也往往得不到一个好的结果。我可以通过一个比喻说明这个问题:某个学校举办学科竞赛,有语文和数学两个科目,但是每个班可以选择一名同学参加其中一项比赛,为此,老师对每个同学进行语文和数学测试,测试后,老师有2个方法寻找最佳的学生:1.语文和数学成绩一起考虑(比如相加)来寻找最佳学生;2.分别找出语文和数学成绩最好的两名同学,在比较选择。你们认为那种方法选出的学生比赛取得好成绩的概率更高呢?

                 通过这个比喻,我们寻找最佳点的方法也就出来,分别求出最佳进攻点,如果有多个最佳进攻点,则选择其中防守得分最高的,对于最佳防守点也如此。然后进一步比较,如果最佳进攻点得发大于等于最佳防守点,则以最佳进攻点为最佳点,反之,最佳防守点为最佳点。
    具体代码如下:
    void turnComputer()

    void gobang::turnComputer(){
        cout << "turn computer" << endl; 
        point best1, best2;
        do{
            srand(time(NULL));
            best1.y = best2.y = rand()%15;
            best1.x = best2.x = rand()%15;
        } 
        while(chessboard[best1.y][best1.x] != 0);
        int a1 = score(best1, computer), b1 = score(best1, player);
        for(int i = 0; i < 15; i ++){
            for(int j = 0; j < 15; j ++){
                if(chessboard[i][j] != 0){
                    continue;
                }
                point cur = {i, j};
                int m1 = score(cur, computer);
                int m2 = score(cur, player);
                if(m1 > a1){
                    best1 = cur;
                    a1 = m1;
                    b1 = m2; 
                }
                else if(m1 == a1){
                    if(m2 > b1){ 
                        best1 = cur;
                        b1 = m2;
                    }
                }
            }
        }
        int a2 = score(best2, player), b2 = score(best2, computer);
        for(int i = 0; i < 15; i ++){
            for(int j = 0; j < 15; j ++){
                if(chessboard[i][j] != 0){
                    continue;
                }
                point cur = {i, j};
                int m1 = score(cur, player);
                int m2 = score(cur, computer);
                if(m1 > a2){
                    best2 = cur;
                    a2 = m1;
                    b2 = m2;
                }
                else if(m1 == a2){
                    if(m2 > b2){
                        best2 = cur;
                        b2 = m2;
                    }
                }
            }
        }    
        if(a1 >= a2){
            laozi = best1;
        }
        else{
            laozi = best2;
        }
        chessboard[laozi.y][laozi.x] = computer;
        display();
    }

    void score(point p, int who)

    int gobang::score(point p, int who){
        int win5 = 0, alive4 = 0, die4 = 0, ddie4 = 0, alive3 = 0, 
        dalive3 = 0, die3 = 0, alive2 = 0, dalive2 = 0, die2 = 0, nothing = 0;
        int opp;
        if(who == 1){
            opp = 2;
        }
        else{
            opp = 1;
        }
        for(int i = 1; i <= 4; i ++){
            dir d;
            switch(i){
                case 1:
                    d = d1;
                    break;
                case 2:
                    d = d2;
                    break;
                case 3:
                    d = d3;
                    break;
                case 4:
                    d = d4;
                    break;
           }
           int l = 1;
           point le, ri, p1;
           int left[5], right[5];
           p1 = newPoint(p, d, -1);
           le = p;
           while(isInBoard(p1) && chessboard[p1.y][p1.x] == who){
                   le = p1;
                   p1 = newPoint(p1, d, -1);
                l ++;
           }
           p1 = newPoint(p, d, 1);
           ri = p;
           while(isInBoard(p1) && chessboard[p1.y][p1.x] == who){
                ri = p1;
                p1 = newPoint(p1, d, 1);
                l ++;
           }
           for(int j = 1; j <= 4; j ++){
                   p1 = newPoint(le, d, -j);
                   if(isInBoard(p1)){
                       left[j] = chessboard[p1.y][p1.x];
                }
                else{
                    left[j] = opp;
                }
                   p1 = newPoint(ri, d, j);
                   if(isInBoard(p1)){
                       right[j] = chessboard[p1.y][p1.x];
                }
                else{
                    right[j] = opp;
                }
           }
           //具体棋型判断
           if(l == 5){
               win5 ++;
           }
           else if(l == 4){
                  if(left[1] == 0 && right[1] == 0){//alive4 
                          alive4 ++;
               }
               else if(left[1] == 0 || right[1] == 0){//die4
                       die4 ++;
               }
               else{//nothing
                       nothing ++;
               }
           }
           else if(l == 3){
                  if((left[1] == 0 && left[2] == who) || (right[1] == 0 && right[2] == who)){//ddie4
                          ddie4 ++;
               }
               else if(left[1] == 0 && right[1] == 0 && (left[2] == 0 || right[2] == 0)){//alive3
                       alive3 ++;                             
               }
               else if((left[1] == 0 && left[2] == 0) || (right[1] == 0 && right[2] == 0)){//die3
                       die3 ++;
               }
               else if(left[1] == 0 && right[1] == 0){//die3
                       die3 ++; 
               } 
               else{//nothing
                       nothing ++;
               }
           }
           else if(l == 2){
                  if((left[1] == 0 && left[2] == who && left[3] == who) && 
                     (right[1] == 0 && right[2] == who && right[3] == who)){//die4
                       ddie4 ++;
               }
               else if(left[1] == 0 && right[1] == 0 && 
                       ((left[2] == who && left[3] == 0) || (right[2] == who && right[3] == 0))){//dalive3
                       dalive3 ++;
               }
               else if((left[1] == 0 && left[3] == 0 && left[2] == who) || 
                       (right[1] == 0 && right[3] == 0 && right[2] == who)){//die3
                    die3 ++;
               }
               else if((left[1] == 0 && right[1] == 0) && 
                       (left[2] == who || right[2] == who)){//die3
                       die3 ++;
               }
               else if((left[1] == 0 && left[2] == 0 && left[3] == who) || 
                       (right[1] == 0 && right[2] == 0 && right[3] == who)){//die3
                    die3 ++;
               }
               else if((left[1] == 0 && right[1] == 0 && right[2] == 0 && right[3] == 0) || 
                       (left[1] == 0 && left[2] == 0 && right[1] == 0 && right[2] == 0) || 
                       (left[1] == 0 && left[2] == 0 && left[3] == 0 && right[1] == 0)){//alive2
                       alive2 ++;
               }
               else if((left[1] == 0 && left[2] == 0 && left[3] == 0) || 
                       (right[1] == 0 && right[2] == 0 && right[3] == 0)){//die2
                       die2 ++;
               }
               else{//nothing
                       nothing ++;
               }
           }
           else if(l == 1){
                  if((left[1] == 0 && left[2] == who && left[3] == who && left[4] == who) || 
                     (right[1] == 0 && right[2] == who && right[3] == who && right[4] == who)){//ddie4
                       ddie4 ++;
               }
               else if((left[1] == 0 && right[1] == 0) && ((left[2] == who && left[3] == who && left[4] == 0) || 
                       (right[2] == who && right[3] == who && right[4] == 0))){//dalive3
                       dalive3 ++;
               }
               else if((left[1] == 0 && right[1] == 0) && 
                       ((left[2] == who && left[3] == who) || (right[2] == who && right[3] == who))){//die3
                       die3 ++;
               }
               else if((left[1] == 0 && left[4] == 0 && left[2] == who && left[3] == who) || 
                       (right[1] == 0 && right[4] == 0 && right[2] == who && right[3] == who)){//die3
                       die3 ++;
               }
               else if((left[1] == 0 && left[2] == 0 && left[3] == who && left[4] == who) || 
                       (right[1] == 0 && right[2] == 0 && right[3] == who && right[4] == who)){//die3
                       die3 ++;
               } 
               else if((left[1] == 0 && left[3] == 0 && left[2] == who && left[4] == who) || 
                       (right[1] == 0 && right[3] == 0 && right[2] == who && right[4] == who)){//die3
                       die3 ++;
               }
               else if((left[1] == 0 && right[1] == 0 && right[3] == 0 && right[2] == who) && (left[2] == 0 || right[4] == 0)){//dalive2
                       dalive2 ++;
               }
               else if((right[1] == 0 && left[1] == 0 && left[3] == 0 && left[2] == who) && 
                       (right[2] == 0 || left[4] == 0)){//dalive2
                       dalive2 ++;
               }
               else if((left[1] == 0 && right[1] == 0 && right[2] == 0 && right[4] == 0 && right[3] == who) || 
                       (right[1] == 0 && left[1] == 0 && left[2] == 0 && left[4] == 0 && left[3] == who)){//dalive2
                       dalive2 ++;
               }
               else if((left[1] == 0 && left[3] == 0 && left[4] == 0 && left[2] == who) || 
                       (right[1] == 0 && right[3] == 0 && right[4] == 0 && right[2] == who)){//die2
                       die2 ++;
               }
               else if((left[1] == 0 && right[1] == 0 && right[2] == 0 && left[2] == who) || 
                       (right[1] == 0 && left[1] == 0 && left[2] == 0 && right[2] == who)){//die2
                       die2 ++;
               }
               else if((left[1] == 0 && left[2] == 0 && left[4] == 0 && left[3] == who) || 
                       (right[1] == 0 && right[2] == 0 && right[4] == 0 && right[3] == who)){//die2
                       die2 ++;
               }
               else if((left[1] == 0 && left[2] == 0 && right[1] == 0 && left[3] == who) || 
                       (right[1] == 0 && right[2] == 0 && left[1] == 0 && right[3] == who)){//die2
                       die2 ++;
               }
               else if((left[1] == 0 && left[2] == 0 && left[3] == 0 && left[4] == who) || 
                       (right[1] == 0 && right[2] == 0 && right[3] == 0 && right[4] == who)){//die2
                       die2 ++;
               }
               else{//nothing
                       nothing ++;
               }
           }
        }
        if (win5 >= 1)
            return 14;//赢5
    
        if (alive4 >= 1 || die4 >= 2 || (die4 >= 1 && alive3 >= 1))
            return 13;//活4 双死4 死4活3
    
        if (alive3 >= 2)
            return 12;//双活3
    
        if (die3 >= 1 && alive3 >= 1)
            return 11;//死3高级活3
    
        if (die4 >= 1)
            return 10;//高级死4
    
        if (ddie4 >= 1)
            return 9;//低级死4
    
        if (alive3 >= 1)
            return 8;//单活3
    
        if (dalive3 >= 1)
            return 7;//跳活3
    
        if (alive2 >= 2)
            return 6;//双活2
    
        if (alive2 >= 1)
            return 5;//活2
    
        if (dalive2 >= 1)
            return 4;//低级活2
    
        if (die3 >= 1)
            return 3;//死3
    
        if (die2 >= 1)
            return 2;//死2
    
        return 1;//没有威胁
    }

     

            

           三、完整代码

    #include <iostream>
    #include <conio.h>
    #include <ctime>
    #include <cstdlib>
    using namespace std;
     
    struct point{
        int y;
        int x;
    }; 
    struct dir{
        int dy;
        int dx;
    };
    const dir d1 = {0, 1};//
    const dir d2 = {1, 0};//
    const dir d3 = {1, -1};//
    const dir d4 = {1, 1};//
    
    class gobang{
    private:
        int chessboard[15][15];//记录棋盘信息 
        int player;//玩家棋子 
        int computer;//电脑棋子 
        int Y, X;//光标位置 
        point laozi;//落子位置 
    public:
        void play();
            int selMode();
            void turnPlayer();
            void turnComputer(); 
            bool isEnd();
    protected:
        bool isInBoard(point p); 
        void display();
        int score(point p, int who);
        point newPoint(point p, dir d, int lenth);
    };
    void gobang::play(){
        int i = selMode();
        if(i == 1){
            computer = 1;
            player = 2;
        }
        else{
            player = 1;
            computer = 2;
        }
        int cur = 1;
        while(1){
            if(cur == player){
                turnPlayer();
            }
            else{
                turnComputer();
            }
            if(isEnd()){
                if(cur == player){
                    cout << "Player Win !";
                    system("pause");
                    break;
                }    
                else{
                    cout << "Computer Win !";
                    system("pause");
                       break; 
                }
            }
            else{
                cur = (cur == 1) ? 2 : 1;
            }        
        }
    } 
    int gobang::selMode(){
        system("cls");
        cout << "*************************************************" << endl;
        cout << "******************0、退出************************" << endl;
        cout << "******************1、电脑先手********************" << endl;
        cout << "******************2、玩家先手********************" << endl;
        cout << "*************************************************" << endl;
        while(1){
            int i;
            cin >> i;
            if(i == 0){
                exit(1);
            }
            else if(i == 1 || i == 2){
                Y = 9;
                X = 9;
                for(int j = 0; j < 15; j ++){
                    for(int k = 0; k < 15; k ++){
                        chessboard[j][k] = 0;
                    }
                }
                display();
                return i;
            }
            else{
                cout << "非法输入,请重新输入!" << endl;
            }
        }
    }
    void gobang::turnPlayer(){
        cout << "turn player" << endl;    
        while(1){
            char c = getch();
            if(c == 'w'){
                if(Y != 0){
                    Y --;
                    display();
                }
            }
            else if(c == 's'){
                if(Y != 14){
                    Y ++;
                    display();
                }
                
            }
            else if(c == 'a'){
                if(X != 0){
                    X --;
                    display();
                }
            }
            else if(c == 'd'){
                if(X != 14){
                    X ++;
                    display();
                }
            }
            else if(c == 'j' && chessboard[Y][X] == 0){
                laozi.y = Y;
                laozi.x = X;
                chessboard[Y][X] = player;
                display();
                break;
            }
        } 
    }
    void gobang::turnComputer(){
        cout << "turn computer" << endl; 
        point best1, best2;
        do{
            srand(time(NULL));
            best1.y = best2.y = rand()%15;
            best1.x = best2.x = rand()%15;
        } 
        while(chessboard[best1.y][best1.x] != 0);
        int a1 = score(best1, computer), b1 = score(best1, player);
        for(int i = 0; i < 15; i ++){
            for(int j = 0; j < 15; j ++){
                if(chessboard[i][j] != 0){
                    continue;
                }
                point cur = {i, j};
                int m1 = score(cur, computer);
                int m2 = score(cur, player);
                if(m1 > a1){
                    best1 = cur;
                    a1 = m1;
                    b1 = m2; 
                }
                else if(m1 == a1){
                    if(m2 > b1){ 
                        best1 = cur;
                        b1 = m2;
                    }
                }
            }
        }
        int a2 = score(best2, player), b2 = score(best2, computer);
        for(int i = 0; i < 15; i ++){
            for(int j = 0; j < 15; j ++){
                if(chessboard[i][j] != 0){
                    continue;
                }
                point cur = {i, j};
                int m1 = score(cur, player);
                int m2 = score(cur, computer);
                if(m1 > a2){
                    best2 = cur;
                    a2 = m1;
                    b2 = m2;
                }
                else if(m1 == a2){
                    if(m2 > b2){
                        best2 = cur;
                        b2 = m2;
                    }
                }
            }
        }    
        if(a1 >= a2){
            laozi = best1;
        }
        else{
            laozi = best2;
        }
        chessboard[laozi.y][laozi.x] = computer;
        display();
    }
    int gobang::score(point p, int who){
        int win5 = 0, alive4 = 0, die4 = 0, ddie4 = 0, alive3 = 0, 
        dalive3 = 0, die3 = 0, alive2 = 0, dalive2 = 0, die2 = 0, nothing = 0;
        int opp;
        if(who == 1){
            opp = 2;
        }
        else{
            opp = 1;
        }
        for(int i = 1; i <= 4; i ++){
            dir d;
            switch(i){
                case 1:
                    d = d1;
                    break;
                case 2:
                    d = d2;
                    break;
                case 3:
                    d = d3;
                    break;
                case 4:
                    d = d4;
                    break;
           }
           int l = 1;
           point le, ri, p1;
           int left[5], right[5];
           p1 = newPoint(p, d, -1);
           le = p;
           while(isInBoard(p1) && chessboard[p1.y][p1.x] == who){
                   le = p1;
                   p1 = newPoint(p1, d, -1);
                l ++;
           }
           p1 = newPoint(p, d, 1);
           ri = p;
           while(isInBoard(p1) && chessboard[p1.y][p1.x] == who){
                ri = p1;
                p1 = newPoint(p1, d, 1);
                l ++;
           }
           for(int j = 1; j <= 4; j ++){
                   p1 = newPoint(le, d, -j);
                   if(isInBoard(p1)){
                       left[j] = chessboard[p1.y][p1.x];
                }
                else{
                    left[j] = opp;
                }
                   p1 = newPoint(ri, d, j);
                   if(isInBoard(p1)){
                       right[j] = chessboard[p1.y][p1.x];
                }
                else{
                    right[j] = opp;
                }
           }
           //具体棋型判断
           if(l == 5){
               win5 ++;
           }
           else if(l == 4){
                  if(left[1] == 0 && right[1] == 0){//alive4 
                          alive4 ++;
               }
               else if(left[1] == 0 || right[1] == 0){//die4
                       die4 ++;
               }
               else{//nothing
                       nothing ++;
               }
           }
           else if(l == 3){
                  if((left[1] == 0 && left[2] == who) || (right[1] == 0 && right[2] == who)){//ddie4
                          ddie4 ++;
               }
               else if(left[1] == 0 && right[1] == 0 && (left[2] == 0 || right[2] == 0)){//alive3
                       alive3 ++;                             
               }
               else if((left[1] == 0 && left[2] == 0) || (right[1] == 0 && right[2] == 0)){//die3
                       die3 ++;
               }
               else if(left[1] == 0 && right[1] == 0){//die3
                       die3 ++; 
               } 
               else{//nothing
                       nothing ++;
               }
           }
           else if(l == 2){
                  if((left[1] == 0 && left[2] == who && left[3] == who) && 
                     (right[1] == 0 && right[2] == who && right[3] == who)){//die4
                       ddie4 ++;
               }
               else if(left[1] == 0 && right[1] == 0 && 
                       ((left[2] == who && left[3] == 0) || (right[2] == who && right[3] == 0))){//dalive3
                       dalive3 ++;
               }
               else if((left[1] == 0 && left[3] == 0 && left[2] == who) || 
                       (right[1] == 0 && right[3] == 0 && right[2] == who)){//die3
                    die3 ++;
               }
               else if((left[1] == 0 && right[1] == 0) && 
                       (left[2] == who || right[2] == who)){//die3
                       die3 ++;
               }
               else if((left[1] == 0 && left[2] == 0 && left[3] == who) || 
                       (right[1] == 0 && right[2] == 0 && right[3] == who)){//die3
                    die3 ++;
               }
               else if((left[1] == 0 && right[1] == 0 && right[2] == 0 && right[3] == 0) || 
                       (left[1] == 0 && left[2] == 0 && right[1] == 0 && right[2] == 0) || 
                       (left[1] == 0 && left[2] == 0 && left[3] == 0 && right[1] == 0)){//alive2
                       alive2 ++;
               }
               else if((left[1] == 0 && left[2] == 0 && left[3] == 0) || 
                       (right[1] == 0 && right[2] == 0 && right[3] == 0)){//die2
                       die2 ++;
               }
               else{//nothing
                       nothing ++;
               }
           }
           else if(l == 1){
                  if((left[1] == 0 && left[2] == who && left[3] == who && left[4] == who) || 
                     (right[1] == 0 && right[2] == who && right[3] == who && right[4] == who)){//ddie4
                       ddie4 ++;
               }
               else if((left[1] == 0 && right[1] == 0) && ((left[2] == who && left[3] == who && left[4] == 0) || 
                       (right[2] == who && right[3] == who && right[4] == 0))){//dalive3
                       dalive3 ++;
               }
               else if((left[1] == 0 && right[1] == 0) && 
                       ((left[2] == who && left[3] == who) || (right[2] == who && right[3] == who))){//die3
                       die3 ++;
               }
               else if((left[1] == 0 && left[4] == 0 && left[2] == who && left[3] == who) || 
                       (right[1] == 0 && right[4] == 0 && right[2] == who && right[3] == who)){//die3
                       die3 ++;
               }
               else if((left[1] == 0 && left[2] == 0 && left[3] == who && left[4] == who) || 
                       (right[1] == 0 && right[2] == 0 && right[3] == who && right[4] == who)){//die3
                       die3 ++;
               } 
               else if((left[1] == 0 && left[3] == 0 && left[2] == who && left[4] == who) || 
                       (right[1] == 0 && right[3] == 0 && right[2] == who && right[4] == who)){//die3
                       die3 ++;
               }
               else if((left[1] == 0 && right[1] == 0 && right[3] == 0 && right[2] == who) && (left[2] == 0 || right[4] == 0)){//dalive2
                       dalive2 ++;
               }
               else if((right[1] == 0 && left[1] == 0 && left[3] == 0 && left[2] == who) && 
                       (right[2] == 0 || left[4] == 0)){//dalive2
                       dalive2 ++;
               }
               else if((left[1] == 0 && right[1] == 0 && right[2] == 0 && right[4] == 0 && right[3] == who) || 
                       (right[1] == 0 && left[1] == 0 && left[2] == 0 && left[4] == 0 && left[3] == who)){//dalive2
                       dalive2 ++;
               }
               else if((left[1] == 0 && left[3] == 0 && left[4] == 0 && left[2] == who) || 
                       (right[1] == 0 && right[3] == 0 && right[4] == 0 && right[2] == who)){//die2
                       die2 ++;
               }
               else if((left[1] == 0 && right[1] == 0 && right[2] == 0 && left[2] == who) || 
                       (right[1] == 0 && left[1] == 0 && left[2] == 0 && right[2] == who)){//die2
                       die2 ++;
               }
               else if((left[1] == 0 && left[2] == 0 && left[4] == 0 && left[3] == who) || 
                       (right[1] == 0 && right[2] == 0 && right[4] == 0 && right[3] == who)){//die2
                       die2 ++;
               }
               else if((left[1] == 0 && left[2] == 0 && right[1] == 0 && left[3] == who) || 
                       (right[1] == 0 && right[2] == 0 && left[1] == 0 && right[3] == who)){//die2
                       die2 ++;
               }
               else if((left[1] == 0 && left[2] == 0 && left[3] == 0 && left[4] == who) || 
                       (right[1] == 0 && right[2] == 0 && right[3] == 0 && right[4] == who)){//die2
                       die2 ++;
               }
               else{//nothing
                       nothing ++;
               }
           }
        }
        if (win5 >= 1)
            return 14;//赢5
    
        if (alive4 >= 1 || die4 >= 2 || (die4 >= 1 && alive3 >= 1))
            return 13;//活4 双死4 死4活3
    
        if (alive3 >= 2)
            return 12;//双活3
    
        if (die3 >= 1 && alive3 >= 1)
            return 11;//死3高级活3
    
        if (die4 >= 1)
            return 10;//高级死4
    
        if (ddie4 >= 1)
            return 9;//低级死4
    
        if (alive3 >= 1)
            return 8;//单活3
    
        if (dalive3 >= 1)
            return 7;//跳活3
    
        if (alive2 >= 2)
            return 6;//双活2
    
        if (alive2 >= 1)
            return 5;//活2
    
        if (dalive2 >= 1)
            return 4;//低级活2
    
        if (die3 >= 1)
            return 3;//死3
    
        if (die2 >= 1)
            return 2;//死2
    
        return 1;//没有威胁
    }
    bool gobang::isEnd(){
        for(int i = 1; i <= 4; i ++){
            dir d;
            int count = 0;
            switch(i){
                case 1:
                    d = d1;
                    break;
                case 2:
                    d = d2;
                    break;
                case 3:
                    d = d3;
                    break;
                case 4:
                    d = d4;
                    break;
            }
            for(int j = -4; j <= 4; j ++){
                point p1 = newPoint(laozi, d, j);
                if(isInBoard(p1) && chessboard[p1.y][p1.x] == chessboard[laozi.y][laozi.x]){
                    count ++;
                }
                else{
                    count = 0;
                }
                if(count == 5){
                    return true;
                }
            }
        }
        return false;
    }
    bool gobang::isInBoard(point p){
        if(p.y >= 0 && p.y < 15 && p.x >= 0 && p.x < 15){
            return true;
        }
        else{
            return false;
        }
    }
    
    point gobang::newPoint (point p, dir d, int lenth){
        point p1 = {p.y + d.dy * lenth, p.x + d.dx * lenth};
        return p1;
    }
    void gobang::display(){
        system("cls");
        for(int i = 0; i < 15; i ++){
            for(int j = 0; j < 15; j ++){
                if(i == Y && j == X){
                    cout << "";
                }
                else if(chessboard[i][j] == 1){
                    cout << "";
                }
                else if(chessboard[i][j] == 2){
                    cout << "";
                }
                else{
                    cout << ". ";
                }
                    
            }
            cout << endl;
        }
    }
    int main(){
        gobang game;
        game.play();
        return 0;
    }

     

      

     

         四、写五子棋程序的建议:          
                   1.首先要寻找好的代码,如果是那种完全是代码却一点都没有讲解的还是不要看了,给我帮助的博客有:https://www.cnblogs.com/songdechiu/p/5768999.html                              https://www.jb51.net/article/105675.htm
                   2.要先有规划,这就好比新年家里要大扫除,如果不做规划,就不知道从何开始,进行到哪里,做得怎么样。我一开始没有规划,盲目打代码,结果必定的错误百出,而且还难以寻找错误(连自己的代码为什么这样写都糊里糊涂),后来重新开始,先写一个思路图,在打代码,最后检查错误,时间节省了很多。
                 
                   3.完成之后,不妨教给别人(写博客是个好方法,可是应该没什么人看),在写的过程中,我要思考如何把一些问题讲清楚明白,让不会的人能理解,虽然我只是学到了皮毛,但是在这个过程中对程序的理解又有所提升。
            最后、因为我这个五子棋程序很简单,下赢它不难(我不太会五子棋,下不赢5555),我希望自己可以用博弈树在写一个五子棋程序,加油吧!

  • 相关阅读:
    react-native 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。
    Hibernate HQL和原生SQL查询的一点区别
    JPA project Change Event Handler问题解决[转]
    Webstorm2016激活码[ 转]
    [支付]微信NATIVE扫码支付JAVA实现
    jeecms附件标签用法
    Eclipse查找类路径快捷方式
    第4条:用辅助函数来取代复杂的表达式
    关于python2中的unicode和str以及python3中的str和bytes
    第2条:遵循PEP8风格指南
  • 原文地址:https://www.cnblogs.com/Serenaxy/p/10362519.html
Copyright © 2011-2022 走看看