【C++】C++下的简易中国象棋

news/2024/11/7 21:34:18/

参考自Originum学长的博客,个人进行了一些小修改,
原博客地址:https://blog.csdn.net/Originum/article/details/80356452
联系邮箱:Originum@126.com

本人博客地址:Megalomania

一个简单的中国象棋游戏,主要实现:
1、两人对弈;
2、简单的棋子移动以及规则判断,不符合规则便重走;
3、有一方获胜便结束游戏。

一、类的设计

  1. “Chess”类:
    (1) 私有成员有int型的Id,用于记录棋子的归属以及判断轮到的玩家是否可以移动;
    (2) 公共成员函数有Get函数来获取Id,以及判断走法是否正确的Judgement纯虚函数;
    (3) 作为基类来派生出其他棋子的类。

具体代码如下:

class Chess
{
private:int Id;
public:Chess(int x) :Id(x) {}int Get()                //取ID{return Id;}virtual bool Judgement(Chessboard& ch, int startx, int starty, int endx, int endy) = 0;//判断走步合理性virtual ~Chess() {}
};
  1. “Chessboard”类:
    (1) 私有成员有一个10*11的指向Chess类的指针(为了方便操作将0的位置腾了出来),用于存放棋子的地址;
    (2) 还有一个Char型的Chessword数组用于存放棋子的名字(一个汉字占4个Char型空间);
    (3) 公共成员部分有static int型的 Player用于记录轮到哪个玩家以及哪个玩家获胜。

具体实现代码如下:

class Chessboard
{
private:Chess *c[10][11];        //棋盘:X为横(9),Y为纵(10),从1开始记char Chessword[15][4] = { "兵","炮","车","马","相","仕","帅"," ","将","士","象","馬","車","砲","卒" };
public:static int Player;       //上半区为1,下半区为-1static bool End;         //判断是否结束Chessboard();Chess *Get(int x, int y);//返回指定点的指针int Getid(int x, int y);//返回指定点处棋子ID的指针bool Move(int startx, int starty, int endx, int endy);	//移动void Init();               //初始化棋子void Show();               //打印void Play();               //开始游戏~Chessboard();
};

二、具体变量的意义

红方棋子:“兵”,“炮”,“车”,“马”,“相”,“仕”,“帅”
Id为:7 6 5 4 3 2 1
绿方棋子:“将”,“士”,“象”,“馬”,“車”,“砲”,“卒”
Id为:-1 -2 - 3 -4 -5 -6 -7

用于实现移动的变量:
startx,starty: 开始的位置;
endx,endy:目标的位置;
S_Id: 存储开始位置的棋子的编号,若该点没有棋子(空指针),则值为0;
E_Id: 存储目标位置的棋子的编号,若该点没有棋子(空指针),则值为0;
TempX: 开始位置到目标位置的x坐标的偏移量(startx-endx);
TempY: 开始位置到目标位置的y坐标的偏移量(starty-endy)。

三、实现走棋

每次把位置信息传到Chessboard类的Move()函数时,会判断:

  1. 传入的两个位置是否越界(超出了10*11数组的范围),越界则返回false。
  2. 传入的开始位置的点的id是否为零(当点上无棋子,也就是空指针的时候为零),若为零则返回false。
  3. 当前选的棋子是否是这一回对应那一方的棋子,若不是则返回false。
  4. 对当前棋子的具体规则进行判断(通过指针调用虚函数,判断该棋子的具体规则)。若错误则返回false。

若以上判断都准确无误,则把棋子走到对应位置:

  1. 不吃子:目标位置为空指针时,把目标位置的指针指向该棋子对象,把棋子的起始位置指针赋值NULL,设为空指针。
  2. 吃子:delete目标位置的棋子对象,该棋子被吃。把目标位置的指针指向该棋子对象,把棋子的起始位置指针赋值NULL,设为空指针。

四、判断结束

判断结束:

  1. 棋盘类有一个静态变量bool End, 初始化为true。当将(帅)对象被析构时,把end赋值为false,表示棋局结束,退出走棋的循环(while(chessboard :: end)控制走棋是否继续)。
~General(){Chessboard::End = false;}
  1. 当有一位玩家的某一步棋使双方的将(帅)面对面时,直接判负。具体实现是检测将(帅)所在的4、5、6 三列中将和帅是否在同一类且两者间的指针为全为空指针;
