最近学习EasyX,在发现[PE]经典八炮的发布的一个中国象棋算法部分的代码后,于是尝试使用EasyX实现图形化。
另外一点小提示:如果想要实现本代码,需要安装EasyX,安装方法自行百度。
算法部分代码来自:C++实现双人中国象棋(一)——算法篇(附完整代码)_[PE]经典八炮的博客-CSDN博客_c++象棋代码sz最近突发奇想,要使用C++做一个双人象棋的程序,昨天肝了一天,终于把算法部分完成了,下面把开发过程中的经验分享一下。知识要求:熟练掌握C++语言面向对象编程的知识(继承,多态)掌握STL的基本操作了解中国象棋基本规则(不会还有人不知道中国象棋规则吧!)..................https://blog.csdn.net/qq_54121864/article/details/125652386?spm=1001.2014.3001.5502直接贴源码吧:
#include
#include
#include
#include
using namespace std;
const bool BLACK_CHESS = 0, RED_CHESS = 1;
const uint8_t DRAW = 2, NONE = 3;
class Point {
public:
int8_t x, y;
Point(int8_t nx, int8_t ny) {
this->x = nx;
this->y = ny;
}
bool ColorOfTheArea() const {
if (y <= 4) {
return RED_CHESS;
}
return BLACK_CHESS;
}
bool IsInNinePalaces()const {
return x >= 3 && x <= 5 && (y <= 2 || y >= 7);
}
};
bool operator==(const Point& a, const Point& b) {
return a.x == b.x && a.y == b.y;
}
class ChessBoard {
private:
friend class ChessPiece;
ChessPiece* board[10][9];
list red, black;
public:
ChessBoard();
const list& GetRedPieces() const {
return red;
}
const list& GetBlackPieces() const {
return black;
}
ChessPiece*& GetChess(const Point& point) {
return board[point.y][point.x];
}
ChessPiece* const& GetChess(const Point& point) const {
return board[point.y][point.x];
}
void RemoveChess(const Point& point);
bool KingsFaceToFace() const;
~ChessBoard();
};
class ChessPiece {
protected:
Point pt;
ChessBoard& board;
public:
const bool cl;
ChessPiece(const Point& point, bool color, ChessBoard& chessboard) :pt(point), cl(color), board(chessboard) {
if (cl == BLACK_CHESS) {
board.black.push_back(this);
}
else {
board.red.push_back(this);
}
board.GetChess(pt) = this;
}
const Point& GetPoint() const {
return pt;
}
virtual bool CanMoveTo(const Point& point)const = 0;
virtual const char* GetName() = 0;
virtual const bool CanCrossTheRiver() const = 0;
bool MoveTo(const Point& point) {
if (CanMoveTo(point)) {
board.GetChess(pt) = nullptr;
pt.x = point.x;
pt.y = point.y;
board.RemoveChess(point);
board.GetChess(point) = this;
return true;
}
return false;
}
};
class Rook :public ChessPiece {
public:
Rook(const Point& point, bool color, ChessBoard& chessboard) :ChessPiece(point, color, chessboard) {}
virtual bool CanMoveTo(const Point& point)const override {
if (board.GetChess(point) == nullptr || board.GetChess(point)->cl != this->cl) {
if (point.x == pt.x) {
if (point.y < pt.y) {
for (uint8_t i = point.y + 1; i < pt.y; i++) {
if (board.GetChess(Point(point.x, i))) {
return false;
}
}
}
else {
for (uint8_t i = pt.y + 1; i < point.y; i++) {
if (board.GetChess(Point(point.x, i))) {
return false;
}
}
}
return true;
}
else if (point.y == pt.y) {
if (point.x < pt.x) {
for (uint8_t i = point.x + 1; i < pt.x; i++) {
if (board.GetChess(Point(i, point.y))) {
return false;
}
}
}
else {
for (uint8_t i = pt.x + 1; i < point.x; i++) {
if (board.GetChess(Point(i, point.y))) {
return false;
}
}
}
return true;
}
}
return false;
}
virtual const char* GetName() {
return "車";
}
virtual const bool CanCrossTheRiver() const {
return true;
}
};
class Horse :public ChessPiece {
public:
Horse(const Point& point, bool color, ChessBoard& chessboard) :ChessPiece(point, color, chessboard) {}
virtual bool CanMoveTo(const Point& point)const override {
static const Point s[8] = {
{2, 1},
{2, -1},
{-2, -1},
{-2, -1},
{1, 2},
{-1, 2},
{1, -2},
{-1, -2}
},
u[8] = {
{1, 0},
{1, 0},
{-1, 0},
{-1, 0},
{0, 1},
{0, 1},
{0, -1},
{0, -1}
};
if (board.GetChess(point) == nullptr || board.GetChess(point)->cl != this->cl) {
for (size_t i = 0; i < 8; i++) {
if (point == Point(pt.x + s[i].x, pt.y + s[i].y) && board.GetChess(Point(pt.x + u[i].x, pt.y + u[i].y)) == nullptr) {
return true;
}
}
}
return false;
}
virtual const char* GetName() {
return "馬";
}
virtual const bool CanCrossTheRiver() const {
return true;
}
};
class Cannon : public ChessPiece {
public:
Cannon(const Point& point, bool color, ChessBoard& chessboard) : ChessPiece(point, color, chessboard) {}
virtual bool CanMoveTo(const Point& point) const override {
if (board.GetChess(point) == nullptr) {
if (point.x == pt.x) {
if (point.y < pt.y) {
for (uint8_t i = point.y + 1; i < pt.y; i++) {
if (board.GetChess(Point(point.x, i))) {
return false;
}
}
}
else {
for (uint8_t i = pt.y + 1; i < point.y; i++) {
if (board.GetChess(Point(point.x, i))) {
return false;
}
}
}
return true;
}
else if (point.y == pt.y) {
if (point.x < pt.x) {
for (uint8_t i = point.x + 1; i < pt.x; i++) {
if (board.GetChess(Point(i, point.y))) {
return false;
}
}
}
else if (pt.x < point.x) {
for (uint8_t i = pt.x + 1; i < point.x; i++) {
if (board.GetChess(Point(i, point.y))) {
return false;
}
}
}
return true;
}
return false;
}
else if (board.GetChess(point)->cl != this->cl) {
uint8_t count = 0;
if (point.x == pt.x) {
if (point.y < pt.y) {
for (uint8_t i = point.y + 1; i < pt.y; i++) {
if (board.GetChess(Point(point.x, i))) {
count++;
}
}
}
else {
for (uint8_t i = pt.y + 1; i < point.y; i++) {
if (board.GetChess(Point(point.x, i))) {
count++;
}
}
}
}
else if (point.y == pt.y) {
if (point.x < pt.x) {
for (uint8_t i = point.x + 1; i < pt.x; i++) {
if (board.GetChess(Point(i, point.y))) {
count++;
}
}
}
else if (pt.x < point.x) {
for (uint8_t i = pt.x + 1; i < point.x; i++) {
if (board.GetChess(Point(i, point.y))) {
count++;
}
}
}
}
if (count == 1) {
return true;
}
}
return false;
}
virtual const char* GetName() {
return "炮";
}
virtual const bool CanCrossTheRiver() const {
return true;
}
};
class Elephant :public ChessPiece {
public:
Elephant(const Point& point, bool color, ChessBoard& chessboard) :ChessPiece(point, color, chessboard) {}
virtual bool CanMoveTo(const Point& point) const override {
static const Point s[4] = {
{2,2},
{2, -2},
{-2, 2},
{-2, -2}
}, u[4] = {
{1,1},
{1, -1},
{-1,1},
{-1, -1}
};
if (board.GetChess(point) == nullptr || board.GetChess(point)->cl != this->cl) {
if (cl == point.ColorOfTheArea()) {
for (size_t i = 0; i < 4; i++) {
if (point == Point(pt.x + s[i].x, pt.y + s[i].y) && board.GetChess(Point(pt.x + u[i].x, pt.y + u[i].y)) == nullptr) {
return true;
}
}
}
}
return false;
}
virtual const char* GetName() {
return cl == BLACK_CHESS ? "象" : "相";
}
virtual const bool CanCrossTheRiver()const {
return false;
}
};
class Adviser :public ChessPiece {
public:
Adviser(const Point& point, bool color, ChessBoard& chessboard) :ChessPiece(point, color, chessboard) {
}
virtual bool CanMoveTo(const Point& point)const override {
static const Point s[4] = {
{1,1},
{1,-1},
{-1, 1},
{-1,-1}
};
if (board.GetChess(point) == nullptr || board.GetChess(point)->cl != this->cl) {
if (cl == point.ColorOfTheArea() && point.IsInNinePalaces()) {
for (size_t i = 0; i < 4; i++) {
if (point == Point(pt.x + s[i].x, pt.y + s[i].y)) {
return true;
}
}
}
return false;
}
return false;
}
virtual const char* GetName() {
return "士";
}
virtual const bool CanCrossTheRiver()const {
return false;
}
};
class Pawn :public ChessPiece {
public:
Pawn(const Point& point, bool color, ChessBoard& chessboard) :ChessPiece(point, color, chessboard) {
}
virtual bool CanMoveTo(const Point& point)const override {
if (board.GetChess(point) == nullptr || board.GetChess(point)->cl != this->cl) {
int8_t front = (cl == RED_CHESS ? 1 : -1);
if (cl == pt.ColorOfTheArea()) {
return point == Point(pt.x, pt.y + front);
}
static const Point s[3] = {
{0, front},
{1, 0},
{-1, 0}
};
for (size_t i = 0; i < 4; i++) {
if (point == Point(pt.x + s[i].x, pt.y + s[i].y)) {
return true;
}
}
}
return false;
}
virtual const char* GetName() {
return cl == BLACK_CHESS ? "卒" : "兵";
}
virtual const bool CanCrossTheRiver()const {
return true;
}
};
class King :public ChessPiece {
public:
King(const Point& point, bool color, ChessBoard& chessboard) :ChessPiece(point, color, chessboard) {
}
virtual bool CanMoveTo(const Point& point)const override {
static const Point s[4] = {
{0,1},
{0,-1},
{1, 0},
{-1, 0}
};
if (board.GetChess(point) == nullptr || board.GetChess(point)->cl != this->cl) {
if (point.IsInNinePalaces() && point.ColorOfTheArea() == cl) {
for (size_t i = 0; i < 4; i++) {
if (point == Point(pt.x + s[i].x, pt.y + s[i].y)) {
return true;
}
}
}
}
return false;
}
virtual const char* GetName() {
return cl == BLACK_CHESS ? "将" : "帥";
}
virtual const bool CanCrossTheRiver()const {
return false;
}
};
ChessBoard::ChessBoard() {
memset(board, 0, sizeof(board));
new King(Point(4, 0), RED_CHESS, *this);
new King(Point(4, 9), BLACK_CHESS, *this);
new Adviser(Point(3, 0), RED_CHESS, *this);
new Adviser(Point(5, 0), RED_CHESS, *this);
new Adviser(Point(3, 9), BLACK_CHESS, *this);
new Adviser(Point(5, 9), BLACK_CHESS, *this);
new Elephant(Point(2, 0), RED_CHESS, *this);
new Elephant(Point(6, 0), RED_CHESS, *this);
new Elephant(Point(2, 9), BLACK_CHESS, *this);
new Elephant(Point(6, 9), BLACK_CHESS, *this);
new Horse(Point(1, 0), RED_CHESS, *this);
new Horse(Point(7, 0), RED_CHESS, *this);
new Horse(Point(1, 9), BLACK_CHESS, *this);
new Horse(Point(7, 9), BLACK_CHESS, *this);
new Rook(Point(0, 0), RED_CHESS, *this);
new Rook(Point(8, 0), RED_CHESS, *this);
new Rook(Point(0, 9), BLACK_CHESS, *this);
new Rook(Point(8, 9), BLACK_CHESS, *this);
new Cannon(Point(1, 2), RED_CHESS, *this);
new Cannon(Point(7, 2), RED_CHESS, *this);
new Cannon(Point(1, 7), BLACK_CHESS, *this);
new Cannon(Point(7, 7), BLACK_CHESS, *this);
new Pawn(Point(0, 3), RED_CHESS, *this);
new Pawn(Point(2, 3), RED_CHESS, *this);
new Pawn(Point(4, 3), RED_CHESS, *this);
new Pawn(Point(6, 3), RED_CHESS, *this);
new Pawn(Point(8, 3), RED_CHESS, *this);
new Pawn(Point(0, 6), BLACK_CHESS, *this);
new Pawn(Point(2, 6), BLACK_CHESS, *this);
new Pawn(Point(4, 6), BLACK_CHESS, *this);
new Pawn(Point(6, 6), BLACK_CHESS, *this);
new Pawn(Point(8, 6), BLACK_CHESS, *this);
}
// 将RemoveChess 放在ChessPiece之后能防止报未定义未定义ChessPiece的错误
void ChessBoard::RemoveChess(const Point& point) {
if (GetChess(point)) {
if (GetChess(point)->cl == RED_CHESS) {
red.erase(find(red.begin(), red.end(), GetChess(point)));
}
else {
black.erase(find(black.begin(), black.end(), GetChess(point)));
}
}
delete GetChess(point);
GetChess(point) = nullptr;
}
bool ChessBoard::KingsFaceToFace() const {
auto r = find_if(red.begin(), red.end(), [](ChessPiece* p) {return !strcmp(p->GetName(), "帥"); }),
b = find_if(black.begin(), black.begin(), [](ChessPiece* p) {return !strcmp(p->GetName(), "将"); });
if (r != red.end() && b != black.end()) {
if ((*r)->GetPoint().x == (*b)->GetPoint().x) {
for (uint8_t i = (*r)->GetPoint().y + 1; i < (*b)->GetPoint().y; i++) {
if (GetChess(Point((*r)->GetPoint().x, i))) {
return false;
}
}
return true;
}
}
return false;
}
ChessBoard::~ChessBoard() {
for (ChessPiece* p : red) {
delete p;
}
for (ChessPiece* p : black) {
delete p;
}
}
算法代码部分只做了一些小修改,如GetName() 函数中函数体后面加const ,_stprintf_s会读取失败。
#pragma once
#include
#include"Chess.hpp"
const int BLOCK_SIZE = 55;
const int RowNum = 11;
const int COLNum = 10;
class Game
{
private:
bool nextPlayer;
ChessBoard board;
Point* firstPoint, *secondPoint; // 鼠标点击两次的位置
public:
Game() {
nextPlayer = RED_CHESS;
firstPoint = new Point(-1, -1);
secondPoint = new Point(-1, -1);
}
bool Move(const Point& a, const Point& b) {
if (board.GetChess(a) && board.GetChess(a)->cl == nextPlayer) {
if (board.GetChess(a)->MoveTo(b)) {
nextPlayer = !nextPlayer;
return true;
}
return false;
}
return false;
}
const ChessBoard& GetBoard() const {
return board;
}
uint8_t GetWinner() const {
if (board.KingsFaceToFace()) {
return nextPlayer;
}
if (find_if(board.GetRedPieces().begin(), board.GetRedPieces().end(), [](ChessPiece* p) {return !strcmp(p->GetName(),"帥"); }) == board.GetRedPieces().end()) {
return BLACK_CHESS;
}
if (find_if(board.GetBlackPieces().begin(), board.GetBlackPieces().end(), [](ChessPiece* p) {return !strcmp(p->GetName(), "将"); }) == board.GetBlackPieces().end()) {
return RED_CHESS;
}
if (count_if(board.GetRedPieces().begin(), board.GetRedPieces().end(), [](ChessPiece* p) {return p->CanCrossTheRiver(); }) +
count_if(board.GetBlackPieces().begin(), board.GetBlackPieces().end(), [](ChessPiece* p) {return p->CanCrossTheRiver(); }) == 0) {
return DRAW; // 双方都不能过河,平局
}
return NONE;
}
bool GetNexPlayer() const {
return nextPlayer;
}
void startup();
void show();
void updateWithInput();
};
void Game::startup() {
initgraph(BLOCK_SIZE * COLNum, BLOCK_SIZE * RowNum);
setbkcolor(RGB(221, 200, 157));
setlinestyle(PS_SOLID, 2);
cleardevice();
BeginBatchDraw();
}
void Game::show() {
cleardevice();
// 下面为绘制棋盘
setlinecolor(BLACK);
setfillcolor(RGB(221, 200, 157));
for (int i = 0; i < RowNum - 2; i++) {
for (int j = 0; j < COLNum - 2; j++) {
if (i != 4) {
fillrectangle((j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE, (j + 2) * BLOCK_SIZE, (i + 2) * BLOCK_SIZE);
}
}
}
//画楚河汉界外的两笔 坐标(i = 5,j = 1 i = 5 , j = 9
line(1 * BLOCK_SIZE, 5 * BLOCK_SIZE, BLOCK_SIZE, 6 * BLOCK_SIZE);
line(9 * BLOCK_SIZE, 5 * BLOCK_SIZE, 9 * BLOCK_SIZE, 6 * BLOCK_SIZE);
//画两个九宫格 i = 1 + 2, j = 4 + 2 ; i = 1 + 2, j = 6 -2 ;
// 下面的: i = 10 - 2, j = 4 + 2; i = 8 + 2, j = 4 + 2
line(4 * BLOCK_SIZE, 1 * BLOCK_SIZE, 6 * BLOCK_SIZE, 3 * BLOCK_SIZE);
line(6 * BLOCK_SIZE, 1 * BLOCK_SIZE, 4 * BLOCK_SIZE, 3 * BLOCK_SIZE);
line(4 * BLOCK_SIZE, 10 * BLOCK_SIZE, 6 * BLOCK_SIZE, 8 * BLOCK_SIZE);
line(4 * BLOCK_SIZE, 8 * BLOCK_SIZE, 6 * BLOCK_SIZE, 10 * BLOCK_SIZE);
//写楚河汉界 楚河 i = 5 , j = 2 汉界 i = 5, j = 6
TCHAR s[20];
setbkmode(TRANSPARENT);
settextcolor(BLACK);
settextstyle(55, 0, _T("华文行楷"));
_stprintf_s(s, _T("楚河"));
outtextxy(2 * BLOCK_SIZE, 5 * BLOCK_SIZE, s);
settextcolor(RED);
_stprintf_s(s, _T("汉界"));
outtextxy(6 * BLOCK_SIZE, 5 * BLOCK_SIZE, s);
//绘制棋子,首先,需要有一个画圆的函数,画出一个圆,然后中间是棋子的名字,棋子在
setlinecolor(RGB(100, 100, 100));
setfillcolor(RGB(221 - 20, 200 - 20, 157 -20));
for (int y = 0; y < 10; y++) { //这里对应的线
for (int x = 0; x < 9; x++) {
ChessPiece* p = this->board.GetChess(Point(x, y));
if (p) {
if (p->cl == BLACK_CHESS) { // 绘制黑棋 画圆,设置字体
fillcircle((p->GetPoint().x + 1) * BLOCK_SIZE, (p->GetPoint().y + 1) * BLOCK_SIZE, BLOCK_SIZE / 2 - 2);
TCHAR s[20];
setbkmode(TRANSPARENT);
settextcolor(BLACK);
settextstyle(35, 0, _T("宋体"));
_stprintf_s(s, _T("%hs"), p->GetName());
outtextxy((x + 1) * BLOCK_SIZE - BLOCK_SIZE / 2 + 10, (y + 1) * BLOCK_SIZE - BLOCK_SIZE / 2 + 10, s);
}
else {
fillcircle((p->GetPoint().x + 1) * BLOCK_SIZE, (p->GetPoint().y + 1) * BLOCK_SIZE, BLOCK_SIZE / 2 - 2);
TCHAR s[20];
setbkmode(TRANSPARENT);
settextcolor(RED);
settextstyle(35, 0, _T("宋体"));
_stprintf_s(s, _T("%hs"),p->GetName());
outtextxy((x + 1) * BLOCK_SIZE - BLOCK_SIZE / 2 + 10, (y + 1) * BLOCK_SIZE - BLOCK_SIZE / 2 + 10, s);
}
}
}
}
//绘制第一个棋子的位置
if (firstPoint->x != -1) {
setlinecolor(RED);
circle((firstPoint->y + 1) * BLOCK_SIZE, (firstPoint->x + 1) * BLOCK_SIZE, BLOCK_SIZE / 2 + 4);
}
TCHAR s1[20];
setbkmode(TRANSPARENT);
settextcolor(RED);
settextstyle(35, 0, _T("宋体"));
_stprintf_s(s1, _T("%d, %d"),firstPoint->x, firstPoint->y);
outtextxy(0, 0, s1);
// 判断胜利者
auto winner = GetWinner();
if (winner == BLACK_CHESS) {
_stprintf_s(s1, _T("黑方胜利!"));
outtextxy(4*BLOCK_SIZE, 5*BLOCK_SIZE, s1);
}
else if (winner == RED_CHESS) {
_stprintf_s(s1, _T("红方胜利!"));
outtextxy(4 * BLOCK_SIZE, 5 * BLOCK_SIZE, s1);
}
else if (winner == DRAW) {
_stprintf_s(s1, _T("平局"));
outtextxy(4 * BLOCK_SIZE, 5 * BLOCK_SIZE, s1);
}
FlushBatchDraw();
}
void Game::updateWithInput() {
MOUSEMSG m;
if (MouseHit()) {
m = GetMouseMsg();
if (m.uMsg == WM_LBUTTONDOWN) {
int clicked_j = int(m.y - BLOCK_SIZE / 2) / BLOCK_SIZE;
int clicked_i = int(m.x - BLOCK_SIZE / 2) / BLOCK_SIZE;
//首先应该判断点击次数,两种方法,静态变量,和成员变量
static int i = 1;
//第一次点击判断是否有棋子
if (i == 1) {
i++;
firstPoint->y = clicked_i;
firstPoint->x = clicked_j;
show();
}
else { //第二次点击
i = 1;
secondPoint->y = clicked_i;
secondPoint->x = clicked_j;
Move(Point(firstPoint->y, firstPoint->x), Point(secondPoint->y, secondPoint->x));
firstPoint->y = -1;
firstPoint->x = -1;
show();
}
}
}
}
主要图形化实现部分:游戏总体的框架为 startup()初始化, 然后无限循环show()和updateWithInput()直到得到游戏结果。
startup主要新建一个窗口,并且,设置一些基本参数。
show()主要绘制棋盘,楚河汉界的文字,棋子,如果出现胜利者需要宣布胜利
updateWithInput()主要读取鼠标状态,进行棋子的移动。
#include
#include
#include"Game.hpp"
using namespace std;
// 在此声明,Height为y为RowNum, Width为x为ColNum
int main() {
Game g;
g.startup();
while (1) {
g.show();
g.updateWithInput();
if (g.GetWinner() != NONE) {
break;
}
}
_getch();
closegraph();
return 0;
}
主程序主要执行程序框架。
执行效果如图:
可以看出,选择棋子的界面有点简陋,本来想做一个类似于直角引号的选择提示,但是发现代码量比直接画圆复杂很多,遂放弃。。。