C++练习实例———中国象棋小游戏

通过在控制台输出字符来实现一个中国象棋小游戏实际上是很简单的,也非常有趣。游戏是人人对战模式,实现后的效果如下:

代码思路很简单,就是创建好各个游戏对象的类,然后用一个管理类来实现规则就可以了。下面直接上代码:

Point类

#ifndef POINT_H
#define POINT_H
#include<iostream>
using namespace std;
//坐标类
class Point
{
public:
	Point(int x = 0, int y = 0) : m_x(x), m_y(y) {};
	~Point() {};
	Point& operator=(const Point &p)
	{
		m_x = p.m_x;
		m_y = p.m_y;
		return *this;
	}
	bool operator==(const Point &p)const {
		if (m_x == p.m_x&&m_y == p.m_y)
			return true;
		else return false;
	}
	void Set(const int x, const int y) { m_x = x; m_y = y; }
	void SetX(const int x) { m_x = x; }
	void SetY(const int y) { m_y = y; }
	int GetX() const { return m_x; }
	int GetY()const { return m_y; }

private:
	int m_x;
	int m_y;
};
#endif

 Chess类

#ifndef CHESS_H
#define CHESS_H

#include"Point.h"

enum ChessCamp//棋子阵营(红绿两方)
{
	RED,GREEN
};

enum ChessType//棋子种类
{
	MA,SHUAI,CHE,PAO,SHI,BING,XIANG
};

class Chess
{
public:
	Chess(ChessType type, ChessCamp camp, Point position) 
		:m_type(type),m_camp(camp),m_position(position)
	{}
	~Chess(){}

	Point GetPosition()const { return m_position; }
	void SetPosition(const Point& newposition) { m_position = newposition; }
	ChessType GetType()const { return m_type; }
	ChessCamp GetCamp()const { return m_camp; }

private:
	ChessType m_type;
	ChessCamp m_camp;
	Point m_position;

};

#endif // !CHESS_H

ChessBoard(棋盘)类

#ifndef CHESSBOARD_H
#define CHESSBOARD_H

#include<Windows.h>
#include"chess.h"

class ChessBoard
{
public:
	bool m_isend;

	ChessBoard();
	~ChessBoard() {}

	void PrintBoard();
	void ChangeChess(const Point& spos, const Point& tpos);
	Chess* GetChess(const Point& pos)const
	{
		return m_allchess[pos.GetX()][pos.GetY()];
	}
	void Clear() {
		for (int i = 0; i < 10; i++)
		{
			for (int j = 0; j < 9; j++)
			{
				if (m_allchess[i][j] != nullptr) 
				{
					delete m_allchess[i][j];
					m_allchess[i][j] = nullptr;
				}
			}
		}
	}

private:
	Chess* m_allchess[10][9];
};
#endif 
#include"ChessBoard.h"

ChessBoard::ChessBoard()
{
	m_isend = false;
	for (int i = 0; i < 10; i++)
	{
		for (int j = 0; j < 9; j++)
			m_allchess[i][j] = nullptr;
	}
	//四个车
	m_allchess[0][0] = new Chess(CHE, GREEN, Point(0, 0));
	m_allchess[0][8] = new Chess(CHE, GREEN, Point(0, 8));
	m_allchess[9][0] = new Chess(CHE, RED, Point(9, 0));
	m_allchess[9][8] = new Chess(CHE, RED, Point(9, 8));
	//四个马
	m_allchess[0][1] = new Chess(MA, GREEN, Point(0, 1));
	m_allchess[0][7] = new Chess(MA, GREEN, Point(0, 7));
	m_allchess[9][1] = new Chess(MA, RED, Point(9, 1));
	m_allchess[9][7] = new Chess(MA, RED, Point(9, 7));
	//四个炮
	m_allchess[2][1] = new Chess(PAO, GREEN, Point(2, 1));
	m_allchess[2][7] = new Chess(PAO, GREEN, Point(2, 7));
	m_allchess[7][1] = new Chess(PAO, RED, Point(7, 1));
	m_allchess[7][7] = new Chess(PAO, RED, Point(7, 7));
	//两个帅
	m_allchess[0][4] = new Chess(SHUAI, GREEN, Point(0, 4));
	m_allchess[9][4] = new Chess(SHUAI, RED, Point(9, 4));
	//象
	m_allchess[0][2] = new Chess(XIANG, GREEN, Point(0, 2));
	m_allchess[0][6] = new Chess(XIANG, GREEN, Point(0, 6));
	m_allchess[9][2] = new Chess(XIANG, RED, Point(9, 2));
	m_allchess[9][6] = new Chess(XIANG, RED, Point(9, 6));
	//士
	m_allchess[0][3] = new Chess(SHI, GREEN, Point(0, 3));
	m_allchess[0][5] = new Chess(SHI, GREEN, Point(0, 5));
	m_allchess[9][3] = new Chess(SHI, RED, Point(9, 3));
	m_allchess[9][5] = new Chess(SHI, RED, Point(9, 5));
	//兵
	for (int i = 0; i <= 8; i += 2)
		m_allchess[3][i] = new Chess(BING, GREEN, Point(3, i));
	for (int i = 0; i <= 8; i += 2)
		m_allchess[6][i] = new Chess(BING, RED, Point(6, i));

}

