使用C语言制作简易的三子棋游戏
新晋码农一枚,小编会定期整理一些写的比较好的代码和知识点,作为自己的学习笔记,试着做一下批注和补充,转载或者参考他人文献会标明出处,非商用,如有侵权会删改!欢迎大家斧正和讨论!本章内容较多,可点击文章目录进行跳转!
小编整理和学习了C语言的相关知识,可作为扫盲使用,后续也会更新一些技术类的文章,大家共同交流学习!
您的点赞、关注、收藏就是对小编最大的动力!
一、代码分析
1. 整体架构设计
- 模块化设计:将功能拆分为初始化、打印、胜利检查、平局检查等独立函数
- 状态管理:使用二维数组存储棋盘状态,字符变量记录当前玩家
- 输入验证:采用分层验证机制(格式、范围、占用状态)
2. 核心函数实现逻辑
2.1 初始化棋盘 initializeBoard()
void initializeBoard(char board[][SIZE]) {for (int i = 0; i < SIZE; i++) { // 行遍历for (int j = 0; j < SIZE; j++) { // 列遍历board[i][j] = ' '; // 初始化为空格}}
}
- 使用双重循环初始化3x3棋盘
- 空格字符表示未落子状态
2.2 棋盘打印 printBoard()
void printBoard(char board[][SIZE]) {printf("\n");for (int i = 0; i < SIZE; i++) {// 打印当前行for (int j = 0; j < SIZE; j++) {printf(" %c ", board[i][j]); // 打印当前格子if (j < SIZE - 1) printf("|"); // 列间分隔线}printf("\n");// 行间分隔线if (i < SIZE - 1) {for (int k = 0; k < SIZE * 2 - 1; k++) printf("-"); // 横线数量计算:3格需要5条横线printf("\n");}}printf("\n");
}
- 动态生成带分隔线的棋盘视图
- 计算分隔线数量:每行需要
(格子数*2 -1)
条横线
2.3 胜利检测 checkWin()
bool checkWin(char board[][SIZE], char player) {// 检测行for (int i = 0; i < SIZE; i++) {if (board[i][0] == player && board[i][1] == player && board[i][2] == player) {return true;}}// 检测列for (int j = 0; j < SIZE; 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) ||(board[0][2] == player && board[1][1] == player && board[2][0] == player)) {return true;}return false;
}
- 行检测:遍历每行检查连续三个相同棋子
- 列检测:遍历每列检查连续三个相同棋子
- 对角线检测:检查两条对角线
2.4 平局检测 checkDraw()
bool checkDraw(char board[][SIZE]) {for (int i = 0; i < SIZE; i++) {for (int j = 0; j < SIZE; j++) {if (board[i][j] == ' ') { // 发现空格即未结束return false;}}}return true; // 所有格子被占满
}
- 遍历整个棋盘检测是否存在空格
3. 主游戏循环逻辑
while (!gameOver) {printBoard(board); // 显示当前棋盘// 获取玩家输入printf("玩家 %c 的回合,请输入行和列(空格分隔): ", currentPlayer);if (scanf("%d %d", &row, &col) != 2) {// 输入验证失败处理while (getchar() != '\n'); // 清空输入缓冲区continue;}// 坐标范围验证if (row < 0 || row >= SIZE || col < 0 || col >= SIZE) {printf("坐标超出范围!\n");continue;}// 位置占用验证if (board[row][col] != ' ') {printf("该位置已被占用!\n");continue;}// 落子操作board[row][col] = currentPlayer;// 状态检查if (checkWin(board, currentPlayer)) {// 胜利处理gameOver = true;} else if (checkDraw(board)) {// 平局处理gameOver = true;} else {// 切换玩家currentPlayer = (currentPlayer == 'X') ? 'O' : 'X';}
}
4. 关键设计决策
4.1 输入验证机制
- 格式验证:使用
scanf
返回值检测输入是否为两个整数 - 范围验证:检查坐标是否在[0,2]范围内
- 占用验证:检查目标位置是否为空格
- 缓冲区处理:使用
while (getchar() != '\n')
清空错误输入
4.2 游戏状态管理
- 使用
bool gameOver
标志控制游戏循环 - 通过棋盘状态直接判断游戏结果
- 玩家切换采用三元运算符简化代码
4.3 棋盘表示选择
- 使用
char
数组而非int
数组:- 更直观的字符表示('X'/'O')
- 简化打印逻辑
- 方便状态检查
5. 扩展性设计
5.1 模块化结构
- 每个功能独立封装,便于修改:
- 修改棋盘尺寸只需调整
#define SIZE
- 修改胜利条件只需调整
checkWin
逻辑
- 修改棋盘尺寸只需调整
5.2 状态检测分离
- 胜利检测与平局检测解耦
- 便于添加新的检测条件(如五子棋扩展)
5.3 输入处理扩展点
- 预留输入验证接口
- 方便扩展为GUI界面或网络对战
这种设计实现了高内聚低耦合的代码结构,既保证了基础功能的完整性,又为后续扩展提供了清晰的接口边界。
二、代码运行
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS 1
#endif
#include <stdio.h>
#include <stdbool.h>#define SIZE 3// 初始化棋盘
void initializeBoard(char board[][SIZE]) {for (int i = 0; i < SIZE; i++) {for (int j = 0; j < SIZE; j++) {board[i][j] = ' '; // 确保使用空格字符而非空字符}}
}
// 打印棋盘
void printBoard(char board[][SIZE]) {printf("\n");for (int i = 0; i < SIZE; i++) {for (int j = 0; j < SIZE; j++) {printf(" %c ", board[i][j]);if (j < SIZE - 1) printf("|");}printf("\n");if (i < SIZE - 1) {for (int k = 0; k < SIZE * 2 - 1; k++) printf("--");printf("\n");}}printf("\n");
}// 检查胜利条件
bool checkWin(char board[][SIZE], char player) {// 明确使用单字符检查for (int i = 0; i < SIZE; i++) {if (board[i][0] == player &&board[i][1] == player &&board[i][2] == player) return true;}for (int j = 0; j < SIZE; j++) {if (board[0][j] == player &&board[1][j] == player &&board[2][j] == player) return true;}return (board[0][0] == player && board[1][1] == player && board[2][2] == player) ||(board[0][2] == player && board[1][1] == player && board[2][0] == player);
}// 检查平局
bool checkDraw(char board[][SIZE]) {for (int i = 0; i < SIZE; i++) {for (int j = 0; j < SIZE; j++) {if (board[i][j] == ' ') return false; // 明确检查空格字符}}return true;
}int main() {char board[SIZE][SIZE];char currentPlayer = 'X'; // 明确初始化为字符'X'int row, col;bool gameOver = false;initializeBoard(board);printf("欢迎来到三子棋游戏!\n");printf("玩家X和O轮流输入坐标(行和列,0-2)来放置棋子\n");printf("例如:输入 1 1 表示中间位置\n");while (!gameOver) {printBoard(board);printf("玩家 %c 的回合,请输入行和列(空格分隔): ", currentPlayer);if (scanf("%d %d", &row, &col) != 2) {printf("输入无效,请输入两个数字!\n");while (getchar() != '\n'); // 清空缓冲区continue;}if (row < 0 || row >= SIZE || col < 0 || col >= SIZE) {printf("坐标范围错误!请输入0-%d之间的值\n", SIZE - 1);continue;}if (board[row][col] != ' ') {printf("该位置已被占用!请重新选择\n");continue;}board[row][col] = currentPlayer;if (checkWin(board, currentPlayer)) {printBoard(board);printf("恭喜玩家 %c 获胜!\n", currentPlayer);gameOver = true;}else if (checkDraw(board)) {printBoard(board);printf("游戏结束,平局!\n");gameOver = true;}else {currentPlayer = (currentPlayer == 'X') ? 'O' : 'X'; // 切换玩家}}return 0;
}