C++ 中国象棋的实现流程详解

中国象棋的中国棋文化,也是中华民族的文化瑰宝,它源远流长,趣味浓厚,基本规则简明易懂。中国象棋在中国的群众中基础远远超过围棋,是普及最广的棋类项目,中国象棋已流传到十几个国家和地区。 中国象棋使用方形格状棋盘,圆形棋子共有32个,红黑二色各有16个棋子,摆放和活动在交叉点上。双方交替行棋,先把对方的将(帅)“将死”的一方获胜。

我们今天就来看看我们自己能不能写出这样一个游戏呢?

今天就不话不多说了,先说一下,今天我们做的是一个简易版的单机中国象棋,希望大家理解,联网对弈的话需要用到的知识过多,数据库以及网络协议这些大部分同学都没有学,所以我们今天就简单的实现《中国象棋》的简单对弈,主要是希望同学们可以理解其中的逻辑关系,之后就可以更好的去完善

行吧,我们现在就开始吧!!!

今天先出场的就不是我们的老朋友结构体了,而是我们的新朋友枚举类型

enum Pieces //棋子
{
	NONE = -1,
	車, 馬, 象, 士, 将, 砲, 卒,
	俥, 马, 相, 仕, 帥, 炮, 兵,
	BEGIN, END,
};
//给id赋值
enum Pieces redChess[] = { 車, 馬, 象, 士, 将, 砲, 卒 };
enum Pieces blackChess[] = { 俥, 马, 相, 仕, 帥, 炮, 兵 };
//绘制时转化成字符串
const char* ChessName[] = { "車","馬","象","士","将","砲","卒","俥", "马", "相", "仕", "帥", "炮", "兵" };

接下来出场的是我们的老朋友结构体

//每一个棋子的属性
struct Chess
{
	enum Pieces id;		//棋子名称
	DWORD type;			//棋子类型,红?黑?
	short x;
	short y;
	bool  isRiver;			//是否过了河
};

//游戏地图
struct Chess map[ROW][COL];

struct State
{
	int begr;
	int begc;
	int endr;
	int endc;
	int state;
}state = {-1,-1,-1,-1,BEGIN};

我们的初始化函数,一定要想好其中的逻辑

//初始化数据
void init()
{
	//遍历地图
	for (size_t i = 0; i < ROW; i++)
	{
		size_t temp = 0;
		for (size_t k = 0; k < COL; k++)
		{
			map[i][k].id = NONE;	//先把棋子置为没有
			if (i <= 4)	//黑棋子
			{
				map[i][k].type = BLACK;
				if (i == 0)	//放置第一行的棋子
				{
				//0 1 2 3 4
				if (k <= 4)
				{
					temp = k;
				}
				// 3 2 1 0
				else
				{
					// k == 5
					temp = 4 - (k - 4);
					/*
					4 - (5-4)	//3
					4 - (6-4)	//2
					4 - (7-4)	//1
					4 - (8-4)	//0
					*/
				}
				map[i][k].id = blackChess[temp];
				}
				//设置炮
				if (i == 2 && (k == 1 || k == 7))
				{
					map[i][k].id = blackChess[5];
				}
				//设置兵
				if (i == 3 && k % 2 == 0)
				{
					map[i][k].id = blackChess[6];
				}
			}
			else       //红棋
			{
			map[i][k].type = RED;
			if (i == 9)	//放置第一行的棋子
			{
				//0 1 2 3 4
				if (k <= 4)
				{
					temp = k;
				}
				// 3 2 1 0
				else
				{
					// k == 5
					temp = 4 - (k - 4);
					/*
					4 - (5-4)	//3
					4 - (6-4)	//2
					4 - (7-4)	//1
					4 - (8-4)	//0
					*/
				}
				map[i][k].id = redChess[temp];
			}
			//设置炮
			if (i == 7 && (k == 1 || k == 7))
			{
				map[i][k].id = redChess[5];
			}
			//设置兵
			if (i == 6 && k % 2 == 0)
			{
				map[i][k].id = redChess[6];
			}
			}
			map[i][k].isRiver = false;
			map[i][k].x = k * GRID_SIZE + INTERVAL;
			map[i][k].y = i * GRID_SIZE + INTERVAL;
		}
	}
}

接下来是我们的绘制函数

