C++ 实现对战AI五子棋

简介: C++ 实现对战AI五子棋


前言:

    为了能够快速上手一门语言,我们往往在学习了基本语法后,采用写一个小项目的方式来加深理解语言的语法及运用,本文采用c++去实现对战AI五子棋,采用面向对象开发的一款游戏,里面应用了类和对象以及vector容器等知识。

一、项目效果展示


 


二、游戏思路

 


 

三、游戏框架

我们这里创建四个类(可以简单的理解为加强版的结构体),玩家类、AI类、棋盘类、棋盘控制类,将玩家类、AI类、棋盘类作为参数传给棋盘控制类,棋盘控制类获取这三个类的信息,从而可以控制游戏的运行,而玩家和AI要进行下棋操作时,需要棋盘信息,所以在玩家和AI类设置棋盘类。

根据上面分析,我们搭建好框架,先实现棋盘类功能,再实现AI和玩家类,最后实现棋盘控制类

四、棋盘类实现

4.1  用棋盘类构造函数初始化

4.1.1  checkerboard.h

#include<graphics.h>//eaysx头文件
#include<vector>
using namespace std;
enum  GameResult { BLACK_WIN,WHITE_WIN,DRAW ,CONTINUE};
class checkerboard
{
public:
  //构造函数初始化成员变量
  checkerboard(int BoardSize, int margin_x, int margin_y, float ChessSize)
  {
    this->BoardSize = BoardSize;//几线棋盘
    this->margin_x=margin_x;
    this->margin_y = margin_y;
    this->ChessSize = ChessSize;//棋子大小
     //加载黑子和白子图片到黑子和白子变量
    loadimage(&BLACK_IMG, "res/black.png", ChessSize, ChessSize, true);
    loadimage(&WHITE_IMG, "res/white.png", ChessSize, ChessSize, true);
    
  //棋盘初始化
    for (int i = 0; i < ChessSize; i++)
    {
      vector<int> row;
      for (int j = 0; j < ChessSize; j++)
      {
        row.push_back(0);
      }
      BoardMap.push_back(row);
    }
    
     gameresult= CONTINUE;
    
  }
  
  int BoardSize;//棋盘大小
  float ChessSize;//棋子大小
  vector<vector<int>> BoardMap;//表示棋盘落子情况
private:
  IMAGE BLACK_IMG;//黑棋图片变量
  IMAGE WHITE_IMG;//白棋图片变量
  
  int margin_x;//左侧边界45
  int margin_y;//右侧边界45
};

4.2  棋盘类初始化函数

注:

这个初始化函数和棋盘类构造函数的初始化一样,为什么再初始化一次呢?因为我们后面进行游戏运行时,一局结束,再来一局还需要再调用一次棋盘初始化,而定义棋盘类只能调用一次构造函数,所以再创一个棋盘类初始化函数

4.2.1  checkerboard.h

pubilc:
void Init();//棋盘初始化

4.2.2   checkerboard.cpp

void checkerboard::Init()
{
    initgraph(L, W, 1);//窗口大小
    //加载到窗口棋盘图片
    loadimage(0, "res/棋盘2.jpg", L,W,true);
    //播放声音
  /*  mciSendString("play res/start.WAV", 0, 0, 0);*/
    //加载黑子和白子图片到黑子和白子变量
    //loadimage(&BLACK_IMG, "res/black.png", ChessSize, ChessSize, true);
    //loadimage(&WHITE_IMG, "res/white.png", ChessSize, ChessSize, true);
    //后面没有调用构造函数,调用初始化,所有在这里还需要对容器归0
    for (int i = 0; i < ChessSize; i++)
    {
        
        for (int j = 0; j < ChessSize; j++)
        {
            BoardMap[i][j] = 0;
        }
        
    }
    gameresult = CONTINUE;
  
}

4.3  检查鼠标点击是否有效

注:

虽然代码很长,但是思路很简单,先计算点击位置(x,y) 附近的4个落棋位置的实际坐标位置,然后再计算点击位置到这四个落棋位置之间的距离,如果落棋位置与点击位置距离小于棋子大小的0.4倍,就认为这个落棋位置是玩家想要落棋的位置,存储在pos中。若此时该位置没有其他棋子,则为有效点击,返回真。

4.3.1 checkerboard.h

棋盘类外:

