三子棋游戏,也被称为井字棋,是一种简单而经典的棋类游戏,通常在3x3的棋盘上进行。两名玩家轮流在棋盘上放置自己的棋子,一方是"X",另一方是"O",目标是先在水平、垂直或对角线上成功连成三个自己的棋子,即获胜。如果棋盘填满而没有玩家连成三子,游戏为平局。
规则:
1. 初始状态,棋盘是一个3x3的方格,所有格子都为空。
2. 两名玩家轮流行动,先手为"X",后手为"O"。
3. 玩家在自己的回合选择一个空格,在该位置放置自己的棋子。
4. 玩家获胜条件:在同一行、列或对角线上连成三个自己的棋子。
5. 如果棋盘填满而没有玩家连成三子,游戏为平局。
玩法:
1. 游戏开始,棋盘显示为空格,玩家 "X" 首先行动。
2. 玩家 "X" 输入要下棋的行和列(例如:行 1 列 2),将棋子放置在选择的位置。
3. 棋盘更新,显示玩家 "X" 的棋子。
4. 玩家 "O" 输入下棋位置,放置自己的棋子。
5. 重复步骤2-4,直到有玩家获胜或者棋盘填满平局。
6. 游戏结束,显示获胜的玩家或平局的结果。
1. 模块一:主函数模块
这是整个程序的入口,包含主要的游戏逻辑和流程控制。在主函数模块中,我们定义了一个3x3的二维字符数组 `board` 用于表示游戏棋盘。另外,我们使用字符变量 `currentPlayer` 来标识当前轮到哪个玩家下棋。主函数通过调用其他模块来完成初始化棋盘、显示棋盘、检查玩家输入的合法性、检查是否有玩家获胜以及检查棋盘是否已满等功能。游戏进行中,不断切换玩家,直到游戏结束。
#include <stdio.h>
#include <stdbool.h>
// 模块一:主函数模块
int main() {
char board[3][3]; // 二维字符数组,表示游戏棋盘
char currentPlayer = 'X'; // 标识当前轮到哪个玩家下棋
int row, col;
bool gameover = false; // 标识游戏是否结束
init_board(board); // 初始化棋盘
while (!gameover) {
display_board(board); // 显示当前棋盘状态
// 获取玩家输入
printf("玩家 %c,请输入要下棋的行和列(格式:行 列):", currentPlayer);
scanf("%d %d", &row, &col);
// 检查输入是否合法
if (!is_valid_move(board, row, col)) {
printf("无效的行和列,请重新输入。\n");
continue;
}
// 下棋
board[row][col] = currentPlayer;
// 检查是否有人获胜
if (check_winner(board, currentPlayer)) {
display_board(board);
printf("玩家 %c 获胜!\n", currentPlayer);
gameover = true;
} else if (is_board_full(board)) {
display_board(board);
printf("平局!\n");
gameover = true;
}
// 切换玩家
currentPlayer = (currentPlayer == 'X') ? 'O' : 'X';
}
return 0;
}
2. 模块二:初始化棋盘模块
在这个模块中,我们定义了一个名为 `init_board` 的函数,用于初始化游戏棋盘。它接受一个二维字符数组 `board` 作为参数,并将每个元素初始化为空格字符,表示棋盘上的每个位置都是空的。
// 模块二:初始化棋盘模块
void init_board(char board[3][3]) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
board[i][j] = ' '; // 将每个格子初始化为空格字符
}
}
}
3. 模块三:显示棋盘模块
这个模块定义了一个名为 `display_board` 的函数,用于在命令行中显示当前的游戏棋盘状态。该函数接受一个二维字符数组 `board` 作为参数,并根据其中的棋盘信息,打印出当前的棋盘状态,以及每个格子里的棋子。
// 模块三:显示棋盘模块
void display_board(char board[3][3]) {
printf("\n");
printf(" %c | %c | %c \n", board[0][0], board[0][1], board[0][2]);
printf("---+---+---\n");
printf(" %c | %c | %c \n", board[1][0], board[1][1], board[1][2]);
printf("---+---+---\n");
printf(" %c | %c | %c \n", board[2][0], board[2][1], board[2][2]);
printf("\n");
}
4. 模块四:检查合法性模块
在这个模块中,我们定义了一个名为 `is_valid_move` 的函数,用于检查玩家输入的行和列是否合法。该函数接受一个二维字符数组 `board` 和两个整数 `row`、`col` 作为参数。它首先检查行和列是否在合法范围内(0~2),然后再检查该位置是否已经被占据(即是否为空格字符),如果通过检查,则返回 `true` 表示输入合法,否则返回 `false` 表示输入无效,需要重新输入。
// 模块四:检查合法性模块
bool is_valid_move(char board[3][3], int row, int col) {
// 检查行和列是否在合法范围内
if (row < 0 || row >= 3 || col < 0 || col >= 3) {
return false;
}
// 检查该位置是否已经被占据
if (board[row][col] != ' ') {
return false;
}
return true; // 合法的行和列输入
}
5. 模块五:检查是否有玩家获胜模块
这个模块定义了一个名为 `check_winner` 的函数,用于检查当前是否有玩家获胜。该函数接受一个二维字符数组 `board` 和一个字符 `player` 作为参数,`player` 表示要检查的玩家('X' 或 'O')。函数会按照游戏规则检查棋盘的行、列以及对角线是否有连续三个相同的棋子,如果有则表示该玩家获胜,返回 `true`,否则返回 `false` 表示没有获胜者。
// 模块五:检查是否有玩家获胜模块
bool check_winner(char board[3][3], char player) {
// 检查行
for (int i = 0; i < 3; i++) {
if (board[i][0] == player && board[i][1] == player && board[i][2] == player) {
return true;
}
}
// 检查列
for (int j = 0; j < 3; j++) {
if (board[0][j] == player && board[1][j] == player && board[2][j] == player) {
return true;
}
}
// 检查对角线
if (board[0][0] == player && board[1][1] == player && board[2][2] == player) {
return true;
}
if (board[0][2] == player && board[1][1] == player && board[2][0] == player) {
return true;
}
return false; // 没有玩家获胜
}
6. 模块六:检查棋盘是否已满模块
在这个模块中,我们定义了一个名为 `is_board_full` 的函数,用于检查游戏棋盘是否已经满了(即所有格子都被占据)。该函数接受一个二维字符数组 `board` 作为参数,遍历整个棋盘,如果发现有任何一个格子为空,则表示棋盘还没满,返回 `false`,否则返回 `true` 表示棋盘已满,游戏为平局。
// 模块六:检查棋盘是否已满模块
bool is_board_full(char board[3][3]) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i][j] == ' ') {
return false; // 棋盘还没满
}
}
}
return true; // 棋盘已满,平局
}
通过这些模块的划分,我们实现了一个简单的三子棋游戏,代码结构清晰,易于理解和维护。每个模块承担特定的功能,使得代码更加模块化、灵活和可扩展。