开发环境:Linux 操作系统
项目描述:采用 C++语言的抽象、封装、继承、多态的思想对游戏中的棋子、棋盘、裁判等
类进行设计,由于在 Linux 下无图形界面、所以通过坐标绘制棋盘文件,从而实现
在 Linux 下的对战的功能。
运用技术点:
1.运用 C++语言的纯虚函数进行多态的设计。
2.将txt棋盘 文件导入 Linux(15×15)。
3.自动切换对象、并记录棋子在棋盘的坐标位置做防重复处理。
4.通过裁判的类判断棋盘上黑棋与白棋的获胜(依据坐标判断)。
面向对象编程,基类分为:棋类,玩家类,光标类,裁判类
棋类含有的属性为横纵坐标,颜色。
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;
};通过颜色可以衍生出黑棋类和白棋类
//宏定义,采用了VT100控制码
#define BLACK 0x1
#define WHITE 0x0
#define BLACK_COLOR "\033[31;40m[✿]"
#define WHITE_COLOR "\033[36;47m[❀]"
//黑棋类
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()); //光标归位
}
};
//白棋类
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()); //光标归位
}
};由于棋盘类只有一个,于是我就采用单例模式,棋盘大小是由.txt文件传入Linux系统,横纵为15×15,两点之间横坐标之间间隔四个字符,纵坐标间隔俩个字符
#define CHESS_BOARD_FILE "ChessBoard.txt"
#define CHESS_BOARD_COLOR "\033[43;37m"
//中心点
#define X_CENTER 29
#define Y_CENTER 15
#define LINE 15
#define COLUMN 15
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;玩家类含有的属性为名字和下棋的颜色
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;
};
通过颜色和棋盘下棋方式的判断可以衍生出黑棋手和白棋手:
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;
}
};
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;
}
};光标类:将实际坐标装换成棋盘坐标
//相邻两点横纵坐标间隔
#define LINE_INTERVAL 2
#define COLUMN_INTERVAL 4
//横纵坐标最大值
#define X_MAX 57
#define Y_MAX 29
//中间点
#define X_CENTER 29
#define Y_CENTER 15
class Cursor
{
public:
Cursor() : x(X_CENTER), y(Y_CENTER)
{
show();
}
void show() const
{
printf("\033[%d;%dH", y, x);
}
void moveUp()
{
if (y - LINE_INTERVAL <= 0) {
return ;
}
y -= LINE_INTERVAL;
show();
}
void moveDown()
{
if (y + LINE_INTERVAL > Y_MAX) {
return ;
}
y += LINE_INTERVAL;
show();
}
void moveLeft()
{
if (x - COLUMN_INTERVAL <= 0) {
return ;
}
x -= COLUMN_INTERVAL;
show();
}
void moveRight()
{
if (x + COLUMN_INTERVAL > X_MAX) {
return ;
}
x += COLUMN_INTERVAL;
show();
}
void moveCenter()
{
x = X_CENTER;
y = Y_CENTER;
show();
}
int getX() const
{
return x;
}
int getY() const
{
return y;
}
private:
int x;
int y;
};通过wsad四个按键移动光标位置
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;
};
裁判类:判断输赢
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;
}
};主函数:
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"; //关闭属性,移动光标到35行
return 0;
}版权声明:本文为m0_65612104原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。