TicTacToe(井字棋 包含 3*3 和 4*4)游戏开发案例 【C++】
-
类
TicTacToe
的成员函数:displayBoard()
: 显示当前棋盘的状态。makeMove()
: 根据玩家输入的位置来更新棋盘。checkWin()
: 检查当前棋盘上是否有获胜的情况。isBoardFull()
: 检查棋盘是否已满,判断是否为平局。changePlayer()
: 切换当前玩家,从 'X' 到 'O' 或反之。playGame()
: 这是主循环,控制游戏的流程。
-
main()
函数:- 创建
TicTacToe
对象并调用playGame()
函数来开始游戏。
- 创建
#include <iostream>
#include <vector>
using namespace std;
class TicTacToe {
private:
vector<vector<char>> board; // 用来表示棋盘的二维数组
char currentPlayer; // 当前玩家('X' 或 'O')
public:
// 构造函数:初始化棋盘和第一个玩家
TicTacToe() {
board = {{'1', '2', '3'}, // 初始化棋盘,位置用数字表示
{'4', '5', '6'},
{'7', '8', '9'}};
currentPlayer = 'X'; // 初始玩家为 X
}
// 显示棋盘的函数
void displayBoard() {
cout << "玩家 X 和 玩家 O\n\n";
// 打印棋盘的每一行
cout << " " << board[0][0] << " | " << board[0][1] << " | " << board[0][2] << " \n";
cout << "---+---+---\n";
cout << " " << board[1][0] << " | " << board[1][1] << " | " << board[1][2] << " \n";
cout << "---+---+---\n";
cout << " " << board[2][0] << " | " << board[2][1] << " | " << board[2][2] << " \n";
}
// 玩家进行移动,传入位置并判断是否合法
bool makeMove(int position) {
int row = (position - 1) / 3; // 计算行号
int col = (position - 1) % 3; // 计算列号
// 如果该位置没有被占用,则放置当前玩家的标记
if (board[row][col] != 'X' && board[row][col] != 'O') {
board[row][col] = currentPlayer;
return true; // 移动成功
}
return false; // 如果该位置已经被占用,返回失败
}
// 检查是否有玩家获胜
bool checkWin() {
// 检查每一行和每一列是否相同
for (int i = 0; i < 3; i++) {
if ((board[i][0] == board[i][1] && board[i][1] == board[i][2]) ||
(board[0][i] == board[1][i] && board[1][i] == board[2][i])) {
return true; // 如果某行或某列相同,表示获胜
}
}
// 检查两个对角线
if ((board[0][0] == board[1][1] && board[1][1] == board[2][2]) ||
(board[0][2] == board[1][1] && board[1][1] == board[2][0])) {
return true; // 如果对角线相同,表示获胜
}
return false; // 如果没有获胜,返回false
}
// 检查棋盘是否已满(平局)
bool isBoardFull() {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i][j] != 'X' && board[i][j] != 'O') {
return false; // 如果有空格,则棋盘没有满
}
}
}
return true; // 如果棋盘已满,返回true
}
// 切换玩家
void changePlayer() {
currentPlayer = (currentPlayer == 'X') ? 'O' : 'X'; // 切换玩家:如果是X就变成O,反之亦然
}
// 运行游戏的主要逻辑
void playGame() {
int position; // 玩家输入的位置
bool validMove; // 判断移动是否合法
while (true) {
displayBoard(); // 显示当前棋盘
cout << "玩家 " << currentPlayer << " 的回合。请输入位置(1-9):";
cin >> position;
validMove = makeMove(position); // 让玩家进行移动并检查是否合法
if (!validMove) {
cout << "无效的移动,请重试。\n"; // 如果移动无效,提示并继续
continue;
}
if (checkWin()) { // 检查是否有玩家获胜
displayBoard();
cout << "玩家 " << currentPlayer << " 获胜!\n";
break; // 游戏结束
}
if (isBoardFull()) { // 检查棋盘是否已满(平局)
displayBoard();
cout << "游戏平局!\n";
break; // 游戏结束
}
changePlayer(); // 切换玩家
}
}
};
int main() {
TicTacToe game; // 创建一个TicTacToe对象,开始游戏
game.playGame(); // 调用playGame函数开始游戏
return 0;
}
-
棋盘扩展:
- 采用了 4x4 的棋盘,棋盘初始化时标记为
'1'
到'G'
,分别对应棋盘的 16 个位置。
- 采用了 4x4 的棋盘,棋盘初始化时标记为
-
胜利条件:
checkWin
函数被修改为检查是否有三子连珠。我们依旧检查每一行、每一列以及两条对角线中的任意三个连续的相同棋子。如果存在连续的三个相同棋子,则表示该玩家获胜。- 这里的
for
循环被调整为检查每行、每列中的连续三个位置是否相同。
-
输入检查:
- 我们依然支持大小写输入(例如
A
和a
都是有效输入),并且其他无效输入会提示重新输入。
- 我们依然支持大小写输入(例如
#include <iostream>
#include <vector>
#include <cctype> // 用于字符转换
using namespace std;
class TicTacToe {
private:
vector<vector<char>> board; // 用来表示棋盘的二维数组
char currentPlayer; // 当前玩家('X' 或 'O')
public:
// 构造函数:初始化 4x4 棋盘和第一个玩家
TicTacToe() {
board = { {'1', '2', '3', '4'},
{'5', '6', '7', '8'},
{'9', 'A', 'B', 'C'},
{'D', 'E', 'F', 'G'} };
currentPlayer = 'X'; // 初始玩家为 X
}
// 显示棋盘的函数
void displayBoard() {
cout << "玩家 X 和 玩家 O\n\n";
// 打印棋盘的每一行
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
cout << " " << board[i][j] << " ";
if (j < 3) cout << "|";
}
cout << "\n";
if (i < 3) cout << "---+---+---+---\n";
}
}
// 将用户输入的位置(1-16 或 A-G 或 a-g)转换为对应的棋盘位置
int convertPosition(char pos) {
pos = toupper(pos); // 将输入字符转换为大写字母,支持大小写
if (isdigit(pos)) {
return pos - '1'; // 如果是数字,转换为 0 到 15
}
else if (pos >= 'A' && pos <= 'G') {
return pos - 'A' + 9; // 如果是字母,转换为 9 到 15
}
return -1; // 返回无效的位置
}
// 玩家进行移动,传入位置并判断是否合法
bool makeMove(char position) {
int index = convertPosition(position); // 转换输入的字符为索引
if (index == -1) return false; // 如果输入无效,返回失败
int row = index / 4; // 计算行号
int col = index % 4; // 计算列号
// 如果该位置没有被占用,则放置当前玩家的标记
if (board[row][col] != 'X' && board[row][col] != 'O') {
board[row][col] = currentPlayer;
return true; // 移动成功
}
return false; // 如果该位置已经被占用,返回失败
}
// 检查是否有玩家获胜,依然是3子连珠的规则
bool checkWin() {
// 检查每一行和每一列是否相同(3子连珠)
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 2; j++) { // 检查行
if (board[i][j] == board[i][j + 1] && board[i][j + 1] == board[i][j + 2] && (board[i][j] == 'X' || board[i][j] == 'O')) {
return true;
}
}
for (int j = 0; j < 2; j++) { // 检查列
if (board[j][i] == board[j + 1][i] && board[j + 1][i] == board[j + 2][i] && (board[j][i] == 'X' || board[j][i] == 'O')) {
return true;
}
}
}
// 检查对角线
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
if (board[i][j] == board[i + 1][j + 1] && board[i + 1][j + 1] == board[i + 2][j + 2] && (board[i][j] == 'X' || board[i][j] == 'O')) {
return true;
}
if (board[i][3 - j] == board[i + 1][2 - j] && board[i + 1][2 - j] == board[i + 2][1 - j] && (board[i][3 - j] == 'X' || board[i][3 - j] == 'O')) {
return true;
}
}
}
return false; // 如果没有获胜,返回false
}
// 检查棋盘是否已满(平局)
bool isBoardFull() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (board[i][j] != 'X' && board[i][j] != 'O') {
return false; // 如果有空格,则棋盘没有满
}
}
}
return true; // 如果棋盘已满,返回true
}
// 切换玩家
void changePlayer() {
currentPlayer = (currentPlayer == 'X') ? 'O' : 'X'; // 切换玩家:如果是X就变成O,反之亦然
}
// 运行游戏的主要逻辑
void playGame() {
char position; // 玩家输入的位置
bool validMove; // 判断移动是否合法
while (true) {
displayBoard(); // 显示当前棋盘
cout << "玩家 " << currentPlayer << " 的回合。请输入位置(1-9 或 A-G):";
cin >> position;
validMove = makeMove(position); // 让玩家进行移动并检查是否合法
if (!validMove) {
cout << "无效的移动,请重试。\n"; // 如果移动无效,提示并继续
continue;
}
if (checkWin()) { // 检查是否有玩家获胜
displayBoard();
cout << "玩家 " << currentPlayer << " 获胜!\n";
break; // 游戏结束
}
if (isBoardFull()) { // 检查棋盘是否已满(平局)
displayBoard();
cout << "游戏平局!\n";
break; // 游戏结束
}
changePlayer(); // 切换玩家
}
}
};
int main() {
TicTacToe game; // 创建一个TicTacToe对象,开始游戏
game.playGame(); // 调用playGame函数开始游戏
return 0;
}