基于C++的五子棋项目

一、五子棋项目介绍

1.游戏规则

五子棋是我国古代传统的黑白棋种之一,黑白双方依次落子,任意一方在棋盘上形成横向、纵向、斜向的连续相同颜色的五颗棋子的一方为胜。

2.完成界面显示

此次项目将不使用任何图形库进行开发,所有显示的内容都是以字符的形式进行显示。

二、棋子对象

1.棋子类

关于棋子类我们可以做如下几点思考:
由于黑棋和白棋的显示是不同的,棋子类的显示方法是不知道如何实现的,所以它是一个抽象类。每棵棋子在棋盘的不同位置存放,所以它应该包含棋子在屏幕上面的具体坐标。
每颗棋子都有自己的颜色,所以它应该包含颜色。

棋子类代码如下:

#ifndef CHESS_HPP
#define CHESS_HPP

#include <iostream>
#include <cstdio>

using namespace std;

class Chess
{
public:
	Chess(int x,int y,char color) : x(x),y(y),color(color)
	{

	}

	virtual ~Chess() {}

	virtual void show() = 0;

	int getX() const
	{
		return x;
	}

	int getY() const
	{
		return y;
	}

	char getColor() const
	{
		return color;
	}
private:
	int x;
	int y;
	char color;
};

#endif

2.黑棋类

黑棋类应该继承棋子类,然后实现棋子类的void show(void) const函数,在这个函数中显示黑色棋子。

黑棋类代码如下:

#ifndef BLACKCHESS_HPP
#define BLACKCHESS_HPP

#include "Chess.hpp"
#include "Config.hpp"

class BlackChess : public Chess
{
public:
	BlackChess(int x,int y) : Chess(x,y,BLACK)
	{

	}

	void show()
	{
		printf("\033[%d;%dH%s",getY(),getX()-1,BLACK_COLOR);
		printf("\033[%d;%dH",getY(),getX());//光标归位
	}
};

#endif

3.白棋类

 白棋类应该继承棋子类,然后实现棋子类的void show(void) const函数,在这个函数中显示白色棋子。

白棋类代码如下:

#ifndef WHITE_HPP
#define WHITE_HPP

#include "Chess.hpp"
#include "Config.hpp"

class WhiteChess : public Chess
{
public:
	WhiteChess(int x,int y) : Chess(x,y,WHITE)
	{

	}

	void show()
	{
		printf("\033[%d;%dH%s",getY(),getX()-1,WHITE_COLOR);
		printf("\033[%d;%dH",getY(),getX());//光标归位
	}
};

#endif

 三、棋盘对象

棋盘对象只有—个,我们可以使用单例模式来设计

1.显示棋盘

棋盘已经在chessBoard.txt文件中存放,只需要将这个文件中的棋盘读取出来然后在终端上面显示就可以了。


链接:https://pan.baidu.com/s/113G9XCGdn1F0SKX_z6h1IQ   提取码:eoks

 2.存放棋子

整个棋盘有15行和15列构成,我们把每个棋子都看成是一个对象,我们只需要记录这些对象的首地址就可以了,可以用一个二维的指针数组存放。

3.落子位置是否有效

如果落子位置已经有棋子了则返回false ,如果落子位置没有棋子则返回true 。

棋盘类代码如下:

#ifndef CHESSBOARD_HPP
#define CHESSBOARD_HPP

#include "Chess.hpp"
#include "Config.hpp"
#include <errno.h>
#include <cstring>

class ChessBoard
{
public:
	static ChessBoard* getInstance()
	{
		return cb;
	}
	
	void show()
	{
		char buf[1024] = {0};
		FILE *fp = fopen(CHESS_BOARD_FILE,"r");
		if(fp == NULL)
		{
			fprintf(stderr,"Fail to open ChessBoard.txt: %s\n",strerror(errno));
			return ;
		}
		cout << "\033[1;1H" << CHESS_BOARD_COLOR;
		while(fgets(buf,sizeof(buf),fp) != NULL)
		{
			fputs(buf,stdout);
		}

		fclose(fp);
		cout << "\033[0m";
	}

	bool isValidPostion(int line,int column)
	{
		if(line >= LINE || line < 0 || column >= COLUMN || column < 0)
		{
			return false;
		}
		return chess[line][column] == NULL ? true : false;
	}