//落子位置
struct ChessPos
{
  int row;
  int col;
};
enum  chess_type{CHESS_WHITE=-1,CHESS_BLACK=1};

棋盘类内:

public:
bool ClickBord(int x, int y, ChessPos& pos);//检查有效点击

4.3.2 checkerboard.cpp

bool checkerboard::ClickBord(int x, int y, ChessPos& pos)
{
    //保证在棋盘内
    if (x >= margin_x && x <= (L - margin_x) && y >= margin_y && y <= (W - margin_y))
    {
        int col = (x - margin_x) / ChessSize;
        int row = (y - margin_y) / ChessSize;
        //该位置左上角的交点的坐标
        int LTPos_x = margin_x + ChessSize * col;
        int LTPos_y = margin_y + ChessSize * row;
        int critical = ChessSize * 0.4;//临界值
        //鼠标点击位置与右上角交点之间的距离
        int distance1 = sqrt((x - LTPos_x) * (x - LTPos_x) + (y - LTPos_y) * (y - LTPos_y));//勾股定理
         //该位置右上角的交点的坐标
        int RTPos_x = LTPos_x + ChessSize;
        int RTPos_y = LTPos_y;
        //鼠标点击位置与右上角交点之间的距离
        int distance2 = sqrt((x - RTPos_x) * (x - RTPos_x) + (y - RTPos_y) * (y - RTPos_y));//勾股定理
         //该位置左下角的交点的坐标
        int LDPos_x = LTPos_x;
        int LDPos_y = LTPos_y + ChessSize;
        //鼠标点击位置与左下角交点之间的距离
        int distance3 = sqrt((x - LDPos_x) * (x - LDPos_x) + (y - LDPos_y) * (y - LDPos_y));//勾股定理
         //该位置右下角的交点的坐标
        int RDPos_x = LTPos_x + ChessSize;
        int RDPos_y = LTPos_y + ChessSize;
        //鼠标点击位置与右下角交点之间的距离
        int distance4 = sqrt((x - RDPos_x) * (x - RDPos_x) + (y - RDPos_y) * (y - RDPos_y));//勾股定理
        if (distance1 <= critical)
        {
            pos.col = col;
            pos.row = row;
            if (BoardMap[pos.row][pos.col] == 0)//该坐标没有棋子
            {
                return true;
            }
            return false;
        }
        else if (distance2 <= critical)
        {
            pos.col = col + 1;
            pos.row = row;
            if (BoardMap[pos.row][pos.col] == 0)//该坐标没有棋子
            {
                return true;
            }
            return false;
        }
        else if (distance3 <= critical)
        {
            pos.col = col;
            pos.row = row + 1;
            if (BoardMap[pos.row][pos.col ] == 0)//该坐标没有棋子
            {
                return true;
            }
            return false;
        }
        else if (distance4 <= critical)
        {
            pos.col = col + 1;
            pos.row = row + 1;
            if (BoardMap[pos.row ][pos.col] == 0)//该坐标没有棋子
            {
                return true;
            }
            return false;
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}

4.4   下棋

功能:实现记录最后一次落子的位置以及最后一次下棋是玩家方还是AI方,在棋盘二维数组记录落子数据。

4.4.1 checkerboard.h

棋盘类外:

//落子位置
struct ChessPos
{
  int row;
  int col;
};
enum  chess_type{CHESS_WHITE=-1,CHESS_BLACK=1};

棋盘类内:

public:
  void PlayChess(ChessPos& pos,chess_type type);//下棋

 4.4.2 checkerboard.cpp

void checkerboard::PlayChess(ChessPos& pos, chess_type type)
{
    int x = margin_x + ChessSize * pos.col-ChessSize*0.5;
    int y = margin_y + ChessSize * pos.row- ChessSize *0.5;
   
        BoardMap[pos.row][pos.col] = type;
        lastpos.row = pos.row;
        lastpos.col = pos.col;
        lasttype = type;
    
    if (type == CHESS_BLACK)
    {
        putimagePNG(x, y, &BLACK_IMG);
       
    }
    else
    {
        putimagePNG(x, y, &WHITE_IMG);
    }
}

4.5  判断棋盘是否下满

4.5.1 checkerboard.h

bool BoardFull();

4.5.2 checkerboard.cpp

bool checkerboard::BoardFull()
{
    for (int row = 0; row < BoardSize; row++)
    {
        for (int col = 0; col < BoardSize; col++)
        {
            if (BoardMap[row][col] == 0)//棋盘没满
            {
                return false;
            }
        }
   }
    return true;
}

4.6  判断游戏状态

4.6.1 checkerboard.h

棋盘类外:

enum  GameResult { BLACK_WIN,WHITE_WIN,DRAW ,CONTINUE};

棋盘类内:

private:
GameResult gameresult;
GameResult IsWin();

4.6.2 checkerboard.cpp

GameResult checkerboard::IsWin()
{
    bool boardfull = BoardFull();
    
    //每个方向记连续棋子个数
    int Black_Num = 0;
    int  White_Num = 0;
    if (lasttype == CHESS_BLACK)//黑子方
    {
        //计算四个方向是否有5个
        for (int i = 0; i <= 1; i++)//分横,竖,上斜,下斜4个方向
        {
            for (int j = -1; j <= 1; j++)
            {
                //每个方向记连续棋子个数
                Black_Num = 0;
                White_Num = 0;
                if ((i == 0 && j == 0) || (i == 0 && j == 1))
                {
                    continue;
                }
                for (int k = 1; k <= 4; k++)//最多判断五个子,四个方向中的单向
                {
                    int Cur_row = lastpos.row + i * k;
                    int Cur_col = lastpos.col + j * k;
                    if (Cur_row >= 0 && Cur_row < BoardSize &&
                        Cur_col >= 0 && Cur_col < BoardSize &&
                        BoardMap[Cur_row][Cur_col] == CHESS_BLACK)
                    {
                        Black_Num++;
                    }
                    else//超出棋盘或者是白子或者空白
                    {
                        break;
                    }
                }
                for (int k = 1; k <= 4; k++)//最多判断五个子,四个方向中单向的另一个方向
                {
                    int Cur_row = lastpos.row - i * k;
                    int Cur_col = lastpos.col - j * k;
                    if (Cur_row >= 0 && Cur_row < BoardSize &&
                        Cur_col >= 0 && Cur_col < BoardSize &&
                        BoardMap[Cur_row][Cur_col] == CHESS_BLACK)
                    {
                        Black_Num++;
                    }
                    else//超出棋盘或者是白子或者空白
                    {
                        break;
                    }
                }
                //判断游戏状态
                if (Black_Num == 4)//5个黑子,游戏结束
                {
                    
                    return BLACK_WIN;
                }
                else
                {
                    if (boardfull)
                    {
                        return  DRAW;
                    }
                    
                }
            }
        }
    }
    else//白子方
    {
        //计算四个方向是否有5个
        for (int i = 0; i <= 1; i++)//分横,竖,上斜,下斜4个方向
        {
            for (int j = -1; j <= 1; j++)
            {
                //每个方向记连续棋子个数
                Black_Num = 0;
                White_Num = 0;
                if ((i == 0 && j == 0) || (i == 0 && j == 1))
                {
                    continue;
                }
                for (int k = 1; k <= 4; k++)//最多判断五个子,四个方向中的单向
                {
                    int Cur_row = lastpos.row + i * k;
                    int Cur_col = lastpos.col + j * k;
                    if (Cur_row >= 0 && Cur_row < BoardSize &&
                        Cur_col >= 0 && Cur_col < BoardSize &&
                        BoardMap[Cur_row][Cur_col] == CHESS_WHITE)
                    {
                        White_Num++;
                    }
                    else//超出棋盘或者是黑子或者空白
                    {
                        break;
                    }
                }
                for (int k = 1; k <= 4; k++)//最多判断五个子,四个方向中单向的另一个方向
                {
                    int Cur_row = lastpos.row - i * k;
                    int Cur_col = lastpos.col - j * k;
                    if (Cur_row >= 0 && Cur_row < BoardSize &&
                        Cur_col >= 0 && Cur_col < BoardSize &&
                        BoardMap[Cur_row][Cur_col] == CHESS_WHITE)
                    {
                       White_Num++;
                    }
                    else//超出棋盘或者是黑子或者空白
                    {
                        break;
                    }
                }
                //判断游戏状态
                if (White_Num == 4)//5个白子,游戏结束
                {
                    return WHITE_WIN;
                }
                else
                {
                    if (boardfull)
                    {
                        return  DRAW;
                    }
                }
            }
        }
    }
    return CONTINUE;
}

4.7   判断游戏是否结束

4.7.1 checkerboard.h

bool CheckOver();//检查游戏是否结束

4.7.2  checkerboard.cpp

bool checkerboard::CheckOver()
{
    gameresult = IsWin();
    if (gameresult == BLACK_WIN)
    {
        Sleep(2000);
        loadimage(0, "res/胜利.jpg",W,L,true);
        //播放声音
        mciSendString("play res/胜利.mp3", 0, 0, 0);
        _getch();
        return true;
    }
    else if (gameresult == WHITE_WIN)
    {
        Sleep(2000);
        loadimage(0, "res/失败.jpg",W , L, true);
        //播放声音
        mciSendString("play res/失败.mp3", 0, 0, 0);
        _getch();//暂停,按任意键继续
        return true;
    }
    else if (gameresult == DRAW)
    {
        Sleep(2000);
        loadimage(0, "res/平局.png",W , L , true);
        _getch();
        return true;
        
    }
    else//继续游戏
    {
        return false;
    }
}

五、玩家类实现

5.1  用玩家类构造函数初始化

5.1.1  chess_player.h

#include"checkerboard.h"
#include"AI.h"
class chess_player
{
public:
  chess_player(checkerboard& checkerboard)
  {
    this->checkerboard = &checkerboard;
  }
  
  void go();
private:
  checkerboard* checkerboard;
};

5.2  玩家下棋

5.2.1 chess_player.h

void go();

5.2.2  chess_player.cpp

void chess_player::go()
{
  
  ChessPos pos;
  while (1)
  {
    MOUSEMSG mousemsg = GetMouseMsg();//鼠标信息结构体变量
    bool click_board = checkerboard->ClickBord(mousemsg.x, mousemsg.y, pos);
    if (mousemsg.uMsg == WM_LBUTTONDOWN &&click_board )//用到checkboard对象的成员
    {
      printf("%d,%d\n", pos.row, pos.col);
      break;
    }
  }
  
  checkerboard->PlayChess(pos, CHESS_BLACK);//黑子下棋的位置(渲染和记录)
}

六、AI类实现

6.1 用AI类构造函数初始化

6.1.1  AI.h

#include"checkerboard.h"
#include<vector>
class AI
{
public:
  AI(checkerboard& checkerboard)//AI构造函数
  {
    this->checkerboard = &checkerboard;
    for (int i = 0; i <checkerboard.ChessSize; i++)
    {
      vector<int> row;
      for (int j = 0; j <checkerboard.ChessSize; j++)
      {
        row.push_back(0);
      }
      ScoreMap.push_back(row);
    }
  }
  void go();
private:
  checkerboard* checkerboard;
  vector<vector<int>>  ScoreMap;
  void  CalculateScore();
  ChessPos   MaxScore();
  
};

6.2  AI计算权值最高的棋盘空白位置

计算棋盘空白位置的权值,首先对该位置的横、竖、上斜、下斜四个方位做判断,以该位置为起点,每个方位只需要在单方向上判断4个棋子位,反方向判断四个棋子位,统计连续的白子或者黑子个数,根据下面的表格给出相应权重值,选择出累计权值最高的位置为AI落子点。

6.2.1  AI.h

private:
  
  vector<vector<int>>  ScoreMap;
  void  CalculateScore();

 6.2.2  AI.cpp

void AI::CalculateScore()
{
  int Black_Num = 0;
  int White_Num = 0;
  int Empty_Num = 0;
  for(int row=0;row<checkerboard->BoardSize;row++)
    for (int col = 0; col< checkerboard->BoardSize; col++)
    {
      if (checkerboard->BoardMap[row][col] != 0)//有棋子,则跳过判断
      {
        continue;
      }
      //先假设下黑子,计分情况
      for (int i = 0; i <= 1; i++)//分横,竖,上斜,下斜4个方向
      {
        for (int j = -1; j <= 1; j++)
        {
          //每个方向记连续棋子个数
          Black_Num = 0;
           White_Num = 0;
           Empty_Num = 0;
          if ((i == 0 && j == 0) || (i ==0 && j == 1))
          {
            continue;
          }
          for (int k = 1; k <= 4; k++)//最多判断五个子,四个方向中的单向
          {
            int Cur_row = row + i * k;
            int Cur_col = col + j * k;
            if (Cur_row>=0&&Cur_row<checkerboard->BoardSize&&
              Cur_col>=0&&Cur_col<checkerboard->BoardSize&&
              checkerboard->BoardMap[Cur_row][Cur_col] == CHESS_BLACK)
            {
              Black_Num++;
            }
            else if(Cur_row >= 0 && Cur_row < checkerboard->BoardSize &&
              Cur_col >= 0 && Cur_col < checkerboard->BoardSize &&
              checkerboard->BoardMap[Cur_row][Cur_col] ==0)
            {
              Empty_Num++;
              break;
            }
            else//超出棋盘或者是白子
            {
              break;
            }
          }
          for (int k = 1; k <= 4; k++)//最多判断五个子,四个方向中单向的另一个方向
          {
            int Cur_row = row - i * k;
            int Cur_col = col - j * k;
            if (Cur_row >= 0 && Cur_row < checkerboard->BoardSize &&
              Cur_col >= 0 && Cur_col < checkerboard->BoardSize &&
              checkerboard->BoardMap[Cur_row][Cur_col] == CHESS_BLACK)
            {
              Black_Num++;
            }
            else if (Cur_row >= 0 && Cur_row < checkerboard->BoardSize &&
              Cur_col >= 0 && Cur_col < checkerboard->BoardSize &&
              checkerboard->BoardMap[Cur_row][Cur_col] == 0)
            {
              Empty_Num++;
              break;
            }
            else//超出棋盘或者是白子
            {
              break;
            }
          }
          //该位置的得分情况
          if (Black_Num == 1)//2个黑子
          {
            ScoreMap[row][col] += 10;
          }
          else if (Black_Num == 2)//连续三个黑子
          {
            if (Empty_Num == 1)
            {
              ScoreMap[row][col] += 30;
            }
            else if(Empty_Num==2)
            {
              ScoreMap[row][col] += 40;
            }
          }
          else if (Black_Num == 3)//连续4个黑子
          {
            if (Empty_Num == 1)
            {
              ScoreMap[row][col] += 60;
            }
            else if (Empty_Num == 2)
            {
              ScoreMap[row][col] += 200;
            }
          }
          else if (Black_Num == 4)//连续5个黑子
          {
            ScoreMap[row][col] += 20000;
          }
        }
      }
      //假设该位置下白子,计分情况
      for (int i = 0; i <= 1; i++)//分横,竖,上斜,下斜4个方向
      {
        for (int j = -1; j <= 1; j++)
        {
          //每个方向记连续棋子个数
          Black_Num = 0;
          White_Num = 0;
          Empty_Num = 0;
          if ((i == 0 && j == 0) || (i == 0 && j == 1))
          {
            continue;
          }
          for (int k = 1; k <= 4; k++)//最多判断五个子,四个方向中的单向
          {
            int Cur_row = row + i * k;
            int Cur_col = col + j * k;
            if (Cur_row >= 0 && Cur_row < checkerboard->BoardSize &&
              Cur_col >= 0 && Cur_col < checkerboard->BoardSize &&
              checkerboard->BoardMap[Cur_row][Cur_col] == CHESS_WHITE)
            {
              White_Num++;
            }
            else if (Cur_row >= 0 && Cur_row < checkerboard->BoardSize &&
              Cur_col >= 0 && Cur_col < checkerboard->BoardSize &&
              checkerboard->BoardMap[Cur_row][Cur_col] == 0)
            {
              Empty_Num++;
              break;
            }
            else//超出棋盘或者是黑子
            {
              break;
            }
          }
          for (int k = 1; k <= 4; k++)//最多判断五个子,四个方向中单向的另一个方向
          {
            int Cur_row = row - i * k;
            int Cur_col = col - j * k;
            if (Cur_row >= 0 && Cur_row < checkerboard->BoardSize &&
              Cur_col >= 0 && Cur_col < checkerboard->BoardSize &&
              checkerboard->BoardMap[Cur_row][Cur_col] == CHESS_WHITE)
            {
              White_Num++;
            }
            else if (Cur_row >= 0 && Cur_row < checkerboard->BoardSize &&
              Cur_col >= 0 && Cur_col < checkerboard->BoardSize &&
              checkerboard->BoardMap[Cur_row][Cur_col] == 0)
            {
              Empty_Num++;
              break;
            }
            else//超出棋盘或者是黑子
            {
              break;
            }
          }
          //该位置的得分情况
          if (White_Num == 0)//1个白子
          {
            ScoreMap[row][col] += 5;
          }
          else if (White_Num == 1)//连续2个白子
          {
            
            ScoreMap[row][col] += 10;
            
          }
          else if (White_Num == 2)//连续3个白子
          {
            if (Empty_Num == 1)
            {
              ScoreMap[row][col] += 25;
            }
            else if (Empty_Num == 2)
            {
              ScoreMap[row][col] += 50;
            }
          }
          else if (White_Num == 3)//连续4个白子
          {
            if (Empty_Num == 1)
            {
              ScoreMap[row][col] += 55;
            }
            else if (Empty_Num == 2)
            {
              ScoreMap[row][col] += 300;
            }
          }
          else if (White_Num == 4)//连续5个白子
          {
            ScoreMap[row][col] += 30000;
          }
        }
      }
    }
}

6.3  选择权值最高的棋盘位置

6.3.1  AI.h

private:
ChessPos   MaxScore();

6.3.2  AI.cpp

ChessPos AI::MaxScore()
{
  int max = 0;
  vector<ChessPos> maxscore_pos;
  ChessPos pos;
  CalculateScore();
  for (int row = 0; row < checkerboard->BoardSize; row++)
  {
    for (int col = 0; col < checkerboard->BoardSize; col++)
    {
      if (ScoreMap[row][col] > max)
      {
        max = ScoreMap[row][col];
        maxscore_pos.clear();
        pos.row = row;
        pos.col = col;
        maxscore_pos.push_back(pos);
      }
      else if (ScoreMap[row][col] == max)
      {
        pos.row = row;
        pos.col = col;
        maxscore_pos.push_back(pos);
      }
    }
  }
  //计分棋盘归0
  for (int i = 0; i < checkerboard->ChessSize; i++)
  {
    for (int j = 0; j < checkerboard->ChessSize; j++)
    {
      ScoreMap[i][j] = 0;
    }
    
  }
  int index = rand() % maxscore_pos.size();
  return maxscore_pos[index];
}

6.4 AI下棋

6.4.1  AI.h

void go();

6.4.2  AI.cpp

void AI::go()
{
  ChessPos pos = MaxScore();
  checkerboard->PlayChess(pos, CHESS_WHITE);//白子下棋的位置(渲染和记录)
}

七、棋盘控制类实现

7.1 用棋盘控制类构造函数初始化

7.1.1 ChessGame.h

#include"chess_player.h"
#include"AI.h"
#include"checkerboard.h"
class ChessGame
{
public:
  ChessGame(chess_player& chess_player, AI& ai, checkerboard& checkerboard)//构造函数初始化
  {
    this->chess_player = &chess_player;
    this->ai = &ai;
    this->checkerboard = &checkerboard;
  }
  void play();//开始游戏
//创建数据成员变量
private:
  chess_player* chess_player;
  AI* ai;
  checkerboard* checkerboard;
};

7.2 控制游戏进行

7.2.1 ChessGame.h

void play();//开始游戏

7.2.2 ChessGame.cpp

//开始游戏
void ChessGame::play()
{
again:
  checkerboard->Init();
  while (1)
  {
    //棋手先走
    chess_player->go();
    if (checkerboard->CheckOver())
    {
      goto  again;
      
    }
    //AI走
    ai->go();
    if (checkerboard->CheckOver())
    {
      
      goto  again;
    }
  }
}

八、主函数

#include<iostream>
#include"ChessGame.h"
int main()
{
  srand((unsigned int)time(NULL));
  checkerboard checkerboard( 13, 45*0.7, 45*0.7,67.25*0.7);//自动调用构造函数
  chess_player chess_player(checkerboard);//自动调用构造函数
  AI ai(checkerboard);//自动调用构造函数;
  ChessGame chessgame(chess_player,ai, checkerboard);//引用传值
  
  chessgame.play();
  return 0;
  
}

完整代码及素材:

希望大家阅读完可以有所收获,同时也感谢各位铁汁们的支持。文章有任何问题可以在评论区留言,百题一定会认真阅读!

相关文章
|
2月前
|
存储 人工智能 C++
C++ 实现对战AI五子棋
C++ 实现对战AI五子棋
47 1
|
1月前
|
存储 人工智能 C++
【PTA】L1-064 估值一亿的AI核心代码(详C++)
【PTA】L1-064 估值一亿的AI核心代码(详C++)
16 1
|
2月前
|
人工智能 测试技术 开发工具
C++中的AI编程助手添加
Fitten Code是一款适用于多种编程环境,如VS Code和Visual Studio的AI编程助手插件。它能自动生成代码、提供实时建议和解决方案,帮助调试错误,支持80多种语言,包括Python、C++等。用户可以通过插件的智能补全功能提高编码速度,使用AI问答解决编程问题,还能生成代码注释、单元测试,检查和修复潜在的代码错误。Fitten Code是免费的,并且提供代码编辑和转换功能,增强开发效率。
33 1
|
2月前
|
存储 人工智能 C++
C++ 实现对战AI五子棋
C++ 实现对战AI五子棋
|
4天前
|
编译器 C++
【C++】string类的使用④(字符串操作String operations )
这篇博客探讨了C++ STL中`std::string`的几个关键操作,如`c_str()`和`data()`,它们分别返回指向字符串的const char*指针,前者保证以&#39;\0&#39;结尾,后者不保证。`get_allocator()`返回内存分配器,通常不直接使用。`copy()`函数用于将字符串部分复制到字符数组,不添加&#39;\0&#39;。`find()`和`rfind()`用于向前和向后搜索子串或字符。`npos`是string类中的一个常量,表示找不到匹配项时的返回值。博客通过实例展示了这些函数的用法。
|
4天前
|
存储 C++
【C++】string类的使用③(非成员函数重载Non-member function overloads)
这篇文章探讨了C++中`std::string`的`replace`和`swap`函数以及非成员函数重载。`replace`提供了多种方式替换字符串中的部分内容,包括使用字符串、子串、字符、字符数组和填充字符。`swap`函数用于交换两个`string`对象的内容,成员函数版本效率更高。非成员函数重载包括`operator+`实现字符串连接,关系运算符(如`==`, `&lt;`等)用于比较字符串,以及`swap`非成员函数。此外,还介绍了`getline`函数,用于按指定分隔符从输入流中读取字符串。文章强调了非成员函数在特定情况下的作用,并给出了多个示例代码。
|
9天前
|
C++
【C++】日期类Date(详解)②
- `-=`通过复用`+=`实现,`Date operator-(int day)`则通过创建副本并调用`-=`。 - 前置`++`和后置`++`同样使用重载,类似地,前置`--`和后置`--`也复用了`+=`和`-=1`。 - 比较运算符重载如`&gt;`, `==`, `&lt;`, `&lt;=`, `!=`,通常只需实现两个,其他可通过复合逻辑得出。 - `Date`减`Date`返回天数,通过迭代较小日期直到与较大日期相等,记录步数和符号。 ``` 这是236个字符的摘要,符合240字符以内的要求,涵盖了日期类中运算符重载的主要实现。
|
4天前
|
C++
【C++】string类的使用④(常量成员Member constants)
C++ `std::string` 的 `find_first_of`, `find_last_of`, `find_first_not_of`, `find_last_not_of` 函数分别用于从不同方向查找目标字符或子串。它们都返回匹配位置,未找到则返回 `npos`。`substr` 用于提取子字符串,`compare` 则提供更灵活的字符串比较。`npos` 是一个表示最大值的常量,用于标记未找到匹配的情况。示例代码展示了这些函数的实际应用,如替换元音、分割路径、查找非字母字符等。
|
4天前
|
C++
C++】string类的使用③(修改器Modifiers)
这篇博客探讨了C++ STL中`string`类的修改器和非成员函数重载。文章介绍了`operator+=`用于在字符串末尾追加内容,并展示了不同重载形式。`append`函数提供了更多追加选项,包括子串、字符数组、单个字符等。`push_back`和`pop_back`分别用于在末尾添加和移除一个字符。`assign`用于替换字符串内容,而`insert`允许在任意位置插入字符串或字符。最后,`erase`函数用于删除字符串中的部分内容。每个函数都配以代码示例和说明。
|
4天前
|
安全 编译器 C++
【C++】string类的使用②(元素获取Element access)
```markdown 探索C++ `string`方法:`clear()`保持容量不变使字符串变空;`empty()`检查长度是否为0;C++11的`shrink_to_fit()`尝试减少容量。`operator[]`和`at()`安全访问元素,越界时`at()`抛异常。`back()`和`front()`分别访问首尾元素。了解这些,轻松操作字符串!💡 ```