Using C + + to realize Chinese chess

Posted by wtech on Mon, 24 Jan 2022 06:26:45 +0100

Project introduction

Recently, I learned about STL library and some practical containers. At the same time, I am also a chess lover. I wondered if I could make a chess game applet and use the knowledge I learned, so I started to do this project, which took about two days to basically complete, However, there are still some functions (general prompt, mandatory response, trapped death detection, etc.) that have not been done. We need to update and optimize them later. First, the figure above shows the effect. Let's see if there is anything to improve

Effect display

Original situation

In addition to the limited changes in the number of steps of the chessboard and artillery chess pieces, you can list all the changes of the current chess pieces, and then use the algorithm to judge whether the next step is reasonable. Unreasonable elimination (for example, if it is beyond the scope of the chessboard, the point of the next step is occupied by your own chess pieces, the soldiers cannot level before crossing the river, and the horses and elephants will be broken legs and stuffed with elephant eyes). The final result will prompt the player to make a choice, as shown in the figure:

Chessmen of cars and guns can walk in unlimited number of squares. It is troublesome to list all changes. Therefore, they are divided into multiple steps. Each step is based on one grid. Players can control the up, down, left and right movement through wsad keys (if they change other direction keys halfway, they will reset to the original position). If they are blocked by their own chessmen or want to go outside the chessboard, they will give a prompt. When they reach the fixed position, Players need to confirm whether to play chess. After confirmation, it's their turn to play chess. As shown in the figure:

Like the normal chess rules, generals can't face each other, but in the current program, players can go into this situation, and there will be an additional choice of flying generals. However, in most online games, players can't go into this situation. The software will restrict the movement, and there is no function of general prompt. The goal of winning the game is to eat the enemy's commander, As shown below:

If you want to exit the match, you can choose to sum or admit defeat. After outputting the match result, you will return to the main interface

Ask for a draw, agree

The draw request was rejected

When it is the turn of one side to play chess, if it admits defeat, it will be judged that one side is defeated and the other side wins

Project source code

There are many source codes, including many header files and source files. The class file of a single chess piece is almost 200 lines. Here are only some key source codes:

//Main.cpp - main menu interface
#include "Menu.h"
#include "Layout.h"
//Make a chess program
//1. Need a start menu
//2. PVP mode (no need to select red / Black options)
//3. Print a chessboard
//4. Print pieces on the chessboard
int main() {
	int tab;
	while (1) {
		Menu();
		cin >> tab;
		switch (tab)
		{
		case 0:
			cout << "The game has exited" << endl;
			system("pause");
			return 0;
		case 1:
			Layout();
			break;
		default:
			cout << "Please enter the correct option!" << endl;
			break;
		}
		system("cls");
	}
}

