相信每个人都玩过手画的三子棋游戏,这篇文章将用初阶C语言的内容来实现没那么聪明的三子棋游戏。
目录
一、三子棋游戏基本逻辑
1.1 进入菜单选择,进入游戏,打印棋盘。
1.2 电脑和玩家不断轮流下棋,每一次下棋,判断输赢,直至出现一方获胜或者平局,游戏结束,再次进入菜单选择,继续或退出游戏。
二、代码实现
由于三子棋游戏需要多个模块共同完成,多个文件可以处理各自模块的功能,整个游戏的脉络也会更加清晰,代码可读性更高。因此创建源文件和头文件,分别为 实现整个游戏程序的test.c,实现游戏内容的game.c和游戏函数声明的game.h。game.h用来进行函数声明,在test.c中调用的函数都需要在game.h中声明,test.c和game.c包含game.h。
三、游戏总代码
1.1进入菜单选择,选择进入游戏,打印棋盘
打印菜单代码
void menu()
{
printf("*********************\n");
printf("***** 1.play *****\n");
printf("***** 0.exit *****\n");
printf("*********************\n");
}
int main()
{
int input = 0;
do
{
menu();//打印菜单的函数
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("进入游戏,\n");//输入1,进入游戏
break;
case 0:
printf("退出游戏!\n");//输入0.退出游戏
break;
default :
printf("选择错误,请重新选择!\n");//输入非1、0,重新选择
break;
}
} while (input);//输入非0,循环继续,输入0,退出游戏,循环结束
}运行结果

继续实现游戏内容,菜单选择1,进入游戏,调用game()函数来实现。
int main()
{
int input = 0;
do
{
menu();//打印菜单的函数
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("进入游戏,\n");//输入1,进入游戏
game();//game()函数是三子棋游戏的核心,它是实现三子棋游戏内容的函数
break;
case 0:
printf("退出游戏!\n");//输入0.退出游戏
break;
default:
printf("选择错误,请重新选择!\n");//输入非1、0,重新选择
break;
}
} while (input);//输入非0,循环继续,输入0,退出游戏,循环结束
}进入游戏后,显示3x3棋盘,但棋盘怎么来实现?
棋盘实际上是一个二维数组,来存放所下的棋子。
因此先创建一个名为board的二维数组,并且初始化,放入空格。
棋盘的行数和列数直接定义在game.h中,方便更改。
在test.c文件中调用game()函数,在game函数中来初始化棋盘。
game.h文件
#pragma once
#include<stdio.h>
#define ROW 3//打印三行的棋盘
#define COL 3//打印三列的棋盘
void initboard(char board[ROW][COL], int row,int col);
test.c文件
在game()函数中调用initboard函数来初始化棋盘
void game()
{
char board[ROW][COL] = { 0 };
initboard(board, ROW, COL);//初始化棋盘
}
game.c文件
写函数来初始化棋盘
void initboard(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
初始化棋盘后,开始打印3x3棋盘网格
3x3棋盘网格是一个“井”字网格,接下来就写函数来打印“井”字网格
game.h
函数声明
void displayboard(char board[ROW][COL], int row, int col);
test.c
在game()函数中调用打印棋盘的函数
void game()
{
char board[ROW][COL] = { 0 };
initboard(board, ROW, COL);//初始化棋盘
displayboard(board, ROW, COL);//打印棋盘
}
game.c
写函数,打印棋盘
void displayboard(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf(" %c ",board[i][j]);//%c是留给下棋的位置
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");
}
}
}运行结果 ,完成棋盘打印

