五子棋图形化+ai人机玩法

该博客介绍了用C++实现的五子棋AI版代码。代码分为棋盘、棋手、AI、游戏运行管理四个板块,涉及多个头文件和源文件,如ai.h、man.h、chess.h、chessgame.h等。实现此代码需具备easy图形库软件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最终实现的效果展示

五子棋(ai版) 2024-01-14 15-28-35

目录

五子棋目录

ai

ai板块  ai.h

棋手板块

man.h

man.cpp

棋盘板块

chess.h

chess.cpp

游戏控制管理板块

chessgame.h

chessgame.cpp


本次代码实现要具备easy图形库软件

五子棋目录

分为四个板块,分别为

棋盘、棋手、ai、游戏运行管理

ai

ai板块  ai.h

#pragma once
#include "Chess.h"
#include<vector>//这个是用c++写向量要的
//对ai的设置
//要进行初始化,就是要告诉他棋盘大小以及棋子种类这种

//ai的思想就是,计算每个落子的位置的价值,哪个好下哪个
class AI
{
public:
	//初始化
	void init(Chess *chess );

	//下棋
	void go();

private:
	Chess* chess;
	//int data[13][13];
	vector<vector <int> > scoreMap; //

private:
	void calculateScore();//评分
	ChessPos think(); //ai思考



};

ai.cpp文件

#include "AI.h"
#include<vector>//这个是用c++写向量要的
//还有个跳三没处理

//AI的思考方式
/*
棋理格言:敌之好点,即我之好点。
就是说,每个点,都要考虑,如果敌方占领了这个点,会产生多大的价值,如果我方占领了这个点,又会产生多大的价值。
如果我方占领这个点,价值只有1000,但是敌方要是占领了这个点,价值有2000,而在自己在其它位置没有价值更高的点,
那么建议直接抢占这个敌方的好点。
*/
void AI::init(Chess* chess)
{
	this->chess = chess;  

	//初始化二维数组
	int size = 0;  //这里错误,void不能转为int 
	size=chess->getqipansize();   //这里getqipansize没有值
	for (int i = 0; i < 13; i++)//这里越界?
	{
		vector<int>row;
		for (int j = 0; j < 13; j++)
		{
			row.push_back(0);
		}
		scoreMap.push_back(row);  //搞明白这个row是和意义,好像是数组名吧对应上面那个
	}


}

//ai下棋
void AI::go()
{
	ChessPos pos = think();

	//ai 太快了,弄一个时间
	Sleep(1000);
	chess->chessDown(&pos, chess_white);
}

