C++_五子棋(注释版)

本程序是在vs2015环境下编译运行
vs左上角:文件–新建–项目–Win32控制台应用程序–(注意勾选“附加选项:空项目“)

在这里插入图片描述
在这里插入图片描述

右键头文件”添加–新建项“,类型为 .h 文件,名称分别为”Player.h“以及”ChessBoard.h",即定义“玩家”和“棋盘”两个class
在这里插入图片描述
在这里插入图片描述
然后相同的方式在源文件中右键添加三个.cpp文件
在这里插入图片描述
然后把code copy过去就可以了

另外,代码不是完美的,存在bug,大家可以尝试找一下

相关文档已上传,可自行下载查看

//main.cpp
#include<cstdio>
#include"ChessBoard.h" //包含入需要的各类头文件,除了需要的标准库头文件,还需要我们自定义的两个类头文件,使得两个类对全段程序可见
#include"Player.h"


int main()
{
	ChessBoard board;            //定义了棋盘对象board,思考该对象的构造过程

	Player playA("aaa", '*');    //玩家aaa的棋子形状是'*'

	playA.attachToBoard(&board); // 这里将棋盘对象board的地址赋给了playA玩家对象的成员变量指针m_ptBoard!!

	Player playB("bbb", '#');    //玩家bbb的棋子形状是'#'

	playB.attachToBoard(&board); // 这里将棋盘对象board的地址赋给了playB玩家对象的成员变量指针m_ptBoard!!

	                             // 这里查看玩家对象的棋盘成员对象指针值是否一致,与board对象地址是否一致!

	board.show();

	while (1)
	{
		playA.setChess();        //玩家A放下一个棋子
		if (playA.isWin())       //玩家A落棋后自己当裁判判断是否可以结束战斗
		{
			cout << "Winer!"; break;
		}

		board.show();            //注意该过程board对象,和AB棋盘对象的内容同时变化

		playB.setChess();        //玩家B放下一个棋子
		if (playB.isWin())       //玩家B落棋后自己当裁判判断是否可以结束战斗
		{
			cout << "Winer!"; break;
		}

		board.show();            //注意该过程board对象,和AB棋盘对象的内容同时变化
	}
	//getchar();
	return 1;
}
//ChessBoard.cpp
#include"ChessBoard.h"

ChessBoard::ChessBoard()
{
	for (int i = 1; i<ROW - 1; i++)
	for (int j = 1; j<COL - 1; j++)
		m_cSquare[i][j] = ' ';
	for (int j = 0; j<COL; j++)
		m_cSquare[0][j] = m_cSquare[ROW - 1][j] = '-';
	for (int i = 1; i<ROW; i++)
		m_cSquare[i][0] = m_cSquare[i][COL - 1] = '|';
}

void ChessBoard::show()
{
	system("cls");
	for (int i = 0; i<ROW; i++)
	{
		for (int j = 0; j<COL; j++)
			cout << m_cSquare[i][j] << ' ';   //这里的“ <<' ' ”很重要,这样才能使屏幕上ROW*COL输出为方形
		cout << endl;
	}
}
//ChessBoard.h
#pragma once

#include<iostream>
using namespace std;

#define ROW 15  // 棋盘行和列定义常数
#define COL 15

class ChessBoard//棋盘类
{
public:
	char m_cSquare[ROW][COL];
public:
	ChessBoard(); //构造函数
	void show();  //棋盘画图显示
};
//player.cpp
#include"Player.h"

bool Player::isInChessBoard(int x, int y)
{
	if (x<ROW - 1 && x>0 && y<COL - 1 && y>0)
		return true;
	else
		return false;
}
/*下面是核心代码:如何判断五子是否连成线。
这里采用的是以玩家此刻放下的棋子为中心,从四种方向逐个判断是否在此方向上连成了线
这里将四个方向上的判断都放在一起,避免了四次调用不同方向上的判断,
但在for里面放一个switch有些别扭,可读性上似乎不好*/
bool Player::isLine(int x, int y)
{
	for (int direc = HORIZON; direc <= LEFTTOPTORIGHTBOTTOM; direc++)//四个方向,权宜之计
	{
		int tempX, tempY, cnt = 1;//cnt:连续排列的同种类的棋子的个数,达到五个则该方赢
		for (int i = -4; i <= 4; i++)
		{
			if (i == 0)continue;//此时循环一遍相当于什么都没做
			switch (direc)
			{
			case HORIZON:
				tempX = x;  tempY = y + i;   break;
			case VERTICAL:
				tempX = x + i; tempY = y;    break;
			case LEFTBOTTOMTORIGHTTOP:
				tempX = x - i; tempY = y + i;   break;
			case LEFTTOPTORIGHTBOTTOM:
				tempX = x + i; tempY = y + i;   break;
			}
			if (isInChessBoard(tempX, tempY) && m_ptBoard->m_cSquare[tempX][tempY] == m_chessType) /*判断关键理解下该句子逻辑*/
				cnt++;
			else
				cnt = 0;
			if (cnt == 5)//五子成线
				return true;
		}
	}return false;
}

void Player::setChess()
{
	cout << "请输入玩家" << m_name << "的x坐标和y坐标:" << endl;
	cin >> m_x >> m_y;
	while (cin.fail() || m_ptBoard->m_cSquare[m_x][m_y] != ' ')//输入不是int型变量或者此位置上已有棋子
	{
		cout << "输入有误,请再次输入玩家" << m_name << "的x坐标和y坐标:" << endl;
		cin.clear();  //清除fail状态 
		cin.sync() ;  //清除缓冲区
		cin >> m_x >> m_y;
	}
	if (isInChessBoard(m_x, m_y))
		m_ptBoard->m_cSquare[m_x][m_y] = m_chessType;
}

bool Player::isWin()
{
	return isLine(m_x, m_y) ? true : false;
}
//player.h
#pragma once
//宏定义四种检测五子是否连成线的方向,常量定义,也可以考虑使用const或者枚举类型定义!
#define HORIZON     0
#define VERTICAL      1
#define LEFTBOTTOMTORIGHTTOP  2
#define LEFTTOPTORIGHTBOTTOM  3

#include"ChessBoard.h"
#include<iostream>
using namespace std;
#include<string>

class Player
{
private:                                /*私有变量,受保护,不希望被直接访问,不能访问吗?*/

	string m_name;                      /*对象棋手名字成员变量*/

	char m_chessType;                   /*黑白棋变量定义,本案例中*和#定义不同的持子双方*/

	int m_x;                        
	int m_y;                            /*下子坐标成员变量*/

	ChessBoard* m_ptBoard;              /*定义棋盘对象指针*/

public:
	Player(string name, char chessType) :m_name(name), m_chessType(chessType), m_ptBoard(NULL){} /*构造函数*/

	void attachToBoard(ChessBoard* ptBoard){ m_ptBoard = ptBoard; } /*给成员棋盘对象指针赋值*/

	bool isInChessBoard(int x, int y);  /*判断下棋位置(x,y)是否合理,思考哪些合理,哪些不合理*/

	bool isLine(int x, int y);          /*判断落子是否排成line*/

	bool isWin();                       /*判断输赢*/

	void setChess();                    /*下子*/
};

在这里插入图片描述

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SmallC1oud

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值