void ChessBoard::PrintBoard()
{
	for (int i = 0; i < 10; i++)
	{
		//输出上排坐标或河界
		if (i == 0 || i == 5)
		{
			cout << "  ";
			for (int j = 0; j < 9; j++)
			{
				if (i == 0)cout << j << " ";//上排坐标
				if (i == 5)cout << "一";//河界
			}
			cout << endl;
		}

		for (int j = 0; j < 9; j++)
		{
			if (j == 0) cout << i << " ";//左排坐标
			if (m_allchess[i][j] == nullptr)
			{
				if (i == 8 && j == 4 || i == 1 && j == 4)cout << "米";//九宫格
				else cout << "十";//没有棋子
			}
			else
			{
				//根据阵营设置颜色
				if (m_allchess[i][j]->GetCamp() == GREEN)
					SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN);

				if (m_allchess[i][j]->GetCamp() == RED)
					SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED);

				if (m_allchess[i][j]->GetType() == CHE)cout << "车";
				if (m_allchess[i][j]->GetType() == MA)cout << "马";
				if (m_allchess[i][j]->GetType() == SHUAI)cout << "帅";
				if (m_allchess[i][j]->GetType() == PAO)cout << "炮";
				if (m_allchess[i][j]->GetType() == XIANG)cout << "象";
				if (m_allchess[i][j]->GetType() == SHI)cout << "士";
				if (m_allchess[i][j]->GetType() == BING)cout << "兵";

				//恢复默认颜色(白色)
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
			}
		}
		cout << endl;
	}
}

void ChessBoard::ChangeChess(const Point & spos, const Point & tpos)
{
		if (m_allchess[tpos.GetX()][tpos.GetY()] != nullptr)
		{
			//如果把帅吃了,游戏结束
			if (m_allchess[tpos.GetX()][tpos.GetY()]->GetType() == SHUAI)m_isend = true;

			delete m_allchess[tpos.GetX()][tpos.GetY()];
		}
		m_allchess[tpos.GetX()][tpos.GetY()] = m_allchess[spos.GetX()][spos.GetY()];
		m_allchess[spos.GetX()][spos.GetY()] = nullptr;
}

GameManager类,控制核心玩法

#ifndef GameManager_H
#define GameManager_H
#include"ChessBoard.h"

class GameManager
{
public:
	~GameManager() { m_chessboard.Clear(); }//严格意义上说单例模式析构应该为私有 但有时编译会出问题

	bool Move(const Point& startpos,const Point& targetpos);
	void ChangeCamp() 
	{
		if (m_nowcamp == RED)m_nowcamp = GREEN;
		else m_nowcamp = RED;
	}
	ChessCamp GetCamp()const{ return m_nowcamp; }
	void Print(){	m_chessboard.PrintBoard();}
	bool IsEnd()const { return m_chessboard.m_isend; }

	static GameManager*Instance();//单例模式
private:
	ChessBoard m_chessboard;
	ChessCamp m_nowcamp;

