从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++)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/385329

相关文章

C++ 中的 if-constexpr语法和作用

《C++中的if-constexpr语法和作用》if-constexpr语法是C++17引入的新语法特性,也被称为常量if表达式或静态if(staticif),:本文主要介绍C++中的if-c... 目录1 if-constexpr 语法1.1 基本语法1.2 扩展说明1.2.1 条件表达式1.2.2 fa

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa

C++字符串提取和分割的多种方法

《C++字符串提取和分割的多种方法》在C++编程中,字符串处理是一个常见的任务,尤其是在需要从字符串中提取特定数据时,本文将详细探讨如何使用C++标准库中的工具来提取和分割字符串,并分析不同方法的适用... 目录1. 字符串提取的基本方法1.1 使用 std::istringstream 和 >> 操作符示

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

C++ 各种map特点对比分析

《C++各种map特点对比分析》文章比较了C++中不同类型的map(如std::map,std::unordered_map,std::multimap,std::unordered_multima... 目录特点比较C++ 示例代码 ​​​​​​代码解释特点比较1. std::map底层实现:基于红黑

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程

利用Python和C++解析gltf文件的示例详解

《利用Python和C++解析gltf文件的示例详解》gltf,全称是GLTransmissionFormat,是一种开放的3D文件格式,Python和C++是两个非常强大的工具,下面我们就来看看如何... 目录什么是gltf文件选择语言的原因安装必要的库解析gltf文件的步骤1. 读取gltf文件2. 提

C++快速排序超详细讲解

《C++快速排序超详细讲解》快速排序是一种高效的排序算法,通过分治法将数组划分为两部分,递归排序,直到整个数组有序,通过代码解析和示例,详细解释了快速排序的工作原理和实现过程,需要的朋友可以参考下... 目录一、快速排序原理二、快速排序标准代码三、代码解析四、使用while循环的快速排序1.代码代码1.由快