目录
C 语言实现的井字棋游戏代码
一.引言
在编程学习的道路上,通过实践项目来巩固知识是一种极为有效的方式。井字棋游戏,作为一个经典且简单的项目,蕴含了诸多编程概念和技巧。本文将用 C 语言编写的井字棋游戏代码。
二.代码功能概述
这段 C 语言代码实现了一个简单的井字棋游戏,玩家可以与电脑进行对战。玩家通过菜单选择开始游戏或退出游戏,在游戏过程中,玩家和电脑轮流下棋,程序会实时判断输赢情况,直至游戏结束。
三.主函数代码(sanziqi.c)
1. 头文件包含
#include "game.h"
这行代码包含了自定义的头文件 game.h
,该头文件中定义了游戏所需的常量、函数声明等内容。
2. game
函数
void game() {
char ret;
//创建棋盘
char board[ROW][COL];
//初始化
noboard(board, ROW, COL);
//打印棋盘
inboard(board, ROW, COL);
while (1) {
//玩家下棋
player(board, ROW, COL);
inboard(board, ROW, COL);
//判断输赢
ret = win(board, ROW, COL);
if (ret != 'c') {
break;
}
//电脑下棋
computermove(board, ROW, COL);
inboard(board, ROW, COL);
ret = win(board, ROW, COL);
if (ret != 'c') {
break;
}
}
if (ret == '*') {
printf("玩家赢\n");
}
else if (ret == '#') {
printf("电脑赢\n");
}
else if (ret == 'q') {
printf("平局\n");
}
inboard(board, ROW, COL);
}
- 棋盘创建与初始化:创建了一个二维字符数组
board
作为棋盘,调用noboard
函数对棋盘进行初始化。 - 游戏循环:使用
while (1)
创建一个无限循环,在循环中玩家和电脑轮流下棋。每次下棋后,调用inboard
函数打印当前棋盘状态,并调用win
函数判断输赢情况。如果win
函数返回值不是'c'
(表示游戏继续),则跳出循环。 - 结果判断:根据
win
函数的返回值判断游戏结果,分别输出玩家赢、电脑赢或平局的信息,并再次打印最终的棋盘状态。
3. menu
函数
void menu() {
printf("******************************\n");
printf("**********1.play**************\n");
printf("**********0.exit**************\n");
printf("******************************\n");
}
该函数用于打印游戏菜单,向用户展示可选择的操作:开始游戏(输入 1)或退出游戏(输入 0)。
4. main
函数
int main() {
int input = 0;
srand((unsigned int)time(NULL));
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;
}
2. 符号定义
#define ROW 3
#define COL 3
这里使用 #define
预处理指令定义了两个符号常量 ROW
和 COL
,它们的值均为 3。在井字棋游戏里,这两个常量分别代表棋盘的行数和列数。采用符号常量的好处在于,若后续需要对棋盘大小进行调整,只需修改这两个定义,而无需在代码的各个地方逐个修改具体的数值,提高了代码的可维护性和可扩展性。
3. 函数声明
//初始化
void noboard(char board[ROW][COL], int row, int col);
//打印棋盘
void inboard(char board[ROW][COL],int row,int col);
//玩家走
void player(char board[ROW][COL],int row, int col);
//电脑走
void computermove(char board[ROW][COL], int row, int col);
//判断输赢
char win(char board[ROW][COL], int row, int col);
- 随机数种子设置:使用
srand((unsigned int)time(NULL))
设置随机数种子,电脑下棋的逻辑中会用到随机数。 - 菜单循环:使用
do-while
循环不断显示菜单,根据用户输入的数字进行相应操作。输入 1 则调用game
函数开始游戏,输入 0 则退出游戏,输入其他数字则提示输入错误并要求重新选择。四.头文件代码声明函数(game.h)
1.代码功能概述
这段代码是井字棋游戏的头文件内容,其主要功能为包含必要的标准库头文件、定义游戏所需的符号常量,以及声明游戏实现过程中会用到的各类函数。
2.代码详细分析
1. 头文件包含
#include <stdio.h> #include <time.h> #include <stdlib.h>
#include <stdio.h>
:此头文件包含了标准输入输出库的相关内容,为程序提供了诸如printf
和scanf
等基础的输入输出函数,在游戏中可用于显示信息和获取用户输入。#include <time.h>
:该头文件包含了与时间相关的函数和类型定义,在游戏里会被用于生成随机数时作为种子,以确保电脑的落子具有随机性。#include <stdlib.h>
:此头文件涵盖了标准库的多种功能,例如内存分配、随机数生成等。在井字棋游戏中,主要用于生成随机数,为电脑的决策提供支持。void noboard(char board[ROW][COL], int row, int col);
:该函数用于对棋盘进行初始化操作。它接收一个二维字符数组board
作为棋盘,以及row
和col
表示棋盘的行数和列数。函数的返回值类型为void
,意味着它不返回任何值。void inboard(char board[ROW][COL], int row, int col);
:此函数的作用是将当前棋盘的状态打印输出,方便玩家查看。同样接收棋盘数组和行数、列数作为参数,返回值类型为void
。void player(char board[ROW][COL], int row, int col);
:该函数处理玩家的落子操作。在游戏过程中,它会提示玩家输入落子的位置,并将玩家的选择反映在棋盘上。void computermove(char board[ROW][COL], int row, int col);
:该函数负责电脑的落子决策。借助随机数或特定算法,电脑会在合适的位置落子。char win(char board[ROW][COL], int row, int col);
:该函数用于判断当前游戏的输赢状态。它会检查棋盘上是否有玩家或电脑达成获胜条件,或者是否出现平局的情况。函数返回一个字符,用于表示不同的游戏结果,如玩家赢、电脑赢、平局或游戏继续等。
五.核心模块实现具体游戏内容(game.c)
1.代码整体架构与功能概述
这段代码围绕井字棋游戏的核心功能展开,涵盖了棋盘初始化、棋盘显示、玩家与电脑的下棋操作、棋局输赢判断以及棋盘是否已满的检测等关键部分。通过多个自定义函数的协同工作,构建了一个完整的井字棋游戏交互逻辑。
2.代码详细解析
棋盘初始化函数 noboard
void noboard(char board[ROW][COL], int row, int col) {
int i, j;
for (i = 0; i < row; i++) {
for (j = 0; j < col; j++)
board[i][j] = ' ';
}
}
该函数的作用是将棋盘数组中的每个元素初始化为空格字符 ' '
。通过两层嵌套的 for
循环遍历二维数组 board
,将每一个位置的字符都设置为空格,为游戏的开始做好准备。这样的初始化操作确保了棋盘在初始状态下没有任何棋子,干净整洁,等待玩家和电脑的操作。
棋盘显示函数 inboard
void inboard(char board[ROW][COL], int row, int col) {
int i = 0;
for (i = 0; i < row; i++) {
int j = 0;
for (j = 0; j < col; j++) {
printf(" %c ", board[i][j]);
if (j < col - 1) {
printf("|");
}
}
printf("\n");
if (i < row - 1) {
int j = 0;
for (j = 0; j < col; j++) {
printf("---");
if (j < col - 1) {
printf("|");
}
}
printf("\n");
}
}
}
这个函数负责将当前棋盘的状态以可视化的形式输出到控制台。同样使用两层嵌套的 for
循环,外层循环控制行数,内层循环控制列数。在每一行中,依次输出每个格子中的字符,并在相邻格子之间添加分隔符 |
。每一行输出完毕后换行,并且在除了最后一行的每一行下方,输出由 ---
和 |
组成的分隔线,以增强棋盘的视觉效果。这样的显示方式能够清晰地呈现棋盘的布局和棋子的分布,方便玩家了解游戏进展。
玩家下棋函数 player
void player(char board[ROW][COL], int row, int col) {
int x, y;
printf("玩家走:>\n");
while (1) {
printf("请输入坐标:>");
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("坐标不合法请重新输入\n");
}
}
}
该函数处理玩家的下棋操作。首先提示玩家输入下棋的坐标,然后进入一个无限循环,直到玩家输入合法且未被占用的坐标为止。在循环内部,对玩家输入的坐标进行合法性检查,确保其在棋盘的有效范围内。接着检查该坐标对应的棋盘位置是否为空,如果为空,则将该位置设置为玩家的棋子 '*'
,并跳出循环。如果坐标不合法或已被占用,则提示玩家重新输入,保证了游戏操作的准确性和规范性。
电脑下棋函数 computermove
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;
}
}
}
此函数实现了电脑的下棋逻辑。电脑通过调用 rand
函数生成随机数来确定下棋的坐标。在一个无限循环中,不断生成随机的行和列坐标,然后检查该坐标对应的棋盘位置是否为空。如果为空,则将该位置设置为电脑的棋子 '#'
,并跳出循环。这种随机下棋的方式虽然简单,但能在一定程度上模拟电脑的决策过程,为玩家提供对手。
棋盘是否已满检测函数 FULL
int FULL(char board[ROW][COL], int row, int col) {
int i, j;
for (i = 0; i < row; i++) {
for (j = 0; j < col; j++) {
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
这个函数用于检测棋盘是否已满。通过两层嵌套的 for
循环遍历整个棋盘数组,检查每一个位置是否为空字符 ' '
。如果发现有任何一个位置为空,则立即返回 0
,表示棋盘未满;如果遍历完整个棋盘都没有发现空位置,则返回 1
,表示棋盘已满,此时棋局可能以平局结束。
棋局输赢判断函数 win
char win(char board[ROW][COL], int row, int col) {
int i, j;
//三行
for (i = 0; i < row; i++) {
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ') {
return board[i][1];
}
}
//三列
for (j = 0; j < col; j++) {
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ') {
return board[1][j];
}
}
//对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ') {
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ') {
return board[1][1];
}
//检测是否填满
//满了返回一不满返回0
int ret = FULL(board, row, col);
if (ret == 1) {
return 'q';
}
return 'c';
}
该函数是整个游戏逻辑的核心之一,用于判断棋局的输赢状态。首先通过三层检查来判断是否有玩家或电脑获胜:
检查行:遍历每一行,检查该行的三个棋子是否相同且不为空,如果满足条件,则返回该行的棋子字符,表示对应的玩家或电脑获胜。
检查列:类似地,遍历每一列,检查该列的三个棋子是否相同且不为空,若满足则返回该列的棋子字符。
检查对角线:分别检查两条对角线的棋子是否相同且不为空,若满足则返回对角线上的棋子字符。
如果没有检测到获胜情况,则调用 FULL
函数检查棋盘是否已满。如果棋盘已满,则返回 'q'
表示平局;否则返回 'c'
表示游戏继续进行。
3.电脑下棋策略优化
当前电脑的下棋策略仅仅是随机选择一个空位置落子,这种策略过于简单,缺乏智能性。可以实现更复杂的电脑下棋策略,例如优先选择能够获胜的位置、阻止玩家获胜的位置,或者采用更高级的博弈算法,如极小极大算法,来提升电脑的下棋水平,增加游戏的挑战性。
六.总结
通过对这段 C 语言井字棋游戏代码的分析,我们了解了游戏的基本实现思路和结构。这个项目不仅让我们熟悉了 C 语言的基本语法和控制结构,还涉及到了数组、函数调用、循环和条件判断等重要编程概念。希望本文能帮助你更好地理解和掌握 C 语言编程以及游戏开发的基本方法。
感谢大家观看