	//单例模式 构造函数为私有
	GameManager()
	{
		m_nowcamp = RED;
		m_chessboard= ChessBoard();
	}
	bool JudgeMoveLegel(const Point& startpos,const Point& targetpos);//判断移动是否符合棋盘规定
	bool JudgeMoveChessRule(const Point& startpos,const Point& targetpos);//判断移动是否符合棋子的规则
	int JudgeChessBetween(const Point& startpos,const Point& targetpos);//返回两点之间棋子的数目
	bool JudgeCrossRiver(const Point&pos);//判断棋子是否过河
};
#endif // !GameManager_H
#include"GameManager.h"

//单例模式
GameManager * GameManager::Instance()
{
	static GameManager instance;
	return &instance;
}

bool GameManager::JudgeMoveLegel(const Point& startpos, const Point& targetpos)
{
	//若目标位置和起始位置相同,错误
	if (startpos == targetpos)return false;
	//如果起始选定位置没有棋子,或棋子阵营与当前玩家不一致,错误
	if (m_chessboard.GetChess(startpos) == nullptr ||
		m_chessboard.GetChess(startpos)->GetCamp() != m_nowcamp)
		return false;
	//如果目标位置越界,错误
	if (targetpos.GetX() < 0 || targetpos.GetX() > 9 ||
		targetpos.GetY() < 0 || targetpos.GetY() > 8)
		return false;
	//如果目标和起始是一个阵营,错误
	if (m_chessboard.GetChess(targetpos)!=nullptr&&
		m_chessboard.GetChess(startpos)->GetCamp() == m_chessboard.GetChess(targetpos)->GetCamp())
		return false;

	return true;
}

bool GameManager::JudgeMoveChessRule(const Point& startpos, const Point& targetpos)
{
	//若是车
	if (m_chessboard.GetChess(startpos)->GetType() == CHE)
	{
		if (startpos.GetX() == targetpos.GetX() || startpos.GetY() == targetpos.GetY())//目标和起始在一条直线上
			if (!JudgeChessBetween(startpos, targetpos))//中间没有棋子
				return true;
	}
	//若是炮
	else if (m_chessboard.GetChess(startpos)->GetType() == PAO)
	{
		if (m_chessboard.GetChess(targetpos) == nullptr)//若不用吃子
		{
			if (startpos.GetX() == targetpos.GetX() || startpos.GetY() == targetpos.GetY())
				if (!JudgeChessBetween(startpos, targetpos))
					return true;
		}
		else //若要吃子
		{
			if (startpos.GetX() == targetpos.GetX() || startpos.GetY() == targetpos.GetY())
				if (JudgeChessBetween(startpos, targetpos) == 1)
					return true;
		}
	}
	//若是马
	else if (m_chessboard.GetChess(startpos)->GetType() == MA)
	{
		int	tempx = targetpos.GetX() - startpos.GetX();
		int tempy = targetpos.GetY() - startpos.GetY();
		//若形成日字,并且没有憋马腿
		if (tempx*tempx + tempy*tempy == 5 &&
			m_chessboard.GetChess(Point(startpos.GetX() + tempx / 2, startpos.GetY() + tempy / 2)) == nullptr)
			return true;
	}
	//若是士
	else if (m_chessboard.GetChess(startpos)->GetType() == SHI)
	{
		int tempx = targetpos.GetX() - startpos.GetX();
		int tempy = targetpos.GetY() - startpos.GetY();
		if ((tempx*tempx + tempy*tempy == 2) && (targetpos.GetY()<= 5) && (targetpos.GetY() >=3) && (targetpos.GetX() >= 7 || targetpos.GetX() <= 2))
			return true;
	}
	//若是帅
	else if (m_chessboard.GetChess(startpos)->GetType() == SHUAI)
	{
		int tempx = targetpos.GetX() - startpos.GetX();
		int tempy = targetpos.GetY() - startpos.GetY();
		if ((tempx*tempx + tempy*tempy == 1) && (targetpos.GetY() <= 5) && (targetpos.GetY() >= 3) && (targetpos.GetX() >= 7 || targetpos.GetX() <= 2))
			return true;
	}
	//若是象
	else if (m_chessboard.GetChess(startpos)->GetType() == XIANG)
	{
		int	tempx = targetpos.GetX() - startpos.GetX();
		int tempy = targetpos.GetY() - startpos.GetY();
		//若形成田字,并且没有踩象眼
		if (tempx*tempx + tempy*tempy == 8 &&
			m_chessboard.GetChess(Point(startpos.GetX() + tempx / 2, startpos.GetY() + tempy / 2)) == nullptr)
			//没有将要过河
			if(m_chessboard.GetChess(startpos)->GetCamp() == RED&&targetpos.GetX() >4||
				m_chessboard.GetChess(startpos)->GetCamp() == GREEN&&targetpos.GetX() <5)
			return true;
	}
	//若是兵
	else if (m_chessboard.GetChess(startpos)->GetType() == BING)
	{
		int	tempx = targetpos.GetX() - startpos.GetX();
		int tempy = targetpos.GetY() - startpos.GetY();
		if (tempx*tempx + tempy*tempy == 1)//走了一步
		{
			if (JudgeCrossRiver((startpos)))//若过河了
				return true;

			else //还没过河
			{
				//若是往前走
				if (m_chessboard.GetChess(startpos)->GetCamp() == RED&&tempx == -1 ||
					m_chessboard.GetChess(startpos)->GetCamp() == GREEN&&tempx == 1)
					return true;
			}
		}
	}
	return false;
}