//计算评分
void AI::calculateScore()
{
	//棋手和ai分别有多少个连续的棋子
	int personNum = 0;//玩家连成子的个数
	int aiNum = 0;//ai连成子的个数
	int emptyNum = 0; //该方向上空白位的个数



	//先对评分向量数组清0,不道为啥,好像每次评分都要清,那清了我评啥
	//for (int i = 0; i < scoreMap.size(); i++)  //scoreMap.size()这个东西不道啥
	//{
	//	for (int j = 0; j < scoreMap[i].size(); j++)
	//	{
	//		scoreMap[i][j] = 0;
	//	}
	//}
	
	//清空评分数组
	for (int i = 0; i < 13; i++)  //scoreMap.size()这个东西不道啥
	{
		for (int j = 0; j < 13; j++)
		{
			scoreMap[i][j] = 0;
		}
	}


	//int size = chess->getqipansize();
	//进行评分计算
	//下面后进行优化,这就是数据结构的意义吧
 	int size = 13;
	for (int row = 0; row < size; row++)
	{
		for (int col = 0; col < size; col++)
		{
			//每次要进行清0计算才可以
			/*personNum = 0;
			aiNum = 0;
			emptyNum = 0;*/

			

			//对每个点进行计算,前提是为空才计算。
			if (chess->getChessData(row, col)  == 0)
			{
				
			//负1为左边,正1为右边,0为本身位置
			for (int y = -1; y <= 0; y++)
			{
				for (int x = -1; x <= 1; x++)
				{


					//八个方向改为4个方向
					if (y == 0 && x == 0)
						continue;
					if (y == 0 && x != 1)
						continue;

					//每个方向都初始化
					personNum = 0;
					aiNum = 0;
					emptyNum = 0; //该方向上空白位的个数




					if (!(y == 0 && x == 0))
					{


						//假设黑棋在该位置落子,会构成什么棋型
						//往前数四个
						for (int i = 1; i <= 4; i++)
						{
							int courRow = row + i * y;
							int courCol = col + i * x;

							//判断是否有笑范围
							if (courRow >= 0 && courRow < size && courCol >= 0 && courCol < size
								&& chess->getChessData(courRow, courCol) == 1)
							{
								personNum++; //黑棋连续棋子加1
							}


							//碰到空白和白棋都跳出去重新换个方向计算
							//空白
							else if (courRow >= 0 && courRow < size && courCol >= 0 && courCol < size
								&& chess->getChessData(courRow, courCol) == 0)
							{
								emptyNum++;
								break;
							}

							//白棋
							else
								break;

						}


						//也要求反方向的棋子是否连续
						for (int i = 1; i <= 4; i++)
						{
							int courRow = row - i * y;
							int courCol = col - i * x;

							//判断是否有笑范围
							if (courRow >= 0 && courRow < size && courCol >= 0 && courCol < size
								&& chess->getChessData(courRow, courCol) == 1)
							{
								personNum++; //黑棋连续棋子加1
							}


							//碰到空白和白棋都跳出去重新换个方向计算
							//空白
							else if (courRow >= 0 && courRow < size && courCol >= 0 && courCol < size
								&& chess->getChessData(courRow, courCol) == 0)
							{
								emptyNum++;
								break;
							}

							//白棋
							else
								break;

						}

						//上面计算好了棋型,下面进行评分
						//连二状态
						if (personNum == 1)
						{
							scoreMap[row][col] += 10;  //连二给10分 
						}

						//连三分为活三和死三
						else  if (personNum == 2)
						{
							if (emptyNum == 1) //一个空,说明是死三
							{
								scoreMap[row][col] += 30;  //30分
							}

							else if (emptyNum == 2) //两个空,说明是活三
							{
								scoreMap[row][col] += 40;
							}

						}

						//连四也分活四和死四
						else  if (personNum == 3)
						{
							if (emptyNum == 1) //一个空,说明是死四
							{
								scoreMap[row][col] += 60;  //30分
							}

							else if (emptyNum == 2) //两个空,说明是活四
							{
								scoreMap[row][col] += 200;
							}

						}

						//五子连珠
						else if (personNum == 4)
						{
							scoreMap[row][col] = 20000;
						}



						//假设白棋在该位置落子,会构成什么棋型
						//空白位置清0
						emptyNum = 0;
						//差不多的代码就能实现
						for (int i = 1; i <= 4; i++)
						{
							int courRow = row + i * y;
							int courCol = col + i * x;

							//判断是否有笑范围
							if (courRow > 0 && courRow < size && courCol > 0 && courCol < size
								&& chess->getChessData(courRow, courCol) == -1)
							{
								aiNum++; //白棋连续棋子加1
							}


							//碰到空白和白棋都跳出去重新换个方向计算
							//空白
							else if (courRow > 0 && courRow < size && courCol > 0 && courCol < size
								&& chess->getChessData(courRow, courCol) == 0)
							{
								emptyNum++;
								break;
							}

							//黑棋
							else
								break;

						}

						//白棋切换方向
						for (int i = 1; i <= 4; i++)
						{
							int courRow = row - i * y;
							int courCol = col - i * x;

							//判断是否有笑范围
							if (courRow > 0 && courRow < size && courCol > 0 && courCol < size
								&& chess->getChessData(courRow, courCol) == -1)
							{
								aiNum++; //白棋连续棋子加1
							}


							//碰到空白和白棋都跳出去重新换个方向计算
							//空白
							else if (courRow > 0 && courRow < size && courCol > 0 && courCol < size
								&& chess->getChessData(courRow, courCol) == 0)
							{
								emptyNum++;
								break;
							}

							//黑棋
							else
								break;

						}

						//判断白棋分数
						//上面计算好了棋型,下面进行评分

						if (aiNum == 0)
						{
							scoreMap[row][col] += 5;  //连1给5分 
						}

						//连二状态
						else if (aiNum == 1)
						{
							scoreMap[row][col] += 10;  //连二给10分 
						}

						//连三分为活三和死三
						else  if (aiNum == 2)
						{
							if (emptyNum == 1) //一个空,说明是死三
							{
								scoreMap[row][col] += 25;
							}

							else if (emptyNum == 2) //两个空,说明是活三
							{
								scoreMap[row][col] += 50;
							}

						}

						//连四也分活四和死四
						else  if (aiNum == 3)
						{
							if (emptyNum == 1) //一个空,说明是死四
							{
								scoreMap[row][col] += 55;  //30分
							}

							else if (emptyNum == 2) //两个空,说明是活四
							{
								scoreMap[row][col] += 10000;
							}

						}

						//五子连珠
						else if (aiNum >= 4)
						{
							scoreMap[row][col] += 30000; //这里居然写了 ==号
						}
					}

				}

				}
			}


		}
	}

	
}