int ifalg = 0;
for (int i = 4; i < 7; i++){for (int j = 1; j < 11; j++){if (c[i][j] != NULL){if ((int)fabs(c[i][j]->Get()) == 1){iflag++;}else if (iflag != 0 && iflag != 2){if ((int)fabs(c[i][j]->Get()) != 1){iflag--;}}}}}if (iflag == 2){Player *= -1;Chessboard::End = false;}

输出胜利的一方的信息:
棋盘类有一个静态变量int player,初始化为-1,每走棋一次乘以-1,在1与-1之间交替表示棋手的轮流下棋。以此来鉴别胜利的是哪一方

五、某些棋子的规则算法

  1. 判断目标点是否是己方的棋:两方的子的Id互为相反数,所以只有当S_Id* E_Id>0时表示目标位置是己方的子,不能走。因而只有满足S_Id*E_Id<=0才是合法条件(空位置为0)。

  2. 判断是否满足只能走1格,或马走日,象走田的条件时,只需要区偏移的距离进行判断。例如TempX*TempX+TempY+TempY表示偏移量的平方,当该值为1时,表示只走了任意方向的一格;当值为2时,表示士的斜走;值为5时,表示马走日;为8时,表示象走田。

  3. 判断马走日的蹩脚马时,用数学计算方法,可以归纳出只需判断(X+TempX/2,Y+TempY/2)位置是否有子便可。而判断塞象时,只用判段(X+TempX/2,Y+TempY/2)的位置是否有子即可。

  4. 判断将(帅)和士是否在3*3的营里只需看其坐标是否在(endx >= 4 && endx <= 6) && (endy >= 1 && endy <= 3 || endy >= 8 && endy <= 10)中。

六、棋盘的背景颜色以及棋子的颜色更改和每步的刷新棋盘

  1. 刷新棋盘很简单,只需在每次的Show()之前加函数如下即可
system("cls");
  1. 棋盘及棋子颜色由windows.h头文件中的函数实现,具体如下
#include<windows.h>HANDLE handle;handle = GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleTextAttribute(handle, 0xFC);

其中0xFC中F为字体的背景色,C为字体色;只有如0xF这种情况只改字体颜色!!!切记!!!!
附上颜色表:

0 = 黑色8 = 灰色
1 = 蓝色9 = 淡蓝色
2 = 绿色A = 淡绿色
3 = 浅绿色B = 淡浅绿色
4 = 红色C = 淡红色
5 = 紫色D = 淡紫色
6 = 黄色E = 淡黄色
7 = 白色F = 亮白色

