C++语言设计实现五子棋

2020-01-06 19:33:36王旭
  • 落子位置评分算法:对活棋检测返回数组中的每个位置进行评分,即以该点为己方参照点,进行活棋检测,若有count=5,直接返回该落子位置。有活三或者半4,分数加20,有活2,分数加5,对角线有相邻同色,分数+2,有异色,分数-2,横竖有同色,分数+1,有异色,分数-1。最后排序,取最高分对应的落子,返回该落子。

    接下来则是数据结构和对象设计及主函数调用实现:

    类及类的实现

    
    #define RENJU_H
    #include <iostream>
    #include <windows.h>
    #include <string>
    #define hor 7
    #define ver 4
    using namespace std;
    
    
    //用于记录坐标
    struct position
    {
     int x;
     int y;
     position()
     {
     x = 0;
     y = 0;
     }
     position(int a,int b)
     {
     x = a;
     y = b;
     }
    };
    
    
    //用于记录棋子颜色和节点状态
    enum state
    {
     blank=0,black=1,white=2
    
    
    };
    
    
    //用于存储棋局分析信息:未完赛,犯规,平局,黑方胜,白方胜
    enum result
    {
     go_on,error,draw,black_win,white_win
    };
    
    
    // 设置光标
    void setpos(COORD a)  
    {
     HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
     SetConsoleCursorPosition(out, a);
    }
    
    
    // 设置光标
    void setpos(int i, int j)
    {
     COORD pos = { i, j };
     setpos(pos);
    }
    
    
    //绘图函数,用于在指定坐标输出指定字符
    inline void gps(int x,int y,char c)
    {
     setpos(y,x);
     cout<<c;
    }
    
    
    //绘图函数,用于在指定坐标输出整数
    inline void gps(int x,int y,int i)
    {
     setpos(y,x);
     if(i>=10)
     cout<<i;
     else
     cout<<0<<i;
    }
    
    
    //绘图函数,用于在指定坐标输出字符串
    inline void gps(int x,int y,string s)
    {
     setpos(y,x);
     cout<<s;
    }
    
    
    //绘图函数,用于在给定坐标打印棋盘中的一格
    void tab(int x,int y,state str)
    {
     string s;
     switch (str)
     {
     case blank:
     s=" "; 
     break;
     case black:
     s="黑";
     break;
     case white:
     s="白";
     break;
     default:
     break;
     }
     setpos(y,x);
     cout<<" ------ ";
     setpos(y,x+1);
     cout<<"|   |";
     setpos(y,x+2);
     cout<<"| "<<s<<" |";
     setpos(y,x+3);
     cout<<"|   |";
     setpos(y,x+4);
     cout<<" ------ ";
    }
    
    
    //查找最大值
    int MAX(const int *a,int n)
    {
     int max = a[0];
     for(int i =1; i < n ;i++)
     {
     if(a[i] > max)
      max = a[i];
     }
     return max;
    }
    
    
    //检测是否符合胜利条件
    
    
    //棋子类
    class chess
    {
    public:
     inline chess(int x=0,int y=0,state c=blank)
     { point.x=x,point.y=y;
     color=c;
     };
     inline chess(chess &ch) 
     { point=ch.drop_point();
     color=ch.get_color();
     }
     ~chess(){};
     struct position drop_point()const;//用于向外部提供棋子位置
     inline state get_color() const { return color;}//提供棋子颜色信息
     void set_point();//用于从外部获取棋子位置
     void set_point(int x,int y){ point.x=x,point.y=y;}
     void set_point(position p){ point.x=p.x,point.y=p.y;}
     void set_color(state c){ color=c;}//设置棋子颜色
    private:
     position point;
     enum state color;
     };
    
    
    position chess::drop_point()const
    {
     return point; 
    }
     
    void chess::set_point()
    {
     if(color==black)
     {
     setpos(110,1);
     cout<<"请黑方输入落子列数和行数,空格隔开:";
     cin>>point.x>>point.y;
     while(point.x<1||point.x>15)
     {
      setpos(110,1);
      cout<<"列数输入超出范围,请重新输入1~15之间数字   ";
      cin>>point.x;
     }
     while(point.y<1||point.y>15)
     {
      setpos(110,2);
      cout<<"行数输入超出范围,请重新输入1~15之间数字  ";
      cin>>point.y;
     }
     }
     else if(color==white)
     {
     setpos(110,1);
     cout<<"请白方输入落子列数和行数,空格隔开:";
     cin>>point.x>>point.y;
     while(point.x<1||point.x>15)
     {
      setpos(110,1);
      cout<<"列数输入超出范围,请重新输入1~15之间数字   ";
      cin>>point.x;
     }
     while(point.y<1||point.y>15)
     {
      setpos(110,2);
      cout<<"行数输入超出范围,请重新输入1~15之间数字  ";
      cin>>point.y;
     }
     }
     point.x--;
     point.y--;
    }
    
    
    //棋盘类
    class chessboard
    {
    public:
     chessboard()
     {
     for(int i=0;i<15;i++)
      for(int j=0;j<15;j++)
      {
      square[i][j]=blank;
      }
     }
     chessboard(chessboard *cb)
     {
     for(int i=0;i<15;i++)
      for(int j=0;j<15;j++)
      {
      square[i][j]=cb->viewboard(i,j);
      }
     }
     inline state viewboard(position p_c) const;//接收坐标,返回该位置的状态
     inline state viewboard(int x,int y) const;//接收整数坐标,返回该位置的状态
     void update(chess ch);//接收新棋子,更新棋盘状态
     void display()const;//向外输出棋盘状态
     result judge(chess ch)const;//规则函数,判断走棋是否犯规和输赢
     void clear()//清空棋盘
     {
      for(int i=0;i<15;i++)
      for(int j=0;j<15;j++)
      {
      square[i][j]=blank;
      }
     }
    private:
     state square[15][15];
    };
    int check_five(chessboard bd,chess ch)
    {
     position ori=ch.drop_point();
     int count=1;//计数器,统计同色个数
     int sum[4]={0};
     bool locked=0;//逻辑标记量,用来标记是否遇到了非同色节点
     //水平方向检测
     for(int i=0,locked=0;i<5&&((ori.x-i)>=0)&&(!locked);i++)//终止循环条件:同色超过4个或触碰到棋盘边界或遇到非同色节点
     if(ch.get_color()==bd.viewboard(ori.x-i,ori.y))
      count++;
     else
      if(i!=0)
      locked=1;
     //sum[0]=count-1;
     for(int i=0,locked=0;i<5&&((ori.x+i)<=14)&&(!locked);i++)//终止循环条件:同色超过4个或触碰到棋盘边界或遇到非同色节点
     if(ch.get_color()==bd.viewboard(ori.x+i,ori.y))
      count++;
     else
      if(i!=0)
      locked=1;
     //sum[1]=count-sum[0]-2;
     sum[0]=count;
     if(count>=5)
     return count;
     //竖直方向检测
     count=1;
     for(int i=0,locked=0;i<5&&((ori.y-i)>=0)&&(!locked);i++)//终止循环条件:同色超过4个或触碰到棋盘边界或遇到非同色节点
     if(ch.get_color()==bd.viewboard(ori.x,ori.y-i))
      count++;
     else
      if(i!=0)
      locked=1;
     //sum[2]=count-1;
     for(int i=0,locked=0;i<5&&((ori.y+i)<=14)&&(!locked);i++)//终止循环条件:同色超过4个或触碰到棋盘边界或遇到非同色节点
     if(ch.get_color()==bd.viewboard(ori.x,ori.y+i))
      count++;
     else
      if(i!=0)
      locked=1;
     //sum[3]=count-sum[2]-2;
     sum[1]=count;
     if(count>=5)
     return count;
     //左上到右下斜向检测
     count=1;
     for(int i=0,locked=0;i<5&&((ori.y-i)>=0)&&((ori.x-i)>=0)&&(!locked);i++)//终止循环条件:同色超过4个或触碰到棋盘边界或遇到非同色节点
     if(ch.get_color()==bd.viewboard(ori.x-i,ori.y-i))
      count++;
     else
      if(i!=0)
      locked=1;
     //sum[4]=count-1;
     for(int i=0,locked=0;i<5&&((ori.x+i)<=14)&&((ori.y+i)<=14)&&(!locked);i++)//终止循环条件:同色超过4个或触碰到棋盘边界或遇到非同色节点
     if(ch.get_color()==bd.viewboard(ori.x+i,ori.y+i))
      count++;
     else
      if(i!=0)
      locked=1;
     //sum[5]=count-sum[4]-2;
     sum[2]=count;
     if(count>=5)
     return count;
     //左下到右上斜向检测
     count=1;
     for(int i=0,locked=0;i<5&&((ori.y+i)<=14)&&((ori.x-i)>=0)&&(!locked);i++)//终止循环条件:同色超过4个或触碰到棋盘边界或遇到非同色节点
     if(ch.get_color()==bd.viewboard(ori.x-i,ori.y+i))
      count++;
     else
      if(i!=0)
      locked=1;
     //sum[6]=count-1;
     for(int i=0,locked=0;i<5&&((ori.x+i)<=14)&&((ori.y-i)>=0)&&(!locked);i++)//终止循环条件:同色超过4个或触碰到棋盘边界或遇到非同色节点
     if(ch.get_color()==bd.viewboard(ori.x+i,ori.y-i))
      count++;
     else
      if(i!=0)
      locked=1;
     //sum[7]=count-sum[6]-2;
     sum[3]=count;
     if(count>=5)
     return count;
     return MAX(sum,4);
    }
    
    
    state chessboard::viewboard(position p_c) const
    {
     return square[p_c.x][p_c.y];
    }
    state chessboard::viewboard(int x,int y) const
    {
     return square[x][y];
    }
    void chessboard::update(chess ch)
    {
     position pos=ch.drop_point();
     square[pos.x][pos.y]=ch.get_color();
    }
    
    
    void chessboard::display()const
    {
     system("cls");
    
    
     for(int i=0;i<15;i++)//打印列坐标说明
     {
     gps(0,6+i*hor,i+1);
     }
     for(int i=0;i<15;i++)//打印列坐标说明
     {
     gps(16*ver,6+i*hor,i+1);
     }
     for(int i=0;i<15;i++)//打印行坐标说明
     {
     gps(3+i*ver,1,i+1);
     }
     for(int i=0;i<15;i++)//打印行坐标说明
     {
     gps(3+i*ver,1+16*hor,i+1);
     }
     for(int i=0,j=0;i<15;i++)
     {
     for(j=0;j<15;j++)
      tab(1+i*ver,3+hor*j,square[j][i]);
     }
     cout<<endl;
    }
    result chessboard::judge(chess set)const
    {
     bool full=1;
     if(viewboard(set.drop_point())!=blank)
     {
     return error;
     }
    
    
     if(check_five(*this,set)>=5&&(set.get_color()==black))
     return black_win;
    
    
     if(check_five(*this,set)>=5&&(set.get_color()==white))
     return white_win;
    
    
     for(int i=0;i<15;i++)
     for(int j=0;j<15;j++)
     {
      if(square[i][j]==blank) 
      full=0;
     }
     if(full==1)
     return draw;
     else
     return go_on;
    }
    #endif