//Layout.cpp - game interface
#include "Layout.h"
#include "config.h"
//1. Print by line
//2. Print by column
//3. Judge the chess pieces
//4. Divide camps (1 for the red side and 0 for the black side)
//5. It is stored in a two-way array. The head interpolation method is put into the Red Square and the tail interpolation method is put into the black square, which is convenient for management
//6. Judge the current state of the chess piece before moving
//7. Write the walking rules and state detection of each chess piece in turn
//8. Test
deque<Chess*> Chess::d;
int Chess::tail;
int Chess::bound;
int tab;
int result;
bool isMore;
int mChessIndex;
void color(int a) {
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), a);
}
void Layout() {
	Chess::d = InitChess();
	while (1)
	{
		/*if (cin.fail()) {
			cin.clear();
			cin.ignore();
		}*/
		Board();
		int index;
		if (!isMore)
			index = selectChess();
		else
			index = mChessIndex;
		if (index == -1) {
			if (tab == 1) {
				cout << "The red side wants peace. Do you agree( Y.agree/N.(rejected)?" << endl;
			}
			if (tab == 0) {
				cout << "The black side wants peace. Do you agree( Y.agree/N.(rejected)?" << endl;
			}
			char confirm;
			cin >> confirm;
			if (confirm == 'Y' || confirm == 'y') {
				result = 2;
			}
			else {
				cout << "Rejected draw!" << endl;
				system("pause");
				tab = !tab;
			}
		}
		else if (index == -2) {
			cout << "Admit defeat( Y.confirm/N.Cancel)?" << endl;
			char confirm;
			cin >> confirm;
			if (confirm == 'Y' || confirm == 'y') {
				if (tab == 1) {
					result = 0;
				}
				if (tab == 0) {
					result = 1;
				}
			}
			else {
				cout << "Cancelled!" << endl;
				system("pause");
				tab = !tab;
			}
		}
		else if (index == -3) {
			cout << "Returned!" << endl;
			system("pause");
			tab = !tab;
		}
		else {
			if (!(Chess::d[index]->findRoad())) {
				//loop
				if (Chess::d[index]->isMoving) {
					//Incomplete move
					isMore = true;
				}
				else {
					//return
					isMore = false;
					cout << "Cancelled!" << endl;
					system("pause");
				}
				tab = !tab;
			}
			else {
				//Move complete
				isMore = false;
				cout << "Move complete!" << endl;
				Chess::d[index]->isMoving = false;
				system("pause");
			}
		}
		Check();
		if (result == 0) {
			cout << "The game is over, black wins and red loses!" << endl;
			system("pause");
			break;
		}
		if (result == 1) {
			cout << "The game is over, red wins and black loses!" << endl;
			system("pause");
			break;
		}
		if (result == 2) {
			cout << "Game over, draw!" << endl;
			system("pause");
			break;
		}
		tab = !tab;
	}
	for (int i = 0; i < Chess::tail + 1; i++) {
		//Release the space opened up by all chess pieces in the heap area
		delete Chess::d[i];
	}
}
void Board(){
	system("cls");
	cout << "1 ==2 ==3 ==4 ==5 ==6 ==7 ==8 ==9 " << endl;
	for (int y = 1; y < 11; y++) {
		for (int x = 1; x < 10; x++) {
			//Chess point position
			int obj = Chess::isHasChess(x, y);
			if (obj != -1) {
				//There are chess pieces
				if (Chess::d[obj]->m_Camp == 1) {
					//On behalf of Red Square
					color(64);
				}
				else {
					color(32);
					//On behalf of the black side
				}
				cout << Chess::d[obj]->m_Name;
				color(7);
			}
			else {
				//No chess pieces
				if (y == 5 || y == 6) {
					cout << LINE;
				}
				else {
					cout << NODE;
				}
			}
			//Chess point position
			if (x != 9) {
				cout << LINE;
			}
		}
		cout << endl;
		//Vertical line area, no need to judge whether there are chess pieces
		if (y != 10) {
			if (y == 5) {
				cout << "|      Chu River              Han Dynasty   | ";
			}
			else {
				for (int x = 1; x < 10; x++) {
					cout << VLINE;
					if (x != 9) {
						cout << spSign(x, y);
					}
				}
			}
			cout << endl;
		}
	}
	cout << "nine==eight==seven==six==five==four==three==two==one" << endl;
	if (tab == 1) {
		cout << "Now it's Red's turn to play chess:" << endl;
	}
	else {
		cout << "Now it's Black's turn to play chess:" << endl;
	}
	return;
}
void Check() {
	if (Chess::d[0]->isDead) {
		//Red handsome death
		result = 0;
	}
	if (Chess::d[Chess::tail]->isDead) {
		//Black will die
		result = 1;
	}
}
string spSign(int x, int y) {
	if (x == 4) {
		if (y == 1 || y == 8) {
			return BSLASH;
		}
		if (y == 2 || y == 9) {
			return SLASH;
		}
	}
	if (x == 5) {
		if (y == 1 || y == 8) {
			return SLASH;
		}
		if (y == 2 || y == 9) {
			return BSLASH;
		}
	}
	return SPACE;
}
deque<Chess*> InitChess() {
	tab = 1;
	result = 3;
	isMore = false;
	deque<Chess*> Rchess;
	Chess* jiang = new Jiang(0);
	Chess* shuai = new Jiang(1);
	//Leave blank ============================== leave blank//
	int k = 1;
	for (int i = 0; i < 2; i++) {
		Chess* BXiang = new Xiang(0, 5 + 2 * k);
		Rchess.push_back(BXiang);
		Chess* RXiang = new Xiang(1, 5 + 2 * k);
		Rchess.push_front(RXiang);
		Chess* Bshi = new Shi(0, 5 + k);
		Rchess.push_back(Bshi);
		Chess* Rshi = new Shi(1, 5 + k);
		Rchess.push_front(Rshi);
		Chess* pao = new Pao(0, 5 + 3 * k);
		Rchess.push_back(pao);
		Chess* bao = new Pao(1, 5 + 3 * k);
		Rchess.push_front(bao);
		Chess* Bma = new Ma(0, 5 + 3 * k);
		Rchess.push_back(Bma);
		Chess* Rma = new Ma(1, 5 + 3 * k);
		Rchess.push_front(Rma);
		Chess* che = new Che(0, 5 + 4 * k);
		Rchess.push_back(che);
		Chess* ju = new Che(1, 5 + 4 * k);
		Rchess.push_front(ju);
		k = -k;
	}
	for (int x = 1; x < 10; x += 2) {
		Chess* zu = new Bing(0, x);
		Rchess.push_back(zu);
		Chess* bing = new Bing(1, x);
		Rchess.push_front(bing);
	}
	Rchess.push_back(jiang);
	Rchess.push_front(shuai);
	//cout << Rchess.size();
	Chess::tail = Rchess.size() - 1;
	Chess::bound = Rchess.size() / 2;
	return Rchess;
}
int selectChess() {
	deque<int> index_j; //veteran
	deque<int> index_b; //soldier
	deque<int> index_c; //vehicle
	deque<int> index_m; //horse
	deque<int> index_p; //cannon
	deque<int> index_s; //Scholar
	deque<int> index_x; //as
	int select;//choice
	cout << "Please select the pieces you want to play:" << endl;
	cout << "(";
	if (tab == 1) {
		//Red Square moves chess and traverses the total number of red square pieces
		deque<int> r_d = Chess::getRchess();
		for (int i = 0; i < r_d.size(); i++) {
			if (Chess::d[r_d[i]]->m_Name == "Handsome") {
				if (index_j.empty())
					cout << "1. Handsome ";
				index_j.push_back(r_d[i]);
			}
			if (Chess::d[r_d[i]]->m_Name == "soldier") {
				if (index_b.empty())
					cout << "2. soldier ";
				index_b.push_back(r_d[i]);
			}
			if (Chess::d[r_d[i]]->m_Name == "Car") {
				if (index_c.empty())
					cout << "3. Car ";
				index_c.push_back(r_d[i]);
			}
			if (Chess::d[r_d[i]]->m_Name == "Horses") {
				if (index_m.empty())
					cout << "4. Horses ";
				index_m.push_back(r_d[i]);
			}
			if (Chess::d[r_d[i]]->m_Name == "Cannon") {
				if (index_p.empty())
					cout << "5. Cannon ";
				index_p.push_back(r_d[i]);
			}
			if (Chess::d[r_d[i]]->m_Name == "Official") {
				if (index_s.empty())
					cout << "6. Official ";
				index_s.push_back(r_d[i]);
			}
			if (Chess::d[r_d[i]]->m_Name == "mutually") {
				if (index_x.empty())
					cout << "7. mutually ";
				index_x.push_back(r_d[i]);
			}
		}
	}
	if (tab == 0) {
		//Black square moves chess and traverses the total number of black square pieces
		deque<int> b_d = Chess::getBchess();
		for (int i = 0; i < b_d.size(); i++) {
			if (Chess::d[b_d[i]]->m_Name == "take") {
				if (index_j.empty())
					cout << "1. take ";
				index_j.push_back(b_d[i]);
			}
			if (Chess::d[b_d[i]]->m_Name == "Pawn") {
				if (index_b.empty())
					cout << "2. Pawn ";
				index_b.push_back(b_d[i]);
			}
			if (Chess::d[b_d[i]]->m_Name == "vehicle") {
				if (index_c.empty())
					cout << "3. vehicle ";
				index_c.push_back(b_d[i]);
			}
			if (Chess::d[b_d[i]]->m_Name == "horse") {
				if (index_m.empty())
					cout << "4. horse ";
				index_m.push_back(b_d[i]);
			}
			if (Chess::d[b_d[i]]->m_Name == "cannon") {
				if (index_p.empty())
					cout << "5. cannon ";
				index_p.push_back(b_d[i]);
			}
			if (Chess::d[b_d[i]]->m_Name == "Scholar") {
				if (index_s.empty())
					cout << "6. Scholar ";
				index_s.push_back(b_d[i]);
			}
			if (Chess::d[b_d[i]]->m_Name == "as") {
				if (index_x.empty())
					cout << "7. as ";
				index_x.push_back(b_d[i]);
			}
		}
	}
	cout << " 9. Sum 0.(admit defeat)" << endl;
retry:
	cin >> select;
	if (cin.fail()) {
		cin.clear();
		cin.ignore();
		select = -1;
	}
	switch (select)
	{
	case 1:
		return index_j[0];
	case 2:
		if (!(index_b.empty())){
			return selectChess(index_b);
		}
	case 3:
		if (!(index_c.empty())) {
			isMore = true;
			//Store the subscripts of multi step chess with global variables
			mChessIndex = selectChess(index_c);
			return mChessIndex;
		}
	case 4:
		if (!(index_m.empty())) {
			return selectChess(index_m);
		}
	case 5:
		if (!(index_p.empty())) {
			isMore = true;
			//Store the subscripts of multi step chess with global variables
			mChessIndex = selectChess(index_p);
			return mChessIndex;
		}
	case 6:
		if (!(index_s.empty())) {
			return selectChess(index_s);
		}
	case 7:
		if (!(index_x.empty())) {
			return selectChess(index_x);
		}
	case 9:
		return -1;
	case 0:
		return -2;
	default:
		cout << "The chess piece is dead or there is no such piece! Please reselect" << endl;
		goto retry;
	}
	return 0;
}
int selectChess(deque<int> ds) {
	int num = ds.size(); //How many pieces are there in the current arms
	int select;
	cout << "Please select:";
	if (Chess::d[ds[0]]->m_Camp == 1) {
		for (int i = 0; i < num; i++) {
			cout << i + 1 << ". " << Chess::d[ds[i]]->m_Name << Chess::d[ds[i]]->xNumToChar() << " ";
		}
	}
	if (Chess::d[ds[0]]->m_Camp == 0) {
		for (int i = 0; i < num; i++) {
			cout << i + 1 << ". " << Chess::d[ds[i]]->m_Name << Chess::d[ds[i]]->getPos().m_x << " ";
		}
	}
	cout << "0. return" << endl;
retry2:
	cin >> select;
	switch (select)
	{
	case 1:
		return ds[0];
		break;
	case 2:
		if(select<=num)
			return ds[1];
		break;
	case 3:
		if (select <= num)
			return ds[2];
		break;
	case 4:
		if (select <= num)
			return ds[3];
		break;
	case 5:
		if (select <= num)
			return ds[4];
		break;
	case 0:
		isMore = false;
		return -3;
	default:
		break;
	}
	cout << "The chess piece is dead or there is no such piece! Please reselect" << endl;
	goto retry2;
}