//ai思考
ChessPos AI::think()
{
	//计算平均分
	calculateScore();
	//printf("11\n");
	/*int size = chess->getGradeSize();*/
	//int size = chess->getqipansize(); //这个取值,不道为啥报错
	//int size = scoreMap.size(); //这个取值,不道为啥报错
	
	//防止出现有多个最大评分,那只能随机了
	vector<ChessPos> maxPoints; //创建一个数组存放那个最大的评分多个
	//搞半天原来是这个玩意搞坏了我的初始化,size
	int size = 13;
	int maxScore = 0;
	//取最大的评分
	for (int row = 0; row < size; row++)
	{
		for (int col = 0; col < size; col++)
		{
			if (chess->getChessData(row, col) == 0)
			{
				if (scoreMap[row][col] > maxScore)
				{
					maxScore = scoreMap[row][col];
					maxPoints.clear();  //清空
					maxPoints.push_back(ChessPos(row, col));
				}
				else if (scoreMap[row][col] == maxScore)
				{
					maxPoints.push_back(ChessPos(row, col));
				}

			}
		}
	}

	int index = rand() % maxPoints.size();  //bug1,求余的为0;
	return maxPoints[index];  //取得的最大的评分
}

棋手板块

man.h

#pragma once
#include"Chess.h"
#include<vector>//这个是用c++写向量要的
class Man
{
public:
	//初始化
	void init(Chess* chess);

	//下棋
	void go();

	//为了调用棋盘,用指针指向,得到关系能调用就行
private:
	Chess* chess;

};

man.cpp

#include "Man.h"
#include"Chess.h"
#include<vector>//这个是用c++写向量要的
//这个的初始化放在游戏控制那里进行
//这个错误很难受,居然没有那个:号就会错误
void Man::init(Chess* chess)
{
	this->chess = chess;
}

//棋手下棋,鼠标点哪里我走哪里
void Man::go()
{
	//定义鼠标变量
	MOUSEMSG msg;
	ChessPos pos;
	
	

	//要解决不小心点到外面,或者点到格子里面
	//通过chess对象,来调用判断落子是否有效,以及落子的功能
	//检测是否左点击和范围是否有效
	while (1)
	{
		//获取鼠标点击信息3
		msg = GetMouseMsg();


		//这里有问题

		if (msg.uMsg == WM_LBUTTONDOWN && chess->clickBoard(msg.x,msg.y,&pos)) //这里不出选择,我很慌
		{
			/*printf("有效\n");*/
			printf("%d,%d\n",msg.x,msg.y);
				break;
		}
	}

	printf("%d,%d\n", pos.row, pos.col);
	//落子

	chess->chessDown(&pos,chess_black );//黑棋掀开 kind种类

}

棋盘板块

chess.h

#pragma once
#include<graphics.h>
#include<vector>//这个是用c++写向量要的
using namespace std;//这叫命名空间
//先大概做好要实现什么 功能,后面再慢慢实现。
//棋子功能
//用来落子
//想到什么先写好什么

//表示落子的位置坐标
struct ChessPos {
	int row;
	int col;

	ChessPos(int r=0 ,int c=0):row(r),col(c){}  //这个是用在存放最大评分数组用的,不道啥意思
};

//定义棋子总类
typedef enum {
	chess_white = -1,//白棋
	chess_black = 1
}chess_kind;  //kind总类 chess棋子

class Chess
{
	//好像c++规定要写这个才能不会报错
	//public表明该数据成员、成员函数是对所有用户开放的,所有用户都可以直接进行调用
	//如果不加,好像mian会调用不了,属于私人,加了就可以所有对外调用
public:
	//Chess(int gradSize, int marginX, int marginY, float chessSize);