//绘制
void draw()
{
	setfillcolor(RGB(252, 215, 162));
	setlinestyle(PS_SOLID, 2);
	//设置文字的样式
	settextstyle(30, 0, "楷体");
	for (size_t i = 0; i < ROW; i++)
	{
		for (size_t k = 0; k < COL; k++)
		{
			if (map[i][k].id == NONE)
				continue;
			settextcolor(map[i][k].type);
			setlinecolor(map[i][k].type);
			//绘制棋子
			fillcircle(map[i][k].x, map[i][k].y, 30);
			fillcircle(map[i][k].x, map[i][k].y, 25);
			outtextxy(map[i][k].x - 15, map[i][k].y - 15, ChessName[map[i][k].id]);
		}
	}
}

后面是我们的重点,鼠标控制函数,以后类似的游戏项目都会有这样的函数,好好理解

//鼠标操作
void mouseEvent()
{
	ExMessage msg;	//定义消息结构体变量
	if(peekmessage(&msg, EM_MOUSE))
	{
		if (msg.message == WM_LBUTTONDOWN)	//鼠标左键按下
		{
			//通过鼠标坐标得出点击的数组的下标
			//k * GRID_SIZE + INTERVAL = x;
			int col = (msg.x - INTERVAL) / GRID_SIZE;
			int row = (msg.y - INTERVAL) / GRID_SIZE;

			//下标校准
			if (msg.x > map[row][col].x + 30 && msg.y < map[row][col].y + 30)
			{
				col++;
			}
			if (msg.x < map[row][col].x + 30 && msg.y > map[row][col].y + 30)
			{
				row++;
			}
			if (msg.x > map[row][col].x + 30 && msg.y > map[row][col].y + 30)
			{
				row++;
				col++;
			}
			//printf("(%d %d)\n", row, col);

			if (state.state == BEGIN)
			{
				state.begr = row;
				state.begc = col;
				state.state = END;
			}
			else if (state.state == END)
			{
				state.endr = row;
				state.endc = col;
				state.state = BEGIN;
			}
			chessMove();
		}
	}
}

重点中的重点,棋子的移动函数,游戏的规则也就在这里体现出来

//移动棋子
void chessMove()
{
	printf("beg(%d %d) end(%d %d)\n", state.begr, state.begc, state.endr, state.endc);
	bool canMove = false;
	//什么情况下能够移动棋子
	if (!(state.begr == state.endr && state.begc == state.endc) &&	//点击的不是同一个棋子
		state.endr!=-1 && state.begr!=-1&&		//下标必须合法
		map[state.begr][state.begc].id != NONE//没有棋子不能移动
		/*&&map[state.begr][state.begc].type != map[state.endr][state.endc].type*/)	//不能自己吃自己
	{

		switch (map[state.begr][state.begc].id)
		{
		case 車:
		case 俥:
			if (state.begr == state.endr || state.begc == state.endc)
			{
				//起始点和结束点之间是否有阻碍
				if (hasBlock(&state))
				{
					canMove = true;
				}

			}
			break;
		case 馬:
		case 马:
			break;
		case 象:
		case 相:
			break;
		case 士:
		case 仕:
			break;
		case 将:
		case 帥:
			break;
		case 砲:
		case 炮:
			break;
		case 卒:
		case 兵:
			break;
		default:
			break;
		}
		if (canMove)
		{
			printf("canMove\n");
			map[state.endr][state.endc].id = map[state.begr][state.begc].id;
			map[state.begr][state.begc].id = NONE;

			map[state.endr][state.endc].isRiver = map[state.begr][state.begc].isRiver;
			map[state.endr][state.endc].type = map[state.begr][state.begc].type;
		}
	}
}

最后就是我们的主函数,进行调用,让项目运行起来

int main()
{
	//创建图形窗口
	initgraph(740, 820,EW_SHOWCONSOLE);
	//设置背景模式
	setbkmode(TRANSPARENT);
	//贴棋盘
	IMAGE img_board;
	loadimage(&img_board, "./res/ChessBoard.png");

	init();
	//双缓冲绘图,防止闪屏
	BeginBatchDraw();
	while (true)
	{
		cleardevice();
		putimage(0, 0, &img_board);
		draw();
		mouseEvent();

		FlushBatchDraw();
	}
	EndBatchDraw();

	getchar();
	return 0;
}

这样一个简易版的《中国象棋》游戏项目就解决啦,重点就是逻辑,一定要想清楚,想要实现联网的同学就要更加的去想清楚,以及去提高自己的能力,好啦,希望可以让大家从中感受到编程的快乐吧,也希望大家可以给UP主一个关注,非常感谢大家了!!!