1.2玩家电脑轮流下棋,判断输赢,游戏结束或者游戏继续。
在game.c中写玩家下棋的函数--playermove函数,玩家或者电脑下棋函数执行完,再次调用displayboard函数打印棋盘,打印下棋后的棋盘
game.c void playermove(char board[ROW][COL], int row, int col) { int x = 0; int y = 0; printf("玩家下棋,请输入坐标:"); scanf("%d %d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col)//判断输入的坐标是否越界 { if (board[x - 1][y - 1] == ' ')//判断坐标是否被占用 //玩家不知道数组下标从0开始,因此玩家输入的坐标应当-1,与二维数组下标相对应 { board[x - 1][y - 1] = '*';//玩家下的棋子为'*'; } else { printf("坐标被占用,请重新输入:"); } } else { printf("输入的坐标有误,请重新输入:"); } } test.c void game() { char board[ROW][COL] = { 0 }; initboard(board, ROW, COL);//初始化棋盘 displayboard(board, ROW, COL);//打印棋盘 playermove(board, ROW, COL);//玩家下棋 displayboard(board, ROW, COL);//打印棋盘 }
运行结果

每次下完棋后,都要打印下棋后的棋盘,判断输赢,所以打印棋盘函数,判断输赢的函数放在循环中反复调用,直至出现平局或获胜。
本次游戏,玩家所下的棋子是*,电脑所下的棋子是#
论如何通过代码来判断输赢:赢得情况有三种:一列,一行,对角
写win函数来判断输赢,三种获胜得情况实现任意一种,则win函数就返回获胜的这个棋子元素到test.c中,在test.c的game()中判断,若返回来的元素是*,则为玩家获胜,若是#,则是电脑获胜,若是C,则游戏继续,若是Q,则是平局
下面来实现玩家下棋,判断三种获胜和平局的情况:
game.c
char win(char board[ROW][COL], int row, int col)
{
int i = 0;
//判断行
for (i = 0; i < col; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')//同1行棋子相等并且不是空格
{
return board[i][1];//返回获胜的棋子元素
}
}
//判断列
for (i = 0; i < row; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')//同1列棋子相同并且不是空格
{
return board[1][i];
}
}
//判断对角
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')//对角的元素相同
{
return board[0][0];
}
if (full(board, ROW, COL))//full函数判断平局,寻找二维数组中是否还有空格,有空格则游戏继续,没有空格则平局
{
return 'Q';
}
else
{
return 'C';
}
}
int full(char board[ROW][COL], int row, int col)//判断平局的函数
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
test.c
while(1)
{
playermove(board, ROW, COL);//玩家下棋
ret = win(board, ROW, COL);//判断输赢
if (ret != 'C')//游戏继续,函数返回C,若不是C,则是出现了平局或者获胜的情况,循环结束
{
break;
}
displayboard(board, ROW, COL);//打印棋盘
}
if (ret == 'Q')
{
printf("平局!\n");
}
else if (ret == '#')
{
printf("玩家获胜!\n");
}
else if (ret == '*')
{
printf("电脑获胜!");
}
displayboard(board, ROW, COL);//打印棋盘 接着电脑下棋,判断输赢
电脑下棋,调用rand()函数来产生随机数,调用srand()初始化rand产生随机数种子。
玩家和电脑反复下棋,放在循环中,每一次调用玩家或电脑下棋函数,输入一次坐标
test.c
void game()
{
int ret = 0;
char board[ROW][COL] = { 0 };
initboard(board, ROW, COL);//初始化棋盘
displayboard(board, ROW, COL);//打印棋盘
while (1)
{
playermove(board, ROW, COL);//玩家下棋
ret = win(board, ROW, COL);//判断输赢
if (ret != 'C')
{
break;
}
displayboard(board, ROW, COL);//打印棋盘
computermove(board, ROW, COL);//电脑下棋
ret = win(board, ROW, COL);//判断输赢
if (ret != 'C')
{
break;
}
displayboard(board, ROW, COL);//打印棋盘
}
if (ret == 'Q')
{
printf("平局!\n");
}
else if (ret == '*')
{
printf("玩家获胜!\n");
}
else if (ret == '#')
{
printf("电脑获胜!\n");
}
displayboard(board, ROW, COL);//打印棋盘
}
game.c
void computermove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋:\n");
while (1)
{
//调用rand函数,产生随机数
x = rand() % row;//行数范围为0-row
y = rand() % col;//列数范围为0-col
if (board[x][y] == ' ')//判断坐标是否被占用
{
board[x][y] = '#';//电脑下的棋子为'#';
break;
}
}
}三子棋游戏代码到这里已经全部完成了,看运行效果


三、游戏总代码
test.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
void menu()
{
printf("*********************\n");
printf("***** 1.play *****\n");
printf("***** 0.exit *****\n");
printf("*********************\n");
}
void game()
{
int ret = 0;
char board[ROW][COL] = { 0 };
initboard(board, ROW, COL);//初始化棋盘
displayboard(board, ROW, COL);//打印棋盘
while (1)
{
playermove(board, ROW, COL);//玩家下棋
ret = win(board, ROW, COL);//判断输赢
if (ret != 'C')
{
break;
}
displayboard(board, ROW, COL);//打印棋盘
computermove(board, ROW, COL);//电脑下棋
ret = win(board, ROW, COL);//判断输赢
if (ret != 'C')
{
break;
}
displayboard(board, ROW, COL);//打印棋盘
}
if (ret == 'Q')
{
printf("平局!\n");
}
else if (ret == '*')
{
printf("玩家获胜!\n");
}
else if (ret == '#')
{
printf("电脑获胜!\n");
}
displayboard(board, ROW, COL);//打印棋盘
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();//打印菜单的函数
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("进入游戏,\n");//输入1,进入游戏
game();//game()函数是三子棋游戏的核心,它是实现三子棋游戏内容的函数
break;
case 0:
printf("退出游戏!\n");//输入0.退出游戏
break;
default:
printf("选择错误,请重新选择!\n");//输入非1、0,重新选择
break;
}
} while (input);//输入非0,循环继续,输入0,退出游戏,循环结束
}game.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
void initboard(char board[ROW][COL], int row, int col)
{
int i = 0;
int 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;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf(" %c ",board[i][j]);//%c是留给给待下棋的位置
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");
}
}
}
void playermove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家下棋,请输入坐标:");
while (1)
{
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//判断输入的坐标是否越界
{
if (board[x - 1][y - 1] == ' ')//判断坐标是否被占用
//玩家不知道数组下标从0开始,因此玩家输入的坐标应当-1,与二维数组下标相对应
{
board[x - 1][y - 1] = '*';//玩家下的棋子为'*';
break;
}
else
{
printf("坐标被占用,请重新输入:");
}
}
else
{
printf("输入的坐标有误,请重新输入:");
}
}
}
char win(char board[ROW][COL], int row, int col)
{
int i = 0;
//判断行
for (i = 0; i < col; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')//同1行棋子相等并且不是空格
{
return board[i][1];//返回获胜的棋子元素
}
}
//判断列
for (i = 0; i < row; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')//同1列棋子相同并且不是空格
{
return board[1][i];
}
}
//判断对角
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')//对角的元素相同
{
return board[0][0];
}
if (full(board, ROW, COL))
{
return 'Q';
}
else
{
return 'C';
}
}
void computermove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋:\n");
while (1)
{
//调用rand函数,产生随机数
x = rand() % row;//行数范围为0-row
y = rand() % col;//列数范围为0-col
if (board[x][y] == ' ')//判断坐标是否被占用
{
board[x][y] = '#';//电脑下的棋子为'#';
break;
}
}
}
int full(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}game.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3//打印三行的棋盘
#define COL 3//打印三列的棋盘
//1.初始化棋盘
void initboard(char board[ROW][COL], int row,int col);
//2.打印棋盘
void displayboard(char board[ROW][COL], int row, int col);
//3.玩家下棋
void playermove(char board[ROW][COL], int row, int col);
//4.判断输赢
char win(char board[ROW][COL], int row, int col);
//5.电脑下棋
void computermove(char board[ROW][COL], int row, int col);
//6.判断平局
int full(char board[ROW][COL], int row, int col);三子棋游戏到这里已经全部实现了,我之所以称这个版本的三子棋游戏是不太聪明的三子棋游戏,因为这个版本的电脑下棋没有目的性,不会去刻意阻止玩家获胜,也没有获胜的目的性,这个版本的三子棋完全是由C语言初阶的内容实现的,因此功能没那么强大。
若文章有什么问题或者建议,欢迎各位大佬留言或者点赞。