使用C语言实现三子棋小游戏:模块化编程与逻辑实战
本文将指导你如何通过模块化思想,在C语言中从零开始构建一个完整的三子棋(Tic-Tac-Toe)小游戏。内容涵盖项目结构设计、核心数据结构的处理、人机交互逻辑、AI随机决策算法以及复杂的胜负判断机制,并提供经过修正和优化的完整代码示例。
结果或目标
最终实现一个可以在终端运行的控制台程序。启动后显示菜单,选择开始后进入双人(人对电脑)对弈模式。棋盘为3x3网格,玩家输入坐标落子(' * '),电脑自动随机落子(' # ')。系统实时判断并宣布赢家或平局,支持重新开始或退出。
准备条件
- 开发环境:支持C99标准及以上的C编译器(如 GCC、Clang 或 MSVC)。
- 基础知识:掌握C语言基本语法、函数调用、指针/数组传参、预处理指令及控制流语句。
- 工具链:文本编辑器或IDE,终端命令行工具。
真实操作顺序
第1步:构建项目模块架构
目的:将游戏的入口、逻辑声明与具体实现分离,提高代码可读性与可维护性。
入口/动作:创建三个源文件:
main.c:包含主函数、菜单显示逻辑和游戏运行循环。three_chess.h:包含常量定义(行列数)及所有函数的原型声明。three_chess.c:包含初始化、棋盘显示、玩家移动、电脑移动及胜负判断的具体函数实现。
第2步:实现头文件与全局常量
目的:定义棋盘尺寸并暴露必要的接口。
代码实现(three_chess.h):
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.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 IsGameOver(char board[ROW][COL], int row, int col);
第3步:实现主流程与菜单
目的:建立游戏的控制流,处理用户的选择分支。
代码实现(main.c):
#include "three_chess.h"
void menu()
{
printf("##########################\n");
printf("### 1. Play Game ###\n");
printf("### 0. Quit Game ###\n");
printf("##########################\n");
}
void game()
{
int input = 0;
srand((unsigned int)time(NULL)); // 初始化随机种子
char board[ROW][COL] = {0};
InitBoard(board, ROW, COL); // 初始化棋盘
while (1)
{
DisplayBoard(board, ROW, COL); // 打印当前棋盘
PlayerMove(board, ROW, COL); // 玩家走一步
char ret = IsGameOver(board, ROW, COL); // 检查是否结束
if (ret != 'C')
{
break; // C代表 Continue(继续),非C则结束
}
ComputerMove(board, ROW, COL); // 电脑走一步
ret = IsGameOver(board, ROW, COL); // 再次检查
if (ret != 'C')
{
break;
}
}
DisplayBoard(board, ROW, COL); // 打印最终状态
if (ret == '*')
printf("玩家赢!\n");
else if (ret == '#')
printf("电脑赢!\n");
else
printf("平局!\n");
}
int main()
{
int input = 0;
do {
menu();
printf("请选择: ");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏。\n");
break;
default:
printf("输入无效,请重新选择。\n");
break;
}
} while (input);
return 0;
}
第4步:实现棋盘初始化与显示
目的:将内存中的字符数组转化为可视化的网格界面,初始化为空格 ' '。
代码实现(three_chess.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, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("| ");
}
printf("\n");
if (i < row - 1)
{
for (j = 0; j < col; j++)
{
printf("--- ");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
第5步:实现玩家移动(含输入校验)
目的:接收用户输入,确保坐标合法且在范围内,防止覆盖已存在的棋子。
关键逻辑:
- 合法性检查:输入的 x 和 y 必须在
[1, ROW]和[1, COL]之间。 - 占用检查:将输入的行列转换为数组索引
[x-1][y-1],若该位置不为空格,则提示重试。
代码实现:
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0, y = 0;
while (1)
{
printf("请输入想要落子的坐标(x y): ");
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 范围内的数字。\n", row);
}
}
}
第6步:实现电脑随机移动
目的:模拟电脑落子,采用简单的随机算法寻找空位。
关键逻辑:
- 使用
rand() % row生成[0, row)范围内的随机行索引。 - 使用
rand() % col生成[0, col)范围内的随机列索引。 - 利用
while循环判断该随机位置是否为空,若非空则重新生成坐标,直到找到空位。
代码实现:
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑正在思考...\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
第7步:实现胜负判断逻辑
目的:检测四种终局状态:玩家赢(*)、电脑赢(#)、平局(D)、继续(C)。
判断规则:
- 行相等:遍历每一行,若三个字符相同且不为空格,返回该字符。
- 列相等:遍历每一列,判断同上。
- 对角线相等:判断主对角线
(0,0)-(1,1)-(2,2)和副对角线(0,2)-(1,1)-(2,0)。 - 平局判定:若上述皆不满足,检查棋盘是否已满。若满且无胜者,返回 'D'。
代码实现:
// 辅助函数:判断棋盘是否填满
static int IsFull(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
for (int j = 0; j < col; j++)
if (board[i][j] == ' ')
return 0; // 有空位,未填满
return 1; // 全满
}
char IsGameOver(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
// 1. 判断行
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];
}
// 2. 判断列
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[0][j] != ' ')
return board[0][j];
}
// 3. 判断对角线
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];
// 4. 判断平局
if (IsFull(board, row, col))
return 'D';
// 5. 继续
return 'C';
}
完成判断
编译全部文件后运行 ./game(或对应平台的可执行文件)。观察控制台输出的棋盘格式是否正确,验证输入非法坐标时的提示信息,以及测试电脑是否能正确避开已占用的格子。当出现三连珠时,确认胜负判定无误。
简要总结
本示例展示了C语言在数据结构处理和逻辑控制方面的基础应用。通过将问题拆解为初始化、交互、计算和输出四个模块,降低了编码复杂度。实际开发中,电脑落子算法可以升级为极小化极大算法(Minimax)以提升AI水平,但当前的随机策略足以演示基本的程序架构。以上就是C语言实现三子棋小游戏的详细内容,更多关于C语言入门游戏开发的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