到此这篇关于C++ 中国象棋的实现流程详解的文章就介绍到这了,更多相关C++ 中国象棋内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++实现鼠标控制的黑框象棋

    本文实例为大家分享了C++实现鼠标控制的黑框象棋的具体代码,供大家参考,具体内容如下 该象棋小游戏的特色 有颜色标注出 红方和绿方 可以用鼠标控制 颜色原理 直接调用用Windows自带的颜色API 用到了 颜色头文件.h 代码. //consolecolor.hpp这是着色的实现头文件 #pragma once #include<Windows.h>//调用win32API函数 #include<iostream>//调用flush成员函数,首先刷新缓冲区 namespace c

  • C++实现骑士走棋盘算法

    本文实例为大家分享了C++实现骑士走棋盘算法的具体代码,供大家参考,具体内容如下 1.问题描述 骑士旅游Knight tour在十八世纪初倍受数学家与拼图迷的注意,它什么时候被提出已不可考,骑士的走法为西洋 棋的走法,骑士可以由任一个位置出发,它要如何走完所有的位置. 2.基本思路 骑士的走法,基本上可以用递回来解决,但是纯粹的递回在维度大时相当没有效率,一个聪明的解法由J.CWarnsdorff 在1823年提出, 简单地说,先将最难的位置走完,接下来的路就宽广了,骑士所想要的下一步,为下一不

  • C++实现简易五子棋游戏

    C++实现的简易五子棋游戏,供大家参考,具体内容如下 三个函数: void menu():                    //菜单 int fun1(char a[21][43]):   //白旗 int fun2(char a[21][43]):   //黑棋 通过二维数组来实现棋盘与棋子. 构建棋盘: 直接通过一个二维字符数组来实现棋盘,只需cout即可.比较直观,但判断条件时过于繁杂.也可以使用二维整型数组,通过不同的整数来表示不同的字符,简化判断.cout时只需根据数组元素的类型

  • C++实现井字棋游戏

    本文实例为大家分享了C++实现井字棋游戏的具体代码,供大家参考,具体内容如下 初步实现双玩家输入,操作游戏. 下一步将实现人机博弈. #include<iostream> using namespace std; void Player1(void); //玩家1输入(操作)函数 void Player2(void); //玩家2输入(操作)函数 void game_judge(void); //输赢判断 void game_start(void); //游戏开始 int rows = 3,c

  • 基于C++和MFC开发象棋程序

    这是我要和大家分享的基于C++和MFC开发的一个象棋程序,目的是练习编程实践和大家分享同时希望大家能给出指教. 进入主题 一.棋盘分析 这是我绘制的棋盘,棋盘的组成由9条竖线和10条横线构成.这儿我们设置每条线间的间隔是50. 二.绘制过程 1.在vs中新建MFC程序,去除环境自动生成的按钮和文字. 2.打开***Dlg.cpp文件,在void CChessDlg::OnPaint()中定义一个棋盘间隔值和绘图设备CDC *cd = CWnd::GetDC(); int nWid = 50; C

  • C++ 中国象棋的实现流程详解

    中国象棋的中国棋文化,也是中华民族的文化瑰宝,它源远流长,趣味浓厚,基本规则简明易懂.中国象棋在中国的群众中基础远远超过围棋,是普及最广的棋类项目,中国象棋已流传到十几个国家和地区. 中国象棋使用方形格状棋盘,圆形棋子共有32个,红黑二色各有16个棋子,摆放和活动在交叉点上.双方交替行棋,先把对方的将(帅)"将死"的一方获胜. 我们今天就来看看我们自己能不能写出这样一个游戏呢? 今天就不话不多说了,先说一下,今天我们做的是一个简易版的单机中国象棋,希望大家理解,联网对弈的话需要用到的知

  • Redis Sentinel服务配置流程(详解)

    1.Redis Sentinel服务配置 1.1简介 Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务: 监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常. 提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过API 向管理员或者其他应用程序发送通知. 自动故障迁移(Automatic failover): 当一个主服务器不

  • 浅谈Python生成器generator之next和send的运行流程(详解)

    对于普通的生成器,第一个next调用,相当于启动生成器,会从生成器函数的第一行代码开始执行,直到第一次执行完yield语句(第4行)后,跳出生成器函数. 然后第二个next调用,进入生成器函数后,从yield语句的下一句语句(第5行)开始执行,然后重新运行到yield语句,执行后,跳出生成器函数,后面再次调用next,依次类推. 下面是一个列子: def consumer(): r = 'here' for i in xrange(3): yield r r = '200 OK'+ str(i)

  • java存储以及java对象创建的流程(详解)

    java存储: 1)寄存器:这是最快的存储区,位于处理器的内部.但是寄存器的数量有限,所以寄存器根据需求进行分配.我们不能直接进行操作. 2)堆栈:位于通用RAM中,可以通过堆栈指针从处理器那里获取直接支持.堆栈指针往下移动,则分配新的内存.网上移动,则释放内存.但是 在创建程序的时候必须知道存储在堆栈中的所有项的具体生命周期,以便上下的移动指针.一般存储基本类型和java对象引用. 3)堆:位于通用RAM中,存放所有的java对象,不需要知道具体的生命周期. 4)常量存储:常量值通常直接存放在

  • Android Bluetooth蓝牙技术使用流程详解

    在上篇文章给大家介绍了Android Bluetooth蓝牙技术初体验相关内容,感兴趣的朋友可以点击了解详情. 一:蓝牙设备之间的通信主要包括了四个步骤 设置蓝牙设备 寻找局域网内可能或者匹配的设备 连接设备 设备之间的数据传输 二:具体编程实现 1. 启动蓝牙功能 首先通过调用静态方法getDefaultAdapter()获取蓝牙适配器BluetoothAdapter,如果返回为空,则无法继续执行了.例如: BluetoothAdapter mBluetoothAdapter = Blueto

  • MVC+DAO设计模式下的设计流程详解

    DAO设计 : DAO层主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此,DAO层的设计首先是设计DAO的接口,然后在Spring的配置文件中定义此接口的实现类,然后就可在模块中调用此接口来进行数据业务的处理,而不用关心此接口的具体实现类是哪个类,显得结构非常清晰,DAO层的数据源配置,以及有关数据库连接的参数都在Spring的配置文件中进行配置. 在该层主要完成对象-关系映射的建立,通过这个映射,再通过访问业务对象即可实现对数据库的访问,使得开发中不必再用SQL语句编写复杂的

  • 微信小程序支付及退款流程详解

    首先说明一下,微信小程序支付的主要逻辑集中在后端,前端只需携带支付所需的数据请求后端接口然后根据返回结果做相应成功失败处理即可.我在后端使用的是php,当然在这篇博客里我不打算贴一堆代码来说明支付的具体实现,而主要会侧重于整个支付的流程和一些细节方面的东西.所以使用其他后端语言的朋友有需要也是可以看一下的.很多时候开发的需求和相应问题的解决真的要跳出语言语法层面,去从系统和流程的角度考虑.好的,也不说什么废话了.进入正题. 一. 支付 支付主要分为几个步骤: 前端携带支付需要的数据(商品id,购

  • Java代码生成器的制作流程详解

    1. 前言 前几天写了篇关于Mybatis Plus代码生成器的文章,不少同学私下问我这个代码生成器是如何运作的,为什么要用到一些模板引擎,所以今天来说明下代码生成器的流程. 2. 代码生成器的使用场景 我们在编码中存在很多样板代码,格式较为固定,结构随着项目的迭代也比较稳定,而且数量巨大,这种代码写多了也没有什么技术含量,在这种情况下代码生成器可以有效提高我们的效率,其它情况并不适于使用代码生成器. 3. 代码生成器的制作流程 首先我们要制作模板,把样板代码的固定格式抽出来.然后把动态属性绑定

  • IDEA社区版下载安装流程详解(小白篇)

    本人一直使用的是Eclipse作为开发工具的,不过现在IDEA非常的受推崇,所以决定上手试一试.网上有很多旗舰版的文章,我没有仔细看,我这次是决定使用社区版的IDEA,虽然功能会少一些,作为练手用完全够用了. IDEA官网地址:https://www.jetbrains.com/idea/download/ 下载社区版后,点击安装,就进行傻瓜式的安装了. 以上两个步骤中有一个点击next的时候时间会稍稍有点久,耐心等待一下就好了. 点击安装,IDEA社区版就安装完成了,安装好之后打开IDEA工具

  • 基于PHP的微信公众号的开发流程详解

    微信公众号开发分傻瓜模式和开发者模式两种,前者不要考虑调用某些接口,只要根据后台提示傻瓜式操作即可,适用于非专业开发人员. 开发模式当然就是懂程序开发的人员使用的. 下面简单说一下微信公众号开发的简易流程,新手看看会有帮助,高手请一笑而过. 1.配置服务器: A.首先在本机建立如下结构的文件夹(这里是我自己的习惯,仅供参考) MMPN:总目录mro message public number 微信公众号 backup:备份目录,主要用于备份php文件,每次修改时将原稿备份到里面去. images

随机推荐