	Chess(int gradSize, int marginX, int marginY, int chessSize);

	//初始化
	void init();

	//判断鼠标落子位置,然后符合的话返回坐标再落子
	bool clickBoard(int x, int y, ChessPos* pos);//成功则保存到结构体pos里面

	//实现落子
	void chessDown(ChessPos *pos, chess_kind kind);//val  ChessPos *pos这个应该是给结构体命名传参吧,后面可以直接引用

	

	//获取棋盘大小
	int  getqipansize();

	// 获取指定位置是黑棋,还是白棋,还是空白
	int getChessData(ChessPos* pos);
	int getChessData(int row, int col);

	//检查棋局是否结束
	bool checkover();

	//开始弄资源图片的加载

	//在棋盘类做好初始定义内容
private:
	IMAGE chessBlackimg;//黑棋棋子
	IMAGE chessWhiteimg;//白棋棋子

	//定义棋盘的大小
	int gradeSize;
	//定义距离棋盘的大小宽度和长度
	int margin_x;//棋盘的左侧边界
	int margin_y;//棋盘的顶部边界 margin 范围,边缘

	//定义棋子的大小
	int chessSize;//棋子的大小(棋盘小方格的长宽跟棋子的直径一样大嘛)

	//做一个数组存放已经落子的数据,就可以知道哪里不能下了
	//c写法,但由于不能改变只能固定,然后就只能采用c++里面的可以改变的写法
	//int chessMap[20][20];  //后面我要用c来改

	//c++写法
	//chessmap[3][5] 表示棋盘的第3行第五列的落子情况 0为空白,黑子为1,白字为-1
	vector<vector<int>> chessMap;

	//表示现在该谁下棋
	bool playerFlag;  //true 黑子走,false 白子走

	void uppdateGameMap(ChessPos* pos);

	bool chekWin();  //检查输赢,返回true为真,否则假

	ChessPos lastPos; //最近落子点的位置


};

chess.cpp

#include "Chess.h"
#include<math.h>//求根号头文件
#include<graphics.h>
#include<conio.h>//暂停函数
#include<mmsystem.h>//音乐头文件
#pragma comment(lib,"winmm.lib")//音乐播放功能
//怎么播放一个音乐直到结束呢


//提升ai强大的方法就是
// 要对ai进行跳三跳四的判断
//再强大就是对黑棋进行禁手了

//解决图片背景透明化
void putimagePNG(int x, int y, IMAGE* picture) //x为载入图片的X坐标,y为Y坐标
{
    // 变量初始化
    DWORD* dst = GetImageBuffer();    // GetImageBuffer()函数,用于获取绘图设备的显存指针,EASYX自带
    DWORD* draw = GetImageBuffer();
    DWORD* src = GetImageBuffer(picture); //获取picture的显存指针
    int picture_width = picture->getwidth(); //获取picture的宽度,EASYX自带
    int picture_height = picture->getheight(); //获取picture的高度,EASYX自带
    int graphWidth = getwidth();       //获取绘图区的宽度,EASYX自带
    int graphHeight = getheight();     //获取绘图区的高度,EASYX自带
    int dstX = 0;    //在显存里像素的角标

    // 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算
    for (int iy = 0; iy < picture_height; iy++)
    {
        for (int ix = 0; ix < picture_width; ix++)
        {
            int srcX = ix + iy * picture_width; //在显存里像素的角标
            int sa = ((src[srcX] & 0xff000000) >> 24); //0xAArrggbb;AA是透明度
            int sr = ((src[srcX] & 0xff0000) >> 16); //获取RGB里的R
            int sg = ((src[srcX] & 0xff00) >> 8);   //G
            int sb = src[srcX] & 0xff;              //B
            if (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight)
            {
                dstX = (ix + x) + (iy + y) * graphWidth; //在显存里像素的角标
                int dr = ((dst[dstX] & 0xff0000) >> 16);
                int dg = ((dst[dstX] & 0xff00) >> 8);
                int db = dst[dstX] & 0xff;
                draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16)  //公式: Cp=αp*FP+(1-αp)*BP  ; αp=sa/255 , FP=sr , BP=dr
                    | ((sg * sa / 255 + dg * (255 - sa) / 255) << 8)         //αp=sa/255 , FP=sg , BP=dg
                    | (sb * sa / 255 + db * (255 - sa) / 255);              //αp=sa/255 , FP=sb , BP=db
            }
        }
    }
}

