C语言实现三子棋游戏完整代码与逻辑解析

温以宁
温以宁
发布时间:2026-10-16 | 3人浏览过
原创

本文将讲解如何使用C语言从头编写一个简单的三子棋控制台程序。通过将程序拆分为菜单、游戏逻辑和判断函数三个部分,利用头文件进行声明,实现模块化开发。内容包含完整的源代码、关键算法解析以及针对原代码逻辑缺陷的修正建议。

三子棋游戏的模块化解构

为了保持代码的可读性和易维护性,大型C项目通常采用“多文件”结构。本实例将代码划分为三个核心部分:

  1. main.c:负责主流程控制、菜单显示和游戏入口调用。
  2. game.h:存放宏定义(如行列数)、全局常量以及所有函数的声明。
  3. 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语言小程序开发的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表