	bool placeChess(Chess *chess)
	{
		int line = (chess->getY() - 1)/LINE_INTERVAL;
		int column = (chess->getX() - 1)/COLUMN_INTERVAL;

		if(isValidPostion(line,column))
		{
			this->chess[line][column] = chess;
			chess->show();
			curLine = line;
			curColumn = column;
			return true;
		}
		return false;
	}

	bool isValidColorChess(int line,int column,char color)
	{
		if(line < 0 || line >= LINE || column < 0 || column >= COLUMN)
		{
			return false;
		}

		Chess *ch = chess[line][column];
		if(ch == NULL)
		{
			return false;
		}

		if(ch->getColor() != color)
		{
			return false;
		}
		return true;
	}

	int getCurLine() const
	{
		return curLine;
	}

	int getCurColumn() const
	{
		return curColumn;
	}

private:
	ChessBoard() : curLine(-1),curColumn(-1)
	{
		for(int i = 0; i < LINE; ++i)
		{
			for(int j = 0; j < COLUMN; ++j)
			{
				chess[i][j] = NULL;
			}
		}
	}

	~ChessBoard()
	{

	}

	static ChessBoard *cb;
	Chess *chess[LINE][COLUMN];
	int curLine;
	int curColumn;
};

ChessBoard *ChessBoard::cb = new ChessBoard;

#endif

四、棋手对象

五子棋游戏中有两个玩家,一个玩家下黑旗,一个玩家下白旗。每个玩家至少包含以下成员:

1.玩家的名字 2.玩家下棋的棋子颜色  3.在棋盘落子的方法

1.玩家类

#ifndef PLAYER_HPP
#define PLAYER_HPP

#include<iostream>

using namespace std;

class Player
{
public:
	Player(const string &name,char color) : name(name),color(color)
	{

	}

	virtual ~Player() {}

	char getColor() const
	{
		return color;
	}

	string getName() const
	{
		return name;
	}

	virtual bool placeChess(int x, int y) = 0;

private:
	string name;
	char color;
};

#endif

2.黑棋玩家类

#ifndef BLACKPLAYER_HPP
#define BLACKPLAYER_HPP

#include "Player.hpp"
#include "Config.hpp"
#include "ChessBoard.hpp"
#include "BlackChess.hpp"

class BlackPlayer : public Player
{
public:
	BlackPlayer(const string &name) : Player(name,BLACK)
	{

	}

	bool placeChess(int x,int y)
	{
		BlackChess *bc = new BlackChess(x,y);
		if(!ChessBoard::getInstance()->placeChess(bc))
		{
			delete bc;
			return false;
		}
		return true;
	}
};

#endif

3.白棋玩家类

#ifndef WHITEPLAYER_HPP
#define WHITEPLAYER_HPP

#include "Player.hpp"
#include "Config.hpp"
#include "ChessBoard.hpp"
#include "WhiteChess.hpp"

class WhitePlayer : public Player
{
public:
	WhitePlayer(const string &name) : Player(name,WHITE)
	{

	}

	bool placeChess(int x,int y)
	{
		WhiteChess *bc = new WhiteChess(x,y);
		if(!ChessBoard::getInstance()->placeChess(bc))
		{
			delete bc;
			return false;
		}
		return true;
	}
};

#endif

五、按键方向控制类

在五子棋项目中,我们通过W/A/S/D/Space五个按键来做控制,这五个按键的功能如下;
W将光标向前移动,即将当前光标y轴坐标-2
S将光标向后移动,即将当前光标y轴坐标+2
A将光标向左移动,即将当前光标x轴坐标 - 4
D将光标向右移动,即将当前光标x轴坐标+4
Space空格键,用来控制落子

终端属性设置:

方向类代码如下:
 

#ifndef KEYHANDLE_HPP
#define KEYHANDLE_HPP

#include "Cursor.hpp"
#include "Player.hpp"
#include <termios.h>
#include <unistd.h>
#include <cstdlib>

class KeyHandle
{
public:
	KeyHandle()
	{
#if 0
		struct termios attr;
		tcgetattr(0,&attr);
		attr.c_lflag &= ~(ICANON | ECHO);
		tcsetattr(0,TCSANOW,&attr);
#else
		system("stty -icanon");
		system("stty -echo");
#endif
	}

