五子棋AI

#include "stdafx.h"
#include "Gloab.h"


//定义点
struct Point
{
 int x ;
 int y ;
};

//定义棋子节点,用于悔棋
struct chessNode
{
 Point point;//棋子的棋盘位置
 int   status;//下子者 0为电脑 ,1为棋手,2为空白
 int   win[2][252];//用于存储当前节点的胜利组合数目
};


class chess
{
private:
 //定义棋盘上棋子的状态
 //const int Black = 0;//黑棋为电脑
 //const int White = 1;//白棋为棋手
 //const int Blank = 2;//空白

 //定义棋手和电脑的棋盘用于存放
 bool playerBoard[11][11][252];
 bool computerBoard[11][11][252];


 //分别用于存放电脑和棋手在各点的得分
 int computerGrade[11][11],playerGrade[11][11];

 //计算在每种组合中电脑或棋手分别占据几粒棋子
 //0代表电脑,1代表棋手
 int win[2][252];


 //定义是否为第一步棋
 bool start;

 //记录电脑和棋手的下棋步数
 int computerCount;
 int playerCount;

 //用以进行当前下棋者的转换
 bool player,computer;

 //用于存放所有棋子的状态,位置和下子者,用于悔棋只用
 chessNode allChess[122];

 //是否游戏结束
 bool gameover;

 //获胜者   0为电脑 1为棋手   2为游戏未结束 -1为平局
 int  winner;
 /*************功能函数**************************/

 //把棋盘初始化为空白
 int initBoard();
 //初始化分数
 void initialMark();
 //初始化获胜的组合数
 int initWinCompages();
  //记录所下棋子的状态
 void recordChessStatus(int horizontal , int vertical , int player);
 //计算某个胜利组合中已经被某方占据的棋子数放到win[2][252]的数组中去, 参数分别为水平,竖直位置,最后是记录落子的是电脑还是棋手
 int compute(int horizontal , int vertical , int player);


public:
 //定义棋盘
 int Board[11][11];
 