//初始化棋盘
Chess::Chess(int gradSize, int marginX, int marginY, int chessSize)
{
    this->gradeSize = gradeSize;
    this->margin_x = marginX;
    this->margin_y = marginY;
    this->chessSize = chessSize;
    playerFlag = chess_black; //黑棋

    //初始化数组
    //真没看懂下面的操作
    for (int i = 0; i < 13; i++)
    {
        //每次搞一行
        vector<int>row; //这里创建一行,下面直接填充这一行数据为0
        for (int j = 0; j < 13; j++)
        {
            row.push_back(0);  //push_back() 在Vector最后添加一个元素(参数为要插入的值)
            //相当于在弄数组的初始化,全部填充为0;
        }
        //在尾部追加一行,为啥呢作用,没太懂这行
        chessMap.push_back(row);

    }


}

IMAGE image1;

//在这里开始绘制游戏窗口界面
void Chess::init()
{
    //创建游戏窗口
    //这个的大小根据棋盘大小来创建
    initgraph(897, 895,EW_SHOWCONSOLE);   //graph 意思为图表 显示控制台

    loadimage(0, "res/menu.png");
    //586 754
   
    //显示开始游戏
    loadimage(&image1, "res/1.png");
    putimage(611, 776, &image1);

    MOUSEMSG msg;
    while (1)
    {
        msg = GetMouseMsg();
    
    if (msg.uMsg == WM_LBUTTONDOWN)
    {
        //显示棋盘
        //加载图片  scanf
        loadimage(0, "res/棋盘2.jpg");
        //播放游戏开始音乐,要加头文件
        mciSendString("play res/start.wav", 0, 0, 0);
        break;
    }

    }
    //加载黑棋和白棋的图片到棋子变量里面存放好
    //去边角才行,改为透明图片
    loadimage(&chessBlackimg, "res/black.png",chessSize,chessSize,true);//在这里,棋子图片太大了83*83,所以加载进来的时候要跟方格的尺寸一样才行
    loadimage(&chessWhiteimg, "res/white.png",chessSize,chessSize,true);

    //给棋盘数组初始化清空
    //这里数组为0
    /*for (int i = 0; i < gradeSize; i++)
    {
        for (int j = 0; j < gradeSize; j++)
        {
            chessMap[i][j] = 0;
        }
    }*/


    //给棋盘数组初始化清空
    //这里数组为0
    for (int i = 0; i < 13; i++)
    {
        for (int j = 0; j < 13; j++)
        {
            chessMap[i][j] = 0;
        }
    }
    
    
    //定义棋子一开始为黑棋
    playerFlag = true;//



}


//这里判断有效点击,x,y为鼠标点的坐标
bool Chess::clickBoard(int x, int y, ChessPos* pos)
{

    //先求鼠标在的行和列数
    //思路画图,就可以知道,x长度减去边界长度,然后除以格子的长度就可以知道x的坐标了
    //类型记得用int 这样就会取整
    int col = (x - margin_x) / chessSize;//列数
    int row = (y - margin_y) / chessSize;//行数
    //求左上角的坐标
    int leftTopPosX = margin_x + chessSize * col;
    int leftTopPosY = margin_y + chessSize * row;

    //设置一个误差,就是不小心点到方格里面偏离了一些,这个参数
    int offset = chessSize * 0.5;  //我取一半吧

    //求鼠标的坐标的位置离中心的距离
    //int  len; //这个要开根号,我觉得为了精确要改为float 或者double吧
    int len;
    //len = sqrt((x - leftTopPosX) * (x - leftTopPosX) + (y - leftTopPosY) * (y - leftTopPosY));  //直角三角形里面的求斜边玩法


    //这里用int?
    int ret = false;
    //bool ret = false;  //在这里设置一个标志
    //下面的就是进行判断,他在哪个中心
    //拿误差来比较
    //得出准确的落棋位置
    //在这个之后要提前知道是否为空,若有棋子就不用下棋了
    
    //要判断他要落子在四个角是哪个角
    do
    {
        //这个居然放在里面
        len = sqrt((x - leftTopPosX) * (x - leftTopPosX) + (y - leftTopPosY) * (y - leftTopPosY));  //直角三角形里面的求斜边玩法

        if (len < offset)
        {
            pos->row = row;
            pos->col = col;

            if (chessMap[pos->row][pos->col] == 0)
            {
                ret = true;
            }
            break;

        }

        //右上角判断
        int x2 = leftTopPosX + chessSize;
        int y2 = leftTopPosY;

        len = sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2));
        if (len < offset)
        {
            pos->row = row;
            pos->col = col+1;  //行不变,列要加1

            if (chessMap[pos->row][pos->col] == 0)
            {
                ret = true;
            }
            break;

        }

        //左下角判断
         x2 = leftTopPosX ;
         y2 = leftTopPosY + chessSize;

        len = sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2));
        if (len < offset)
        {
            pos->row = row+1 ;//列不变,行要加1
            pos->col = col;  

            if (chessMap[pos->row][pos->col] == 0)
            {
                ret = true;
            }
            break;

        }

        //右下角判断
         x2 = leftTopPosX + chessSize;
         y2 = leftTopPosY + chessSize;

        len = sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2));
        if (len < offset)
        {
            pos->row = row + 1;//列不变,行要加1
            pos->col = col + 1;

            if (chessMap[pos->row][pos->col] == 0)
            {
                ret = true;
            }
            break;

        }


    } while (0);
    
    return ret;

}