PS:附上完整代码

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<windows.h>
#include<cmath>
using namespace std;
class Chessboard;
class Chess
{
private:int Id;
public:Chess(int x) :Id(x) {}int Get()                //取ID{return Id;}virtual bool Judgement(Chessboard& ch, int startx, int starty, int endx, int endy) = 0;//判断走步合理性virtual ~Chess() {}
};
class Chessboard
{
private:Chess *c[10][11];        //棋盘:X为横(9),Y为纵(10),从1开始记char Chessword[15][4] = { "兵","炮","车","马","相","仕","帅"," ","将","士","象","馬","車","砲","卒" };
public:static int Player;       //上半区为1,下半区为-1static bool End;         //判断是否结束Chessboard();Chess *Get(int x, int y);//返回指定点的指针int Getid(int x, int y);//返回指定点处棋子ID的指针bool Move(int startx, int starty, int endx, int endy);	//移动void Init();               //初始化棋子void Show();               //打印void Play();               //开始游戏~Chessboard();
};
class General :public Chess//将、帅类,ID为-1和1
{
public:General(int i) :Chess((i == 0 ? -1 : 1)) {}bool Judgement(Chessboard& ch, int startx, int starty, int endx, int endy){int TempX = startx - endx;int TempY = starty - endy;int S_Id = ch.Getid(startx, starty);int E_Id = ch.Getid(endx, endy);if ((S_Id*E_Id <= 0) && (TempX*TempX + TempY * TempY == 1) && (endx >= 4 && endx <= 6) && (endy >= 1 && endy <= 3 || endy >= 8 && endy <= 10)){return true;}return false;}~General(){Chessboard::End = false;}
};
class BodyGuard :public Chess//士、仕类,ID为-2和2
{
public:BodyGuard(int i) :Chess((i == 0 ? -2 : 2)) {}bool Judgement(Chessboard& ch, int startx, int starty, int endx, int endy){int TempX = startx - endx;int TempY = starty - endy;int S_Id = ch.Getid(startx, starty);int E_Id = ch.Getid(endx, endy);if ((S_Id*E_Id <= 0) && (TempX*TempX + TempY * TempY == 2) && (endx >= 4 && endx <= 6) && (endy >= 1 && endy <= 3 || endy >= 8 && endy <= 10)){return true;}return false;}
};
class Chancellor :public Chess//象、相类,ID为-3和3
{
public:Chancellor(int i) :Chess((i == 0 ? -3 : 3)) {}bool Judgement(Chessboard& ch, int startx, int starty, int endx, int endy){int TempX = startx - endx;int TempY = starty - endy;int S_Id = ch.Getid(startx, starty);int E_Id = ch.Getid(endx, endy);if ((S_Id*E_Id <= 0) && (TempX*TempX + TempY * TempY == 8) && (endx % 2 != 0 && endx >= 1 && endy <= 9) && ((starty - 1) / 5 == (endy - 1) / 5) && !ch.Get(startx + (TempX / 2), starty + (TempY / 2))){return true;}return false;}
};
class Horse :public Chess//馬、马类,ID为-4和4
{
public:Horse(int i) :Chess((i == 0 ? -4 : 4)) {}bool Judgement(Chessboard& ch, int startx, int starty, int endx, int endy){int TempX = startx - endx;int TempY = starty - endy;int S_Id = ch.Getid(startx, starty);int E_Id = ch.Getid(endx, endy);if ((S_Id*E_Id <= 0) && (TempX*TempX + TempY * TempY == 5) && !ch.Get(startx + (TempX / 2), starty + (TempY / 2))){return true;}return false;}
};
class Chariot :public Chess//車、车类,ID为-5和5
{
public:Chariot(int i) :Chess((i == 0 ? -5 : 5)) {}bool Judgement(Chessboard& ch, int startx, int starty, int endx, int endy){int TempX = startx - endx;int TempY = starty - endy;int S_Id = ch.Getid(startx, starty);int E_Id = ch.Getid(endx, endy);if ((S_Id*E_Id <= 0) && (!(TempX&&TempY)) && (TempX + TempY)){if (TempX){int Sign = (TempX > 0 ? -1 : 1);for (int i = 1; i < fabs(TempX); i++){if (ch.Get(startx + Sign * i, starty)){return false;}}}else{int Sign = (TempY > 0 ? -1 : 1);for (int i = 1; i < fabs(TempY); i++){if (ch.Get(startx, starty + Sign * i)){return false;}}}return true;}return false;}
};
class Cannon :public Chess//砲、炮类,ID为-6和6
{
public:Cannon(int i) :Chess((i == 0 ? -6 : 6)) {}bool Judgement(Chessboard& ch, int startx, int starty, int endx, int endy){int TempX = startx - endx;int TempY = starty - endy;int S_Id = ch.Getid(startx, starty);int E_Id = ch.Getid(endx, endy);if ((S_Id*E_Id <= 0) && (!(TempX&&TempY)) && (TempX + TempY)){int Tmp = 0;if (TempX){int Sign = (TempX > 0 ? -1 : 1);for (int i = 1; i < fabs(TempX); i++){if (ch.Get(startx + Sign * i, starty)){Tmp++;}}}else{int Sign = (TempY > 0 ? -1 : 1);for (int i = 1; i < fabs(TempY); i++){if (ch.Get(startx, starty + Sign * i)){Tmp++;}}}if (E_Id){if (Tmp == 1){return true;}}else{if (!Tmp){return true;}}}return false;}
};
class Soldier :public Chess//卒、兵类,ID为-7和7
{
public:Soldier(int i) :Chess((i == 0 ? -7 : 7)) {}bool Judgement(Chessboard& ch, int startx, int starty, int endx, int endy){int TempX = startx - endx;int TempY = starty - endy;int S_Id = ch.Getid(startx, starty);int E_Id = ch.Getid(endx, endy);if ((S_Id*E_Id <= 0) && (S_Id*TempY <= 0)){if (fabs(TempY) == 1 && TempX == 0){return true;}if (fabs(TempX) == 1 && TempY == 0){if (((starty - 1) / 5 == 0 && S_Id < 0) || ((starty - 1) / 5 == 1 && S_Id > 0)){return true;}}}return false;}
};
int Chessboard::Player = -1;
bool Chessboard::End = true;
inline Chessboard::Chessboard()
{memset(c, NULL, sizeof(c));
}
inline Chess * Chessboard::Get(int x, int y)
{return c[x][y];
}
int Chessboard::Getid(int x, int y)
{if (c[x][y] != NULL){return c[x][y]->Get();}return NULL;
}
bool Chessboard::Move(int startx, int starty, int endx, int endy)
{if (startx >= 1 && startx <= 9 && starty >= 1 && starty <= 10 && endx >= 1 && endx <= 9 && endy >= 1 && endy <= 10 && Getid(startx, starty) && Getid(startx, starty)*Player > 0 && c[startx][starty]->Judgement(*this, startx, starty, endx, endy)){if (c[endx][endy] != NULL){delete c[endx][endy];           //吃子}c[endx][endy] = c[startx][starty];c[startx][starty] = NULL;Player *= -1;                       //更换玩家操作return true;}else{cout << "走法错误,请重新输入:" << endl;return false;}
}
void Chessboard::Init()
{c[1][1] = new Chariot(1);c[9][1] = new Chariot(1);c[2][1] = new Horse(1);c[8][1] = new Horse(1);c[3][1] = new Chancellor(1);c[7][1] = new Chancellor(1);c[4][1] = new BodyGuard(1);c[6][1] = new BodyGuard(1);c[5][1] = new General(1);c[2][3] = new Cannon(1);c[8][3] = new Cannon(1);c[1][4] = new Soldier(1);c[3][4] = new Soldier(1);c[5][4] = new Soldier(1);c[7][4] = new Soldier(1);c[9][4] = new Soldier(1);c[1][10] = new Chariot(0);c[9][10] = new Chariot(0);c[2][10] = new Horse(0);c[8][10] = new Horse(0);c[3][10] = new Chancellor(0);c[7][10] = new Chancellor(0);c[4][10] = new BodyGuard(0);c[6][10] = new BodyGuard(0);c[5][10] = new General(0);c[2][8] = new Cannon(0);c[8][8] = new Cannon(0);c[1][7] = new Soldier(0);c[3][7] = new Soldier(0);c[5][7] = new Soldier(0);c[7][7] = new Soldier(0);c[9][7] = new Soldier(0);
}
void Chessboard::Show()
{cout << endl;HANDLE handle;handle = GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleTextAttribute(handle, 0xF0);cout << "     P2  一 二 三 四 五 六 七 八 九" << endl << endl;char num[11][4] = { "零","一","二","三","四","五","六","七","八","九" ,"十" };for (int i = 1; i < 11; i++){if (i == 6){SetConsoleTextAttribute(handle, 0xF0);cout << "          ————楚河 汉界————" << endl << endl;}SetConsoleTextAttribute(handle, 0xF0);cout << "     " << num[i] << "  ";for (int j = 1; j < 10; j++){if (c[j][i] != NULL){if (c[j][i]->Get() > 0){SetConsoleTextAttribute(handle, 0xF2);cout << Chessword[c[j][i]->Get() + 7] << " ";}else{SetConsoleTextAttribute(handle, 0xFC);cout << Chessword[c[j][i]->Get() + 7] << " ";}}else if ((i == 2 && j == 5) || (i == 9 && j == 5)){SetConsoleTextAttribute(handle, 0xF0);cout << "米" << " ";}else{SetConsoleTextAttribute(handle, 0xF0);cout << "十" << " ";}}cout << endl << endl;}SetConsoleTextAttribute(handle, 0xF0);cout << "     P1  一 二 三 四 五 六 七 八 九" << endl << endl;
}
void Chessboard::Play()
{HANDLE handle;handle = GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleTextAttribute(handle, 0xFC);system("cls");this->Init();this->Show();do{int startx, starty, aimx, aimy, iflag;int sid, aid;iflag = 0;do{sid = aid = 0;if ((Chessboard::Player == 1 ? 2 : 1) == 1){SetConsoleTextAttribute(handle, 0xFC);}else{SetConsoleTextAttribute(handle, 0xF2);}cout << "请P" << (Chessboard::Player == 1 ? 2 : 1) << "输入起始棋子位置与目标位置的坐标:" << endl;cin >> startx >> starty >> aimx >> aimy;} while (!this->Move(startx, starty, aimx, aimy));system("cls");this->Show();for (int i = 4; i < 7; i++){for (int j = 1; j < 11; j++){if (c[i][j] != NULL){if ((int)fabs(c[i][j]->Get()) == 1){iflag++;}else if (iflag != 0 && iflag != 2){if ((int)fabs(c[i][j]->Get()) != 1){iflag--;}}}}}if (iflag == 2){Player *= -1;Chessboard::End = false;}} while (Chessboard::End);if ((Chessboard::Player == 1 ? 1 : 2) == 1){SetConsoleTextAttribute(handle, 0xFC);}else{SetConsoleTextAttribute(handle, 0xF2);}cout << "结束,赢家是Player" << (Chessboard::Player == 1 ? 1 : 2) << endl;
}
Chessboard::~Chessboard()
{for (int i = 0; i < 10; i++){for (int j = 0; j < 11; j++){if (c[i][j] != NULL){delete c[i][j];c[i][j] = NULL;}}}
}
using namespace std;
int main()
{Chessboard C;C.Play();system("pause");
}

文章转载请注明本人博客地址:
转载自:Megalomania - 【C++】中国象棋


http://www.ppmy.cn/news/430072.html

相关文章

matlab识别中国象棋棋盘,一种基于图像处理的中国象棋识别系统及方法与流程

本发明涉及计算机图像识别技术,具体涉及一种基于图像处理的中国象棋识别系统及方法。 背景技术: 数字图像处理技术在机器感知领域应用十分广泛,主要目标是通过一些图像处理技术从图像中提取信息,该信息类似于人们采用语言和文字解释图像内容的过程,使用图像处理技术的典型…

中国象棋-单机游戏-微信小程序的项目开发流程详解

关于此文章能看懂的条件&#xff1a;对使用微信开发工具熟悉一点即可 在微信开发工具中&#xff0c;用小程序方式新建或打卡项目&#xff0c; 注意&#xff1a;如果是下载来的项目&#xff0c;解压后&#xff0c;要选小程序打开&#xff0c;选错是打不开的哦~ 如图 项目源代码…

软件测试 因果+决策案例--中国象棋中走马

软件测试 因果决策案例–中国象棋中走马 题目&#xff1a; 因果决策案例 中国象棋中走马的实际情况&#xff1a; 1&#xff0e;如果落点在棋盘外&#xff0c;则不移动棋子&#xff1b; 2&#xff0e;如果落点与起点不构成日字型&#xff0c;则不移动棋子&#xff1b; 3&am…

中国象棋(react hooks版)

文章目录 前言功能展示新增模块功能搭建项目框架配置React Router配置React Store配置i18n配置主题色React动画React ColorPicker打谱记录单元测试 核心功能优化落子音效dom解耦小结 结语 前言 它终于来了。终于来了&#xff0c;在第一版的基础上&#xff0c;历时近两个月终于…

中国象棋博弈

文章目录 棋盘表示着法生成搜索算法最小值-最大值搜索搜索alpha-beta剪枝优化 棋局评估棋子子力棋子位置 棋盘UI不足参考文献 棋盘表示 中国象棋的棋盘为10*9的矩形&#xff0c;一般采用10*9的二维数组来表示。 chessBoard: [["BR1","BN1","BB1&quo…

java实现中国象棋 源代码

java实现中国象棋 在网上找了很久中国象棋实现的源代码&#xff0c;终于找到了&#xff0c;下面就是源代码。 /**中国象棋Java版V3.0*源文件:Chess.java*添加功能:实现了当前棋局的保存*/import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.uti…

中国象棋,博大精深

文章目录 象棋简介象棋玩法棋子分数 象棋简介 象棋&#xff0c;是汉族棋类益智游戏&#xff0c;中国象棋在中国有着三千多年的历史&#xff0c;属于二人对抗性游戏的一种。由于用具简单、趣味性强&#xff0c;成为流行广泛的棋艺活动。是我国正式开展的78个体育项目之一。 象…

中国象棋详细设计分析

目 录 第一章 引言&#xff08;概述&#xff09; - 1 - 第二章 可行性分析 - 2 - 2.1 总体分析 - 2 - 2.2 开发环境介绍 - 2 - 2.2.1 软件开发环境 - 2 - 第三章 需求设计 - 2 - 第四章 详细设计 - 3 - 4.1 功能设计 - 3 - 4.1.1 功能说明 - 3- 4.1.2 对弈规则 - 4 - 4.1.3 相…