	~KeyHandle()
	{
#if 0
     	struct termios attr;
		tcgetattr(0,&attr);
		attr.c_lflag |= (ICANON | ECHO);
		tcsetattr(0,TCSANOW,&attr);
#else
		system("stty icanon");
		system("stty echo");
#endif
	}
	
	bool waitPlayerPlaceChess(Player *player)
	{
		char key = '\0';
		bool ret = false;
		while(1)
		{
			key = getchar();
			switch(key)
			{
				case 'w':
				case 'W':
					cursor.moveUp();
					break;
				case 's':
				case 'S':
					cursor.moveDown();
					break;
				case 'a':
				case 'A':
					cursor.moveLeft();
					break;
				case 'd':
				case 'D':
					cursor.moveRight();
					break;
				case ' ':
					ret = player->placeChess(cursor.getX(),cursor.getY());
					break;
			}
			if(ret)
			{
				break;
			}
		}
	}

private:
	Cursor cursor;

};

#endif

 六、裁判类

给出当前可以落子的棋手是谁
判断当前在棋盘上落子的棋子是否构成了五颗相同的棋子(赢棋)显示获得胜利的棋手

裁判类代码如下:

#ifndef ARBITRATION_HPP
#define ARBITRATION_HPP

#include "ChessBoard.hpp"

class Arbitration
{
public:
	bool isWin(char color)
	{
		ChessBoard *cb = ChessBoard::getInstance();
		int curLine = cb->getCurLine();
		int curColumn = cb->getCurColumn();
		bool ret = false;
		ret = isDirectionWin(curLine,curColumn,color,1,0);
		if(ret)
		{
			return true;
		}
		ret = isDirectionWin(curLine,curColumn,color,0,1);
		if(ret)
		{
			return true;
		}
		ret = isDirectionWin(curLine,curColumn,color,1,1);
		if(ret)
		{
			return true;
		}
		ret = isDirectionWin(curLine,curColumn,color,1,-1);
		if(ret)
		{
			return true;
		}
		return false;
	}

	bool isDirectionWin(int line,int column,char color,int x,int y)
	{
		ChessBoard *cb = ChessBoard::getInstance();

		int count = 1;
		for(int i = 1; i < 5; ++i)
		{
			bool ret = cb->isValidColorChess(line + (i * y),column + (i * x),color);
			if(!ret)
			{
				break;
			}
			++count;
		}

		for(int i = 1; i < 5; ++i)
		{
			bool ret = cb->isValidColorChess(line - (i * y),column - (i * x),color);
			if(!ret)
			{
				break;
			}
			++count;
		}

		if(count >= 5)
		{
			return true;
		}
		return false;
	
	}
};

#endif

主函数代码如下:

#include "BlackPlayer.hpp"
#include "WhitePlayer.hpp"
#include "ChessBoard.hpp"
#include "KeyHandle.hpp"
#include "Arbitration.hpp"

int main(int argc, const char *argv[])
{
	cout << "\033[2J";

	ChessBoard::getInstance()->show();
	KeyHandle KeyHandle;
	Arbitration arb;

	Player *player[2];
	player[0] = new BlackPlayer("张三");
	player[1] = new WhitePlayer("李四");

	bool isWin = false;
	while(1)
	{
		for(int i = 0; i < 2; ++i)
		{
			KeyHandle.waitPlayerPlaceChess(player[i]);
			isWin = arb.isWin(player[i]->getColor());
			if(isWin)
			{
				cout << "\033[32;0H" << player[i]->getName() << "获得胜利";
				break;
			}
		}
		if(isWin)
		{
			break;
		}
	}

	delete player[0];
	delete player[1];

	cout << "\033[0m\033[35;0H";
	return 0;
}

宏定义类代码如下:

#ifndef CONFIG_HPP
#define CONFIG_HPP

#define BLACK 0x1
#define WHITE 0x0

#define BLACK_COLOR "\033[31;40m[♚]"
#define WHITE_COLOR "\033[36;47m[♛]"

#define LINE 15
#define COLUMN 15

#define CHESS_BOARD_FILE "ChessBoard.txt"
#define CHESS_BOARD_COLOR "\033[45;37m"

#define LINE_INTERVAL 2
#define COLUMN_INTERVAL 4

#define X_MAX 57
#define Y_MAX 29

#define X_CENTER 29
#define Y_CENTER 15

#endif

运行效果如下:

 

  • 7
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值