从0开始写中国象棋-走一步棋(当门炮,马来跳)(C++)

2023-11-10 21:21

本文主要是介绍从0开始写中国象棋-走一步棋(当门炮,马来跳)(C++),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在文章 从0开始写中国象棋-创建棋盘与棋子

中,我们已经可以看到象棋游戏的界面了。

这是因为,我们创建了棋盘(棋盘数组),并在棋盘上放置一些数字来表示棋子。

让棋子动起来

现在,我们打算让棋子动起来。

棋子动起来,其实很简单,比如开局 炮二平五。

实际上就是棋子从棋盘上的一个位置移动到了棋盘的另一个位置。

实际上是棋盘在变化

对应棋盘的变化就是,棋盘从:

变成了:

由于棋盘上的棋子就是一个一个的不同的数字,所以,从计算机的角度来说,走一步棋就是给二维数组的一个位置设置一个新数字。

也就是,起点位置元素重新赋值为0(表示这里没有棋子了,棋子走到其他位置去了);

终点位置元素重新赋值为炮的ID(表示炮走棋来到了这里)。

程序实现 GoAhead(OneStep)

现在我们希望告诉程序,走一步棋,从一个位置走到另一个位置,程序就能够实现这个目标。

由于这种需求是在下棋双方走棋的时候反复出现的,所以我们可以很方便的用函数来实现。

这个函数大概像下面这样:

bool GoAhead(from_row, from_col, to_row, to_col);

其中,各个参数的意思是很明显的,我们就不解释了。

但是,函数返回值是bool,这个是干什么的呢?

因为用户可能会乱走棋,比如,蹩马腿了也要跳马,这个时候你就要告诉他不能走这步棋。这时候函数返回 false 。

现在让我们来实现这个函数:

bool GoAhead(int from_row, int from_col, int to_row, int to_col)
{//如果出发的地方没有旗子,就返回 falseif()
}

这个时候我们才发现我们需要访问棋盘。

而棋盘是定义在main函数内的变量。我们访问不到。

怎么办?

C++全局变量

不在函数内定义的变量就叫全局变量。

为了能够让任何代码都访问到棋盘,我们在程序的一开始就定义棋盘。这样我们的函数就可以访问棋盘了。

//棋盘数组,不同的数字表示不同的棋子,0表示没有棋子
vector<vector<int>> chess_board
{{ 1, 2, 3, 4, 5, 6, 7, 8, 9},{ 0, 0, 0, 0, 0, 0, 0, 0, 0},{ 0,10, 0, 0, 0, 0, 0,11, 0},{12, 0,13, 0,14, 0,15, 0,16},{ 0, 0, 0, 0, 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0, 0, 0, 0, 0},{26, 0,27, 0,28, 0,29, 0,30},{ 0,31, 0, 0, 0, 0, 0,32, 0},{ 0, 0, 0, 0, 0, 0, 0, 0, 0},{17,18,19,20,21,22,23,24,25},
};bool GoAhead(int from_row, int from_col, int to_row, int to_col)
{//如果出发的地方没有旗子,就返回 falseif (chess_board[from_row][from_col] != 0){}else{return false;}
}

谁能告诉我能否走到哪里?

现在的问题是,当走棋的起点有棋子的时候,这个棋子能否到达目的地位置?

也就是走棋的合理性问题。

这里门道就多了:马走日,相走田,车走直路,炮翻山,小卒一去不会还。

如何实现这样的需求呢?

C++的方式是使用多态来实现。伪代码像下面这样:

//棋子类的基类
struct chess_base
{// 纯虚函数,表示 chess_base 是一个抽象类,专门用来做基类;//GoAhead 用来给各个派生类来重新实现 overridevirtual bool GoAhead(int from_row, int from_col, int to_row, int to_col) = 0;
};struct Horse : public chess_base
{// 马实现自己的走棋bool GoAhead(int from_row, int from_col, int to_row, int to_col){//ba la ba la ....return false;}
};struct King : public chess_base
{// 帅实现自己的走棋bool GoAhead(int from_row, int from_col, int to_row, int to_col){//ba la ba la ....return false;}
};

