C++ 实现对战AI五子棋

03-06 2802阅读 0评论

C++ 实现对战AI五子棋 第1张

 个人主页:日刷百题

系列专栏:〖C/C++小游戏〗〖Linux〗〖数据结构〗 〖C语言〗

🌎欢迎各位→点赞👍+收藏⭐️+留言📝 

C++ 实现对战AI五子棋 第2张

前言:

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

 一、项目效果展示


C++ 实现对战AI五子棋 第3张

 


二、游戏思路

C++ 实现对战AI五子棋 第4张

 


 

三、游戏框架

C++ 实现对战AI五子棋 第5张

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

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

四、棋盘类实现

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

4.1.1  checkerboard.h

#include//eaysx头文件
#include
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  

 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  

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 = margin_y && y = 0 && Cur_row BoardSize &&
							Cur_col >= 0 && Cur_col BoardSize &&
							checkerboard->BoardMap[Cur_row][Cur_col] ==0)
						{
							Empty_Num++;
							break;
						}
						else//超出棋盘或者是白子
						{
							break;
						}
					}
					for (int k = 1; k = 0 && Cur_row BoardSize &&
							Cur_col >= 0 && Cur_col BoardSize &&
							checkerboard->BoardMap[Cur_row][Cur_col] == CHESS_BLACK)
						{
							Black_Num++;
						}
						else if (Cur_row >= 0 && Cur_row BoardSize &&
							Cur_col >= 0 && Cur_col 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 = 0 && Cur_col BoardSize &&
							checkerboard->BoardMap[Cur_row][Cur_col] == CHESS_WHITE)
						{
							White_Num++;
						}
						else if (Cur_row >= 0 && Cur_row BoardSize &&
							Cur_col >= 0 && Cur_col BoardSize &&
							checkerboard->BoardMap[Cur_row][Cur_col] == 0)
						{
							Empty_Num++;
							break;
						}
						else//超出棋盘或者是黑子
						{
							break;
						}
					}
					for (int k = 1; k = 0 && Cur_row BoardSize &&
							Cur_col >= 0 && Cur_col BoardSize &&
							checkerboard->BoardMap[Cur_row][Cur_col] == CHESS_WHITE)
						{
							White_Num++;
						}
						else if (Cur_row >= 0 && Cur_row BoardSize &&
							Cur_col >= 0 && Cur_col 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 maxscore_pos;
	ChessPos pos;
	CalculateScore();
	for (int row = 0; row BoardSize; row++)
	{
		for (int col = 0; col 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 ChessSize; i++)
	{
		for (int j = 0; j 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
#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;
	
}

完整代码及素材:c和c++代码: 争取每日一更。。。。。。 - Gitee.comC++ 实现对战AI五子棋 第6张https://gitee.com/daily-brush-100-questions/c-language-training-camp/tree/master/c++AI%E4%BA%94%E5%AD%90%E6%A3%8B/c++AI%E4%BA%94%E5%AD%90%E6%A3%8B

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


免责声明
1、本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明。
2、本网站转载文章仅为传播更多信息之目的,凡在本网站出现的信息,均仅供参考。本网站将尽力确保所
提供信息的准确性及可靠性,但不保证信息的正确性和完整性,且不对因信息的不正确或遗漏导致的任何
损失或损害承担责任。
3、任何透过本网站网页而链接及得到的资讯、产品及服务,本网站概不负责,亦不负任何法律责任。
4、本网站所刊发、转载的文章,其版权均归原作者所有,如其他媒体、网站或个人从本网下载使用,请在
转载有关文章时务必尊重该文章的著作权,保留本网注明的“稿件来源”,并白负版权等法律责任。

手机扫描二维码访问

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
评论列表 (暂无评论,2802人围观)

还没有评论,来说两句吧...

目录[+]