//Layout.h
#pragma once
#include <deque>
#include "Chess.h"
#define LINE "—"
#define VLINE "| "
#define SPACE "  "
#define SLASH "/ "
#define BSLASH "\\ "
#define BSLASH "\\ "
#define NODE "+ "

void color(int a);
void Layout();
void Board();
void Check();
string spSign(int x,int y);
int selectChess();
int selectChess(deque<int>);
deque<Chess*> InitChess();

/*
    Original situation
	cout << "1 ==2 ==3 ==4 ==5 ==6 ==7 ==8 ==9 " <<endl;
 	cout << "Car horse elephant gentleman general gentleman elephant horse car "< < endl;
	cout << "|   |   |   | \\ | / |   |   |   | " << endl;
	cout << "+ —+ —+ —+ —+ —+ —+ —+ —+ " << endl;
	cout << "|   |   |   | / | \\ |   |   |   | " << endl;
	cout << "+ —Gun - + - + - + - + - + - + - + - gun - + "< < endl;
	cout << "|   |   |   |   |   |   |   |   | " << endl;
	cout << "Stroke - + - stroke - + - stroke - + - stroke - + - stroke - + - stroke "< < endl;
	cout << "|   |   |   |   |   |   |   |   | " << endl;
	cout << "--------—" << endl;
	cout << "|      Chu River Han boundary "< < endl;
	cout << "--------—" << endl;
	cout << "|   |   |   |   |   |   |   |   | " << endl;
	cout << "Soldier - + - Soldier - + - Soldier - + - Soldier - + - soldier "< < endl;
	cout << "|   |   |   |   |   |   |   |   | " << endl;
	cout << "+ —Gun - + - + - + - + - + - + - + - gun - + "< < endl;
	cout << "|   |   |   | \\ | / |   |   |   | " << endl;
	cout << "+ —+ —+ —+ —+ —+ —+ —+ —+ " << endl;
	cout << "|   |   |   | / | \\ |   |   |   | " << endl;
	cout << "Car horse phase official handsome official phase horse car "< < endl;
	cout << "Nine = = eight = = seven = = six = = five = = four = = three = = two = = one "< < endl;
*/
/*
	Empty chessboard
	cout << "1 ==2 ==3 ==4 ==5 ==6 ==7 ==8 ==9 " <<endl;
	cout << "+ —+ —+ —+ —+ —+ —+ —+ —+ " << endl;
	cout << "|   |   |   | \\ | / |   |   |   | " << endl;
	cout << "+ —+ —+ —+ —+ —+ —+ —+ —+ " << endl;
	cout << "|   |   |   | / | \\ |   |   |   | " << endl;
	cout << "+ —+ —+ —+ —+ —+ —+ —+ —+ " << endl;
	cout << "|   |   |   |   |   |   |   |   | " << endl;
	cout << "+ —+ —+ —+ —+ —+ —+ —+ —+ " << endl;
	cout << "|   |   |   |   |   |   |   |   | " << endl;
	cout << "--------—" << endl;
	cout << "|      Chu River Han boundary "< < endl;
	cout << "--------—" << endl;
	cout << "|   |   |   |   |   |   |   |   | " << endl;
	cout << "+ —+ —+ —+ —+ —+ —+ —+ —+ " << endl;
	cout << "|   |   |   |   |   |   |   |   | " << endl;
	cout << "+ —+ —+ —+ —+ —+ —+ —+ —+ " << endl;
	cout << "|   |   |   | \\ | / |   |   |   | " << endl;
	cout << "+ —+ —+ —+ —+ —+ —+ —+ —+ " << endl;
	cout << "|   |   |   | / | \\ |   |   |   | " << endl;
	cout << "+ —+ —+ —+ —+ —+ —+ —+ —+ " << endl;
	cout << "Nine = = eight = = seven = = six = = five = = four = = three = = two = = one "< < endl;
*/

//config.h --------------- required header file library
#pragma once
#include "Jiang.h"
#include "Bing.h"
#include "Shi.h"
#include "Xiang.h"
#include "Che.h"
#include "Pao.h"
#include "Ma.h"

There are many other pieces of the source code, which will not be shown here one by one. If you want to know all the source code, you can go to GitHub - LunarMeal/Chess Take it yourself

More features

The next step is to complete the detection and prompt by the general, and then force the player to be the player on this basis (but I think it's better not to force the player to be the player. Let the player explore like playing chess in reality). Then complete the import and export function of chess score (you can print a txt file according to the current chess shape and save it, and then add a function of importing chess score in the main menu interface to obtain the information of all chess pieces to continue the current game. Of course, you can also write your own chess score according to the format)

Topics: C++ Visual Studio