 //构造函数
 chess();
 //电脑通过计算确定下棋位置
 int computerPlay();
 //棋手在棋盘中落子
 int playerPlayChess(int horizontal , int vertical);
 //悔棋,只能对己方上一步进行悔棋
 int contritionChess();
  //判断是否已经游戏结束
  bool gameOver(int player);
  //取得获胜者 0为电脑 1为棋手 2为棋局未结束 -1为平局
  int getWinner();
};


 /*************功能函数**************************/

 //把棋盘初始化为空白
 int chess::initBoard()
  {
   int i=0;
   
   //把棋盘初始化为空格
   for( i =0 ; i < 11 ;i++)
   {
    for(int j = 0 ; j < 11 ; j++)
     Board[i][j] = 2;
   }
   //初始化棋局
   for(i = 0 ; i<122 ; i++)
   {
    allChess[i].point.x = -1;
    allChess[i].point.y = -1;
    allChess[i].status  = 2 ;
   }
   
   computerCount = playerCount = 0;
   gameover = false ;
   winner = 2;
   return 0 ;
  }
 //初始化分数
 void chess::initialMark()
  {
   for(int i = 0 ;i < 11 ; i ++)
    for(int j = 0 ; j < 11 ; j++)
    {
     computerGrade[i][j] = 0 ;
     playerGrade[i][j] = 0 ;
    }
  
  }
 //初始化获胜的组合数
 int chess::initWinCompages()
  {
   int i=0,j=0,k=0,num=0;
   //初始化水平方向的获胜组合数
   for(i = 0 ; i< 11; i++)
   {
    for(int j = 0 ; j < 7 ; j++)
    {
     for(k = 0; k < 5 ; k++)
     {
      playerBoard[i][j+k][num] = true;
      computerBoard[i][j+k][num] = true;
     }
     num++;
    }
   }

   //初始化垂直方向的获胜组合数
   for(j = 0 ; j< 11; j++)
   {
    for(int i = 0 ; i < 7 ; i++)
    {
     for(k = 0; k < 5 ; k++)
     {
      playerBoard[i+k][j][num] = true;
      computerBoard[i+k][j][num] = true;
     }
     num++;
    }
   }

   //初始化正对角线方向获胜组合
   for(i = 0 ; i< 7; i++)
   {
    for( j = 0 ; j < 7 ; j++)
    {
     for(k = 0; k < 5 ; k++)
     {
      playerBoard[i+k][j+k][num] = true;
      computerBoard[i+k][j+k][num] = true;
     }
     num++;
    }
   }
   
   //初始化反对角线方向获胜组合
   for(i = 0 ; i < 7; i++)
    for(j = 10 ;j >= 4 ; j--)
    {
     for(k = 0; k < 5 ; k++)
     {
      playerBoard[i+k][j+k][num] = true;
      computerBoard[i+k][j+k][num] = true;
     }
     num++;
    }
   num = 0 ;
   return 0;
  }

  //记录所下棋子的状态
 void chess::recordChessStatus(int horizontal , int vertical , int player)
  {
   //存放位置是与下棋的步数相同,也就是从1开始到121,
   allChess[(playerCount+computerCount)].point.x = horizontal;
   allChess[(playerCount+computerCount)].point.y = vertical;
   allChess[(playerCount+computerCount)].status = player;
   //记录当前节点的获胜组合数
   for(int i = 0 ; i <2 ; i++)
    for(int j = 0 ; j <252 ;j++)
     allChess[(playerCount+computerCount)].win[i][j] = win[i][j];
   return ;
  }
 //计算某个胜利组合中已经被某方占据的棋子数放到win[2][252]的数组中去, 参数分别为水平,竖直位置,最后是记录落子的是电脑还是棋手
 int chess::compute(int horizontal , int vertical , int player)
  {
   //如果棋子的位置不在11 * 11范围内的话返回错误
   if((horizontal >=11)||(vertical >= 11)||(horizontal < 0)||(vertical < 0))
    return -1 ;
   for(int i = 0 ; i < 252 ; i++)
   {
    //如果落子者为棋手
    if(player == 1)
    {
     if(playerBoard[horizontal][vertical][i] && (win[1][i] != -1))
     {
      //统计该组合中己方已占据几子,若是为-1表示该组合中有一个已经被对手占据,不可能胜利了
      win[1][i]++;
     }
     if(computerBoard[horizontal][vertical][i])
     {
      //因为棋手已经在该组合中落下一子 所以电脑不可能通过此组合胜利
      computerBoard[horizontal][vertical][i] = false;
      win[0][i] = -1;
     }
    }
    //如果落子者为电脑
    else if(player == 0)
    {
     if(computerBoard[horizontal][vertical][i] && (win[0][i] != -1))
     {
      //统计该组合中己方已占据几子,若是为-1表示该组合中有一个已经被对手占据,不可能胜利了
      win[0][i]++;
     }
     if(playerBoard[horizontal][vertical][i])
     {
      //因为棋手已经在该组合中落下一子 所以电脑不可能通过此组合胜利
      playerBoard[horizontal][vertical][i] = false;
      win[1][i] = -1;
     }
    }
   }
   return 1;
  }
 //构造函数
 chess::chess()
  {
   initBoard();
   initWinCompages();
   initialMark();
   start = true;
   player = true;
   computer = false;
  }
 //电脑通过计算确定下棋位置
 int chess::computerPlay()
  {
   if(computer)
   {
     int i = 0,j = 0 , k = 0;
     //用于存放棋盘中电脑和棋手的最高分数
     int playerMax = 0 ,computerMax = 0;
     int pX = -1,pY = -1,cX = -1 ,cY = -1;

     //用于暂存电脑最后确定的下棋位置
     int x , y ;
     //如果为电脑的第一步棋则优先置于棋盘的中心位置
     if(start)
     {
      if(Board[5][5] == 2)
      {
       x = 5;
       y = 5;
      }
      else
      {
       x = 5;
       y = 4;
      }
      Board[x][y] = 0;
      compute(x,y,0);
      computerCount++;
      //记录所下棋子的状态
      recordChessStatus(x,y,0);
      computer = false;
      player  = true;
      start  = false;
      return 1;
     }

     //先计算棋手的棋盘分数
     for(i = 0 ; i < 11 ; i++)
      for( j = 0 ; j < 11 ; j++)
      {
       //如果该位置为空才对该位置计分
       if(Board[i][j] == 2)
       {
        for(int k = 0 ; k < 252 ; k ++ )
        {
         //确定该位置在哪个获胜的组合中
         if(playerBoard[i][j][k])
         {
          switch(win[1][k])
          {
           //通过计算组合的五子中己方占据子数计分,1子五分,2子50,3子500,4子5000
           case 1:
            playerGrade[i][j] = playerGrade[i][j] + 5;
            break;
           case 2:
            playerGrade[i][j] = playerGrade[i][j] + 50;
            break;
           case 3:
            playerGrade[i][j] = playerGrade[i][j] + 500;
            break;
           case 4:
            playerGrade[i][j] = playerGrade[i][j] + 5000;
            break;
          }
         }
        }
       }
       //如果当前位置大于之前找到的最高分位置,保存当前位置信息
       if(playerGrade[i][j] > playerMax) 
       {
        playerMax = playerGrade[i][j];
        pX = i ;
        pY = j ;
       }
      }

      //计算电脑在棋盘位置的得分
      for(i = 0 ; i < 11 ; i++)
       for( j = 0 ; j < 11 ; j++)
       {
        //如果该位置为空才对该位置计分
        if(Board[i][j] == 2)
        {
         for(int k = 0 ; k < 252 ; k ++ )
         {
          //确定该位置在哪个获胜的组合中
          if(computerBoard[i][j][k])
          {
           switch(win[0][k])
           {
            //通过计算组合的五子中己方占据子数计分,1子五分,2子50,3子500,4子5000
            //让电脑在同等条件下多得一分 , 使之更侧重于进攻,如果侧重于防守同理可得
            case 1:
             computerGrade[i][j] = computerGrade[i][j] + 6;
             break;
            case 2:
             computerGrade[i][j] = computerGrade[i][j] + 51;
             break;
            case 3:
             computerGrade[i][j] = computerGrade[i][j] + 501;
             break;
            case 4:
             computerGrade[i][j] = computerGrade[i][j] + 5001;
             break;
           }
          }
         }
        }
        //如果当前位置大于之前找到的最高分位置,保存当前位置信息
        if(computerGrade[i][j] > computerMax) 
        {
         computerMax = computerGrade[i][j];
         cX = i ;
         cY = j ;
        }
      }
      //如果电脑的最高分大于棋手最高分,则电脑进攻 
      if(computerMax > playerMax)
      {
       x = cX ;
       y = cY ;
      }
      else
      {
       x = pX;
       y = pY;
      }

      //将最佳下棋点置为电脑
      Board[x][y] = 0 ;
      //计算经过落子后某个胜利组合中已经被某方占据的棋子数
      compute(x,y,0);
      computerCount++;
      
      //记录所下棋子的状态
      recordChessStatus(x,y,0);

      //下棋者转换
      computer = false;
      player  = true;

      
      if( computerCount == 60 )  //棋盘上无空位的情况
      {
       gameover = true ;
       winner = -1;
      } 
      initialMark();
      return 1;
    }
     initialMark();
     return -1;
  }
 //棋手在棋盘中落子
 int chess::playerPlayChess(int horizontal , int vertical)
   {
    if(player)
   {
      //如果棋子的位置不在11 * 11范围内的话返回错误
     if((horizontal >=11)||(vertical >= 11)||(horizontal < 0)||(vertical < 0))
      return -1 ;
     if(Board[horizontal][vertical] != 2)
      return -1;
     Board[horizontal][vertical] = 1;
     playerCount++;

     //记录所下棋子的状态
     recordChessStatus(horizontal,vertical,1);

     //计算棋手落子之后棋盘上棋手在一个组合中占有的棋子数
     if(!compute(horizontal,vertical,1))
      return -1;
     player  = false ;
     computer = true ;
     if( playerCount == 60 )  //棋盘上无空位的情况
     {
      gameover = true ;
      winner = -1;
     }
     return 1;
   }
    else
     return -1;
   }

 //悔棋,只能对己方上一步进行悔棋
 int chess::contritionChess()
  {
   //用于存放当前步数
   int step;
   Point point ;
   int player = 2;
  
   step = computerCount + playerCount;
   if(step > 1)
   {
    //先撤销电脑的下棋位置
    //确认刚落子的是否为电脑
    if((allChess[step].status == 0)&&(allChess[step].point.x != -1))
    {
    point = allChess[step].point;
    Board[point.x][point.y] = 2; 
    allChess[step].status = 2;
    allChess[step].point.x = -1;
    allChess[step].point.y = -1;
    //恢复step-1的组合胜利数
    for(int i = 0 ; i <2 ; i++)
     for(int j = 0 ; j <252 ;j++)
       win[i][j] = allChess[(playerCount+computerCount)].win[i][j] ;
    computerCount--;
    step -- ;
    }
   //撤销棋手的棋
    if((allChess[step].status == 1)&&(allChess[step].point.x != -1))
     {
    point = allChess[step].point;
    Board[point.x][point.y] = 2; 
    allChess[step].status = 2;
    allChess[step].point.x = -1;
    allChess[step].point.y = -1;
    //恢复step-1的组合胜利数
    for(int i = 0 ; i <2 ; i++)
     for(int j = 0 ; j <252 ;j++)
       win[i][j] = allChess[(playerCount+computerCount)].win[i][j] ;
    playerCount--;
    step--;
     }
   }
  return 1;
  }
  //判断是否已经游戏结束
  bool chess::gameOver(int player)
  {
   if(!gameover)
    {
    int i ;
    //如果为棋手,判断win[1][i]中是否有已经五子的组合
    if(player == 1)
    {
     for( i = 0  ; i < 252 ; i++ )
      if(win[1][i] == 5)
      {
       //游戏结束
       gameover  = true ;
       winner =  1;
       return true;
      }
    }
    if(player == 0)
    {
     for( i = 0  ; i < 252 ; i++ )
      if(win[0][i] == 5)
      {
       //游戏结束
       gameover  = true ;
       winner =  0;
       return true;
      }
    }
    return false;
    }
  return true;
  }
   //取得获胜者 0为电脑 1为棋手 2为棋局未结束 -1为平局
  int chess::getWinner()
  {
  return winner;
  }

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值