C语言实现三子棋游戏完整代码与逻辑解析
本文将讲解如何使用C语言从头编写一个简单的三子棋控制台程序。通过将程序拆分为菜单、游戏逻辑和判断函数三个部分,利用头文件进行声明,实现模块化开发。内容包含完整的源代码、关键算法解析以及针对原代码逻辑缺陷的修正建议。
三子棋游戏的模块化解构
为了保持代码的可读性和易维护性,大型C项目通常采用“多文件”结构。本实例将代码划分为三个核心部分:
main.c:负责主流程控制、菜单显示和游戏入口调用。game.h:存放宏定义(如行列数)、全局常量以及所有函数的声明。game.c:存放具体的游戏逻辑实现,包括棋盘创建、显示、玩家落子、电脑随机落子及胜负判断。
这种结构类似于实际工程项目中的接口与实现分离,有助于理清程序执行顺序。
准备条件与环境配置
在编译运行代码前,需确保开发环境支持以下库文件,并在代码头部添加相应的预处理指令:
- 标准输入输出:
#include <stdio.h>,用于打印棋盘和处理键盘输入。 - 时间种子:
#include <time.h>,配合srand(time(NULL))保证电脑每次移动是随机的。 - 系统命令:
#include <windows.h>或<cstdlib.h>,用于清屏操作(system("cls"))和延时。
注意:若使用GCC等Linux编译器,需替换Windows相关的头文件和函数(如将Sleep改为sleep,移除_CRT_SECURE_NO_WARNINGS)。以下内容基于Windows控制台环境编写。
第一步:定义头文件与函数声明
game.h 定义了游戏的通用参数和对外接口。这是其他文件访问游戏状态的唯一通道。
#ifndef __GAME_H__
#define __GAME_H__
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define ROW 3
#define COL 3
// 函数声明
void InitBoard(char board[ROW][COL], int row, int col);
void DisplayBoard(char board[ROW][COL], int row, int col);
void PlayerMove(char board[ROW][COL], int row, int col);
void ComputerMove(char board[ROW][COL], int row, int col);
char IsWin(char board[ROW][COL], int row, int col);
#endif
要点说明:使用了 ifndef/define/endif 保护宏防止重复包含;使用字符型数组 char board[3][3] 存储状态,空位为 ' ',玩家为 '*',电脑为 '#',平局返回 'Q',继续返回 'C'。
第二步:实现棋盘初始化与显示逻辑
在游戏开始前,必须将数组元素清空为空格,并根据行列数动态绘制边框,使界面整洁。
// game.c
void InitBoard(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
// 打印行数据
printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
if (i < row - 1) // 最后一行不打印分割线
{
printf---|---|---\n);
}
}
}
逻辑修正:原代码中的打印逻辑较为繁琐,这里使用更标准的分隔线格式,提升视觉体验。
第三步:编写玩家交互与输入校验
玩家通过输入坐标(1-3)来落子。程序需要处理非法输入,例如输入越界或位置已被占据的情况。
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0, y = 0;
printf("请输入坐标 (>:);\n");
while (1)
{
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break; // 合法且空闲,跳出循环
}
else
{
printf("该位置已有棋子,请重新输入!\n");
}
}
else
{
printf("坐标非法,请输入 1-%d: , 1-%d:\n", row, col);
}
}
}
关键点:数组索引从0开始,因此用户输入的1对应索引0,需进行减1处理;使用 while(1) 替代原代码中的 goto 语句,符合结构化编程规范,避免代码陷入不可控状态。
第四步:电脑智能与胜负判定算法
电脑策略:简易版三子棋通常采用完全随机策略。只要找到空地就落子。
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑思考中...\n");
sleep(1000); // 模拟思考延时
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
胜负判断:需遍历行、列和对角线。如果全部相同且不为空,则获胜;如果棋盘满且无人获胜,则为平局。
char IsWin(char board[ROW][COL], int row, int col)
{
int i = 0;
// 检查行
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
return board[i][0];
}
// 检查列
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
return board[0][i];
}
// 检查对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
return board[0][0];
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
return board[0][2];
// 检查平局 (棋盘是否填满)
int is_full = 1;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
is_full = 0;
break;
}
}
if (!is_full) break;
}
if (is_full)
return 'Q'; // 平局 Draw
return 'C'; // 继续 Continue
}
第五步:整合主流程与退出机制
将上述模块组合,并修复原代码中游戏结束后无法正确返回菜单或退出的问题。
void game()
{
char ret = 'C';
char board[ROW][COL] = {0};
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
while (ret == 'C')
{
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != 'C') break;
ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = IsWin(board, ROW, COL);
}
if (ret == '*')
printf("恭喜你赢了!\n");
else if (ret == '#')
printf("很遗憾,你输了!\n");
else
printf("这是个平局!\n");
}
在 main 函数中,设置好随机数种子后,即可进入循环选择游戏或退出。这比原代码中复杂的 switch-case 嵌套更加清晰直观。
总结
通过本实例,我们掌握了C语言二维数组的操作、模块化程序设计思维以及基础的控制台交互技巧。原代码虽然能运行,但存在逻辑冗余和跳转混乱的问题,经过重构后,代码的健壮性和可读性得到了显著提升。以上就是C语言实现三子棋游戏的具体内容,更多关于C语言小程序开发的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