//下棋他来了
//终于知道一个bug玩法了
//就是绘制棋子的坐标时候不能写中心坐标呀,因为绘制的话是从左上角坐标绘制的
//所以呢,我要写的坐标,写的是本来的坐标减去半个方格的长度,宽度也是。
void Chess::chessDown(ChessPos* pos, chess_kind kind)
{
    mciSendString("play res/down7.WAV", 0, 0, 0);
    int x = (margin_x + chessSize * pos->col) - (0.5 * chessSize);
    int y = (margin_y + chessSize * pos->row) - (0.5 * chessSize);

    if (kind == chess_white)
    {
        putimagePNG(x, y, &chessWhiteimg); //输出棋子
        

    }
    else
    {
        //putimage(x, y, &chessBlackimg);
        putimagePNG(x, y, &chessBlackimg);
    }

    //放入更新函数
    uppdateGameMap(pos);

}



int Chess::getChessData(ChessPos* pos)
{
    return  chessMap[pos->row][pos->col];
}

int Chess::getChessData(int row, int col)
{
    return  chessMap[row][col];
}

//棋盘大小
int  Chess::getqipansize()
{
    return gradeSize;
}

//判断是否结束
bool Chess::checkover()
{
    //输赢要显示出
   // printf("11");
    if (chekWin()== true)
    {
        Sleep(2000);
        if (playerFlag == false)
        {
            //false说明最后一步是棋手,也就是胜利者
            mciSendString("play res/不错.mp3", 0, 0, 0);
            loadimage(0, "res/胜利.jpg");
            MessageBox(GetHWnd(), "你赢了", "温馨提醒", MB_OK);//消息盒子,对话框函数
            Sleep(500);
            //mciSendString("play ./稻香 - 周杰伦.320.mp3", NULL, 0, NULL);
        }
        else 
        {
            //false说明最后一步是棋手,也就是胜利者
            mciSendString("play res/失败.mp3", 0, 0, 0);
            loadimage(0, "res/失败.jpg");
            MessageBox(GetHWnd(), "你输了", "温馨提醒", MB_OK);//消息盒子,对话框函数
            Sleep(500);
            //mciSendString("play ./稻香 - 周杰伦.320.mp3", NULL, 0, NULL);

        }

        //暂停键
        //_getch();  //按任意键
        return true;
    }
    //暂停键
   // _getch();  //按任意键
    return false;
    
}


//每次更改棋盘的数据
void Chess::uppdateGameMap(ChessPos* pos)
{
    lastPos = *pos;  //获取最新的落子位置
    chessMap[pos->row][pos->col] = playerFlag ? chess_black : chess_white;  //三目运算符
    playerFlag = !playerFlag;  //棋子的切换

}