bool GameManager::Move(const Point& startpos, const Point& targetpos)
{
	if (JudgeMoveLegel(startpos, targetpos) && JudgeMoveChessRule(startpos, targetpos))
	{
		m_chessboard.ChangeChess(startpos, targetpos);
		return true;
	}
	else return false;
}

int GameManager::JudgeChessBetween(const Point& startpos, const Point& targetpos)
{
	int num = 0;
	//若两点x轴相等
	if (startpos.GetX() == targetpos.GetX())
	{
		int x = startpos.GetX();
		if (startpos.GetY() > targetpos.GetY())
		{
			for (int i = targetpos.GetY() + 1; i < startpos.GetY(); i++)
			{
				if (m_chessboard.GetChess(Point(x, i)) != nullptr)num++;
			}
		}
		else
		{
			for (int i = startpos.GetY() + 1; i < targetpos.GetY(); i++)
			{
				if (m_chessboard.GetChess(Point(x, i)) != nullptr)num++;
			}
		}
	}
	//若两点y轴相等
	else if (startpos.GetY() == targetpos.GetY())
	{
		int y = startpos.GetY();
		if (startpos.GetX() > targetpos.GetX())
		{
			for (int i = targetpos.GetX() + 1; i < startpos.GetX(); i++)
			{
				if (m_chessboard.GetChess(Point(i, y)) != nullptr)num++;
			}
		}
		else
		{
			for (int i = startpos.GetX() + 1; i < targetpos.GetX(); i++)
			{
				if (m_chessboard.GetChess(Point(i, y)) != nullptr)num++;
			}
		}
	}
	return num;
}

bool GameManager::JudgeCrossRiver(const Point & pos)
{
	if (m_chessboard.GetChess(pos)->GetCamp() == RED&&pos.GetX() < 5)
		return true;
	if (m_chessboard.GetChess(pos)->GetCamp() == GREEN&&pos.GetX() > 4)
		return true;
	return false;
}

main函数

#include"GameManager.h"
#define mymanager GameManager::Instance()

int main()
{
	cout << "    中国象棋" <<  endl;
	cout << "****************" << endl << endl;
	cout << "  1.开始游戏" << endl << endl;
	cout << "    2.退出" << endl << endl;
	cout << "****************" << endl << endl;
	cout << "请输入选项:" << endl;
	int c(0);
	cin >> c;
	if (c == 1)
	{
		mymanager->Print();
		while (1)
		{
			if (mymanager->GetCamp() == RED)cout << "现在轮到红方" << endl;
			else cout << "现在轮到绿方" << endl;

			cout << "输入起始点和目标点:";
			int sx, sy, tx, ty;
			cin >> sx >> sy >> tx >> ty;
			if (mymanager->Move(Point(sx, sy), Point(tx, ty)))
			{
				mymanager->Print();
				if (mymanager->IsEnd())
				{
					cout << "游戏结束!获胜方为:";
					if (mymanager->GetCamp() == RED)cout << "红方" << endl;
					else cout << "绿方" << endl;
					break;
				}
				mymanager->ChangeCamp();
			}
			else cout << "输入违法,请重新输入" << endl;
		}
	}
	if (c == 2)exit(0);
	cin.get();
	return 0;
}

谢谢观看:)

猜你喜欢

转载自blog.csdn.net/qq_37553152/article/details/82842318