每个棋子都知道自己的规则,所以自己是知道能否走到目的地的。

这也就要求我们要替各个棋子来实现它们各自的走法。

棋子数组包含对象

之前,我们的棋子数组是不同位置(数组下标)表示不同棋子,棋子只有一个内容,就是它们的名字。

现在,我们希望用类对象来表示。名字只是棋子的一个成员变量。走棋GoAhead才是棋子的主要能力。

#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
using namespace std;//棋盘数组,不同的数字表示不同的棋子,0表示没有棋子
vector<vector<int>> chess_board
{{ 1, 2, 3, 4, 5, 6, 7, 8, 9},{ 0, 0, 0, 0, 0, 0, 0, 0, 0},{ 0,10, 0, 0, 0, 0, 0,11, 0},{12, 0,13, 0,14, 0,15, 0,16},{ 0, 0, 0, 0, 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0, 0, 0, 0, 0},{26, 0,27, 0,28, 0,29, 0,30},{ 0,31, 0, 0, 0, 0, 0,32, 0},{ 0, 0, 0, 0, 0, 0, 0, 0, 0},{17,18,19,20,21,22,23,24,25},
};//棋子类的基类
struct chess_base
{chess_base(const string& name1):name(name1){}// 纯虚函数,表示 chess_base 是一个抽象类,专门用来做基类;//GoAhead 用来给各个派生类来重新实现 overridevirtual bool GoAhead(int from_row, int from_col, int to_row, int to_col) = 0;string name;//棋子要显示的名字
};
//车 車
struct Chariot : public chess_base
{Chariot(const string& name1) :chess_base(name1) {}// 马实现自己的走棋bool GoAhead(int from_row, int from_col, int to_row, int to_col){cout << from_row << "," << from_col << "," << to_row << "," << to_col << endl;//ba la ba la ....return false;}
};
//马 馬
struct Horse : public chess_base
{Horse(const string& name1):chess_base(name1){}// 马实现自己的走棋bool GoAhead(int from_row, int from_col, int to_row, int to_col){cout << from_row << "," << from_col << "," << to_row << "," << to_col << endl;//ba la ba la ....return false;}
};
//炮 砲
struct Cannon : public chess_base
{Cannon(const string& name1) :chess_base(name1) {}// 马实现自己的走棋bool GoAhead(int from_row, int from_col, int to_row, int to_col){cout << from_row << "," << from_col << "," << to_row << "," << to_col << endl;//ba la ba la ....return false;}
};
//将 帅
struct King : public chess_base
{King(const string& name1) :chess_base(name1) {}// 帅实现自己的走棋bool GoAhead(int from_row, int from_col, int to_row, int to_col){//ba la ba la ....cout << from_row << "," << from_col << "," << to_row << "," << to_col << endl;return false;}
};
//士 仕
struct Official : public chess_base
{Official(const string& name1) :chess_base(name1) {}// 帅实现自己的走棋bool GoAhead(int from_row, int from_col, int to_row, int to_col){//ba la ba la ....cout << from_row << "," << from_col << "," << to_row << "," << to_col << endl;return false;}
};
//相 象
struct Minister : public chess_base
{Minister(const string& name1) :chess_base(name1) {}// 帅实现自己的走棋bool GoAhead(int from_row, int from_col, int to_row, int to_col){//ba la ba la ....cout << from_row << "," << from_col << "," << to_row << "," << to_col << endl;return false;}
};
//兵 卒
struct Soldier : public chess_base
{Soldier(const string& name1) :chess_base(name1) {}// 帅实现自己的走棋bool GoAhead(int from_row, int from_col, int to_row, int to_col){//ba la ba la ....cout << from_row << "," << from_col << "," << to_row << "," << to_col << endl;return false;}
};vector<chess_base*> chess_man
{nullptr,//下标为0不用,编号从1开始//上方黑方棋子new Chariot("车"),new Horse("马"), new Minister("相"), new Official("士"), new King("将"), new Official("士"), new Minister("相"), new Horse("马"), new Chariot("车"),new Cannon("炮"),new Cannon("炮"),new Soldier("兵"), new Soldier("兵"), new Soldier("兵"), new Soldier("兵"), new Soldier("兵"),//下方红方棋子new Chariot("車"), new Horse("馬"), new Minister("象"), new Official("仕"), new King("帥"), new Official("仕"), new Minister("象"), new Horse("馬"), new Chariot("車"),new Soldier("卒"), new Soldier("卒"), new Soldier("卒"), new Soldier("卒"), new Soldier("卒"),new Cannon("砲"), new Cannon("砲"),
};int main(void)
{for (int row = 0; row < 10; row++){for (int col = 0; col < 9; col++){auto id = chess_board[row][col];if (id != 0){cout <<setw(5)<< chess_man[id]->name ;//输出一个棋子}else{cout<<setw(5) << "_";//表示棋盘上的一个位置}}cout << endl;cout << endl;}return 0;
}

运行结果:

当门炮,马来跳

有了棋子对象之后,我们实现走棋就很好实现了。

    // 当门炮 : 炮二平五  ID 为 32 从(7,7) 移动到 (7,4)chess_man[32]->GoAhead(7, 7, 7, 4);// 马来跳 : 炮8进7  ID 为 8 从(7,7) 移动到 (7,4)chess_man[8]->GoAhead(0, 7, 2, 6);

此时,我们需要实现炮,马的 GoAhead 函数。

为了简单起见,我们不做合法性检查,让棋子直接在棋盘上从起点走到终点。

既然如此,其实所有棋子都是这样走棋的,我们把所有的棋子走棋都给实现了:

bool GoAhead(int from_row, int from_col, int to_row, int to_col)
{cout << "GoAhead " << from_row << "," << from_col << "," << to_row << "," << to_col << endl;//先保存原来的 ID, 为着放到终点auto id = chess_board[from_row][from_col];//离开之后,留下 0chess_board[from_row][from_col] = 0;//走到了目的地chess_board[to_row][to_col] = id;return false;
}

完整的代码

#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
using namespace std;//棋盘数组,不同的数字表示不同的棋子,0表示没有棋子
vector<vector<int>> chess_board
{/*      0  1  2  3  4  5  6  7  8*//* 0*/{ 1, 2, 3, 4, 5, 6, 7, 8, 9},/* 1*/{ 0, 0, 0, 0, 0, 0, 0, 0, 0},/* 2*/{ 0,10, 0, 0, 0, 0, 0,11, 0},/* 3*/{12, 0,13, 0,14, 0,15, 0,16},/* 4*/{ 0, 0, 0, 0, 0, 0, 0, 0, 0},/* 5*/{ 0, 0, 0, 0, 0, 0, 0, 0, 0},/* 6*/{26, 0,27, 0,28, 0,29, 0,30},/* 7*/{ 0,31, 0, 0, 0, 0, 0,32, 0},/* 8*/{ 0, 0, 0, 0, 0, 0, 0, 0, 0},/* 9*/{17,18,19,20,21,22,23,24,25},
};//棋子类的基类
struct chess_base
{chess_base(const string& name1):name(name1){}// 纯虚函数,表示 chess_base 是一个抽象类,专门用来做基类;//GoAhead 用来给各个派生类来重新实现 overridevirtual bool GoAhead(int from_row, int from_col, int to_row, int to_col) = 0;string name;//棋子要显示的名字
};
//车 車
struct Chariot : public chess_base
{Chariot(const string& name1) :chess_base(name1) {}// 马实现自己的走棋bool GoAhead(int from_row, int from_col, int to_row, int to_col){cout << "GoAhead " << from_row << "," << from_col << "," << to_row << "," << to_col << endl;//先保存原来的 ID, 为着放到终点auto id = chess_board[from_row][from_col];//离开之后,留下 0chess_board[from_row][from_col] = 0;//走到了目的地chess_board[to_row][to_col] = id;return false;}
};
//马 馬
struct Horse : public chess_base
{Horse(const string& name1):chess_base(name1){}// 马实现自己的走棋bool GoAhead(int from_row, int from_col, int to_row, int to_col){cout << "GoAhead " << from_row << "," << from_col << "," << to_row << "," << to_col << endl;//先保存原来的 ID, 为着放到终点auto id = chess_board[from_row][from_col];//离开之后,留下 0chess_board[from_row][from_col] = 0;//走到了目的地chess_board[to_row][to_col] = id;return false;}
};
//炮 砲
struct Cannon : public chess_base
{Cannon(const string& name1) :chess_base(name1) {}// 马实现自己的走棋bool GoAhead(int from_row, int from_col, int to_row, int to_col){cout << "GoAhead " << from_row << "," << from_col << "," << to_row << "," << to_col << endl;//先保存原来的 ID, 为着放到终点auto id = chess_board[from_row][from_col];//离开之后,留下 0chess_board[from_row][from_col] = 0;//走到了目的地chess_board[to_row][to_col] = id;return false;}
};
//将 帅
struct King : public chess_base
{King(const string& name1) :chess_base(name1) {}// 帅实现自己的走棋bool GoAhead(int from_row, int from_col, int to_row, int to_col){cout<<"GoAhead " << from_row << "," << from_col << "," << to_row << "," << to_col << endl;//先保存原来的 ID, 为着放到终点auto id = chess_board[from_row][from_col];//离开之后,留下 0chess_board[from_row][from_col] = 0;//走到了目的地chess_board[to_row][to_col] = id;return false;}
};
//士 仕
struct Official : public chess_base
{Official(const string& name1) :chess_base(name1) {}// 帅实现自己的走棋bool GoAhead(int from_row, int from_col, int to_row, int to_col){cout << "GoAhead " << from_row << "," << from_col << "," << to_row << "," << to_col << endl;//先保存原来的 ID, 为着放到终点auto id = chess_board[from_row][from_col];//离开之后,留下 0chess_board[from_row][from_col] = 0;//走到了目的地chess_board[to_row][to_col] = id;return false;}
};
//相 象
struct Minister : public chess_base
{Minister(const string& name1) :chess_base(name1) {}// 帅实现自己的走棋bool GoAhead(int from_row, int from_col, int to_row, int to_col){cout << "GoAhead " << from_row << "," << from_col << "," << to_row << "," << to_col << endl;//先保存原来的 ID, 为着放到终点auto id = chess_board[from_row][from_col];//离开之后,留下 0chess_board[from_row][from_col] = 0;//走到了目的地chess_board[to_row][to_col] = id;return false;}
};
//兵 卒
struct Soldier : public chess_base
{Soldier(const string& name1) :chess_base(name1) {}// 帅实现自己的走棋bool GoAhead(int from_row, int from_col, int to_row, int to_col){cout << "GoAhead " << from_row << "," << from_col << "," << to_row << "," << to_col << endl;//先保存原来的 ID, 为着放到终点auto id = chess_board[from_row][from_col];//离开之后,留下 0chess_board[from_row][from_col] = 0;//走到了目的地chess_board[to_row][to_col] = id;return false;}
};vector<chess_base*> chess_man
{nullptr,//下标为0不用,编号从1开始//上方黑方棋子new Chariot("车"),new Horse("马"), new Minister("相"), new Official("士"), new King("将"), new Official("士"), new Minister("相"), new Horse("马"), new Chariot("车"),new Cannon("炮"),new Cannon("炮"),new Soldier("兵"), new Soldier("兵"), new Soldier("兵"), new Soldier("兵"), new Soldier("兵"),//下方红方棋子new Chariot("車"), new Horse("馬"), new Minister("象"), new Official("仕"), new King("帥"), new Official("仕"), new Minister("象"), new Horse("馬"), new Chariot("車"),new Soldier("卒"), new Soldier("卒"), new Soldier("卒"), new Soldier("卒"), new Soldier("卒"),new Cannon("砲"), new Cannon("砲"),
};int main(void)
{// 当门炮 : 炮二平五  ID 为 32 从(7,7) 移动到 (7,4)chess_man[32]->GoAhead(7, 7, 7, 4);// 马来跳 : 炮8进7  ID 为 8 从(7,7) 移动到 (7,4)chess_man[8]->GoAhead(0, 7, 2, 6);for (int row = 0; row < 10; row++){for (int col = 0; col < 9; col++){auto id = chess_board[row][col];if (id != 0){cout <<setw(5)<< chess_man[id]->name ;//输出一个棋子}else{cout<<setw(5) << "_";//表示棋盘上的一个位置}}cout << endl;cout << endl;}return 0;
}

运行效果

这篇关于从0开始写中国象棋-走一步棋(当门炮,马来跳)(C++)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:https://blog.csdn.net/ClamReason/article/details/133485065
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/385329

相关文章

C/C++ chrono简单使用场景示例详解

《C/C++chrono简单使用场景示例详解》:本文主要介绍C/C++chrono简单使用场景示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友... 目录chrono使用场景举例1 输出格式化字符串chrono使用场景China编程举例1 输出格式化字符串示

C++/类与对象/默认成员函数@构造函数的用法

《C++/类与对象/默认成员函数@构造函数的用法》:本文主要介绍C++/类与对象/默认成员函数@构造函数的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录名词概念默认成员函数构造函数概念函数特征显示构造函数隐式构造函数总结名词概念默认构造函数:不用传参就可以

C++类和对象之默认成员函数的使用解读

《C++类和对象之默认成员函数的使用解读》:本文主要介绍C++类和对象之默认成员函数的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、默认成员函数有哪些二、各默认成员函数详解默认构造函数析构函数拷贝构造函数拷贝赋值运算符三、默认成员函数的注意事项总结一

C/C++中OpenCV 矩阵运算的实现

《C/C++中OpenCV矩阵运算的实现》本文主要介绍了C/C++中OpenCV矩阵运算的实现,包括基本算术运算(标量与矩阵)、矩阵乘法、转置、逆矩阵、行列式、迹、范数等操作,感兴趣的可以了解一下... 目录矩阵的创建与初始化创建矩阵访问矩阵元素基本的算术运算 ➕➖✖️➗矩阵与标量运算矩阵与矩阵运算 (逐元

C/C++的OpenCV 进行图像梯度提取的几种实现

《C/C++的OpenCV进行图像梯度提取的几种实现》本文主要介绍了C/C++的OpenCV进行图像梯度提取的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录预www.chinasem.cn备知识1. 图像加载与预处理2. Sobel 算子计算 X 和 Y

C/C++和OpenCV实现调用摄像头

《C/C++和OpenCV实现调用摄像头》本文主要介绍了C/C++和OpenCV实现调用摄像头,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录准备工作1. 打开摄像头2. 读取视频帧3. 显示视频帧4. 释放资源5. 获取和设置摄像头属性

c/c++的opencv图像金字塔缩放实现

《c/c++的opencv图像金字塔缩放实现》本文主要介绍了c/c++的opencv图像金字塔缩放实现,通过对原始图像进行连续的下采样或上采样操作,生成一系列不同分辨率的图像,具有一定的参考价值,感兴... 目录图像金字塔简介图像下采样 (cv::pyrDown)图像上采样 (cv::pyrUp)C++ O

c/c++的opencv实现图片膨胀

《c/c++的opencv实现图片膨胀》图像膨胀是形态学操作,通过结构元素扩张亮区填充孔洞、连接断开部分、加粗物体,OpenCV的cv::dilate函数实现该操作,本文就来介绍一下opencv图片... 目录什么是图像膨胀?结构元素 (KerChina编程nel)OpenCV 中的 cv::dilate() 函

C++ RabbitMq消息队列组件详解

《C++RabbitMq消息队列组件详解》:本文主要介绍C++RabbitMq消息队列组件的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. RabbitMq介绍2. 安装RabbitMQ3. 安装 RabbitMQ 的 C++客户端库4. A

C++ HTTP框架推荐(特点及优势)

《C++HTTP框架推荐(特点及优势)》:本文主要介绍C++HTTP框架推荐的相关资料,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. Crow2. Drogon3. Pistache4. cpp-httplib5. Beast (Boos