//判断五子连珠
bool Chess::chekWin()
{
    //判断落子点的周围四个方向即可
    //落子坐标
    int row = lastPos.row;
    int col = lastPos.col;

    //落子点的水平方向
    for (int i = 0; i < 5; i++)
    {
        //最左到最有往右移动
        //要注意防止越界
        if (col - i >= 0 && col - i + 4 < 13 &&
            chessMap[row][col - i] == chessMap[row][col - i + 1] &&
            chessMap[row][col - i] == chessMap[row][col - i + 2] &&
            chessMap[row][col - i] == chessMap[row][col - i + 3] &&
            chessMap[row][col - i] == chessMap[row][col - i + 4] )
        {
            return true;
        }

    }

    //落子点的垂直方向
    for (int i = 0; i < 5; i++)
    {
        //最左到最有往右移动
        //要注意防止越界
        if (row - i >= 0 && row - i + 4 < 13 &&
            chessMap[row-i][col] == chessMap[row - i + 1][col ] &&
            chessMap[row - i][col] == chessMap[row - i + 2][col] &&
            chessMap[row - i][col] == chessMap[row - i + 3][col] &&
            chessMap[row - i][col] == chessMap[row - i + 4][col] )
        {
            return true;
        }

    }

    //左下方到右上方  /
    for (int i = 0; i < 5; i++)
    {
        if (row + i < 13 && row + i - 4 >= 0 &&
            col - i >= 0 && col - i + 4 < 13 &&
            chessMap[row + i][col - i] == chessMap[row + i - 1][col - i + 1] &&
            chessMap[row + i][col - i] == chessMap[row + i - 2][col - i + 2] &&
            chessMap[row + i][col - i] == chessMap[row + i - 3][col - i + 3] &&
            chessMap[row + i][col - i] == chessMap[row + i - 4][col - i + 4])
        {
            return true;
        }
    }


    //这里有问题
    //'\'下方到右上方
    for (int i = 0; i < 5; i++)
    {
        if (col - i >= 0 && row - i + 4 < 13 &&
            row - i >= 0 && col - i + 4 < 13 &&
            chessMap[row - i][col - i] == chessMap[row - i + 1][col - i + 1] &&
            chessMap[row - i][col - i] == chessMap[row - i + 2][col - i + 2] &&
            chessMap[row - i][col - i] == chessMap[row - i + 3][col - i + 3] &&
            chessMap[row - i][col - i] == chessMap[row - i + 4][col - i + 4])
        {
            return true;
        }
    }



    return false;
}

游戏控制管理板块

chessgame.h

#pragma once
#include"AI.h"
#include"Chess.h"
#include"Man.h"
#include<vector>//这个是用c++写向量要的
//游戏控制
class ChessGame
{
public:
	//开始对局这个不同
	ChessGame(Man *man,AI *ai,Chess *chess);

	void play();//有一把刷子按住ctrl可以进行创建,就可以方便切换了


	//private表示私有,私有的意思就是除了class自己之外
	//任何人都不可以直接使用,私有财产神圣不可侵犯嘛,即便是子女,朋友,都不可以使用。
	
	//添加数据成员
	//下面这些定义好像跟结构体差不多
private:
	Man* man;
	AI* ai;
	Chess* chess;
};

chessgame.cpp

#include "ChessGame.h"
#include<vector>//这个是用c++写向量要的

ChessGame::ChessGame(Man* man, AI* ai, Chess* chess)
{
	//this是一个变量 ,一个引用。
	//this保存的就是当前对象的地址,指向对象本身,即this代表的就是“当前对象”。
	//初始化
	this->man  = man;
	this->ai   = ai;
	this->chess= chess;
	
	man->init(chess);
	ai->init(chess);


}

//对局开始(开始玩)
void ChessGame::play()
{
	//下之前要对游戏界面棋盘啥的资源加载初始化
	chess->init();

	//思路
	//先确定谁先走,人先走,电脑后
	//走一步判断一步是否结束
	//如果结束了那就继续下一把
	while (1)
	{
		//棋手走
		man->go();

	
		//判断是否结束
		if (chess->checkover())
		{
			printf("11\n");
			chess->init();//如果结束那就重新初始化。这个初始化每次也需要把存棋子的数组给初始化
			continue;//这个意思就是如果结束了然后返回去继续玩。
		}

		//这里就断了
		//ai走
		


		ai->go();        //ai挂了跑不起来
		//printf("电脑你快下,不下就是挂了\n");
		//判断是否结束
		if (chess->checkover())
		{
			//system("pause");
			
			chess->init();
			continue;
		}
	}
}

到此就结束了,有问题可以留言哈。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值