今天给大家分享一个关于C语言的一个小游戏,首先得有一定的代码基础,分享的这个小游戏,最主要不是用来玩,主要是用来锻炼我们组织大型代码的能力,话不多说,正文开始:
在写代码之前我们先来了解一下这个小游戏,说三子棋很多老铁可能有点陌生,但是说井字棋就豁然开朗,我们首先来看代码实现的总体效果是什么样的:
字体有点小,可以慢慢看,理清逻辑关系。
我们为了逻辑关系清晰,所以创建多个文件:
创建一个头文件:game.h 用来包含我们的头文件和函数的声明以及其他的定义
创建一个源文件:game.c 用来实现关于游戏的函数
再创建一个源文件:test.c 用来测试游戏的基本逻辑
当我们创建好这些文件之后,我们在test.c里面实现游戏的基本逻辑:
首先,我们先要打印一个菜单,然后供玩家选择,如果玩家玩完一次还想玩还可以继续,不想玩直接退出就行,所以我们需要一个do while的循环,我们把头文件全部包含到game.h里面,然后在包含game.h就行了
头文件:game.h:
//game.h的头文件
#pragma once
//包含头文件:
#include
源文件:test.c:
#include "game.h" //包含game.h的头文件
void menu() //打印菜单的函数,不需要返回,所以返回类型是void
{
printf("********************\n");
printf("**** 1. play *****\n");
printf("**** 0. exit *****\n");
printf("********************\n");
}
int main()
{
int input = 0;
do //do while循环来实现多次操作
{
menu();
printf("请选择:>");
scanf("%d", &input);
} while (input); //这里的进入循环的条件是input为真(非0),如果为假(0),则不会进入循环
return 0;
}
打印完菜单之后,就要完善这个菜单带来的效果了,选择play,则进入三子棋游戏,如果选择exit,则退出游戏吧!所以我们就需要用到switch case语句来进行选择
完善过后的do while循环:
int main()
{
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input) //将输入进来的值进行判断
{
case 1: //如果为1,则玩游戏
printf("三子棋游戏:\n");
break;
case 0: //如果为0,则退出游戏
printf("退出游戏\n");
break;
default: //既不是1也不是0,选择错误,重新选择吧
printf("选择错误,请重新选择\n");
break;
}
} while (input);
return 0;
}
我们选1要进行三子棋游戏,所以我们要分装一个game函数,来实现三子棋游戏
在创建一个game函数之后,首先我们得创建一个二维数组,再初始化棋盘,将其初始化为空格
所以我们要在switch case语句中的case 1:中加入game函数
源文件:test.c :
switch (input)
{
case 1:
printf("三子棋游戏:\n");
game(); //游戏逻辑的函数
break;
void game()
{
char board[3][3] = { 0 }; //创建一个二维数组3*3
//初始化棋盘:
InitBoard(board, 3, 3); //将数组,行,列都传给这个函数实现初始化棋盘
}
在这里有一个创建二维数组的好方法:
我们可以在头文件里面用#define来定义ROW为行,定义COL为列,然后赋值,因为如果我们要改变这个棋盘的大小,我们需要把我们整个程序里面的所有关于行和列的值全部修改,所以太麻烦,因此我们只需要在头文件中定义行和列,在后期需要改变的时候直接在头文件里面进行修改,非常方便,所以我们需要改动一下我们写出的代码:
头文件:game.h:
//行和列的定义
#define ROW 3
#define COL 3
源文件:test.c:
void game()
{
char board[ROW][COL] = { 0 };
//初始化棋盘:
InitBoard(board, ROW, COL); //将数组,行,列都传给这个函数实现初始化棋盘
}
修改好之后就来进入我们的初始化棋盘这个函数:
我们初始化棋盘来设定一个函数:InitBoard
源文件:test.c:
void game()
{
char board[ROW][COL] = { 0 };
//初始化棋盘:
InitBoard(board, ROW, COL); //将数组,行,列都传给这个函数实现初始化棋盘
}
然后先要在头文件里面声明
头文件:game.h:
//函数的声明:
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col); //不需要返回什么所以返回类型是void
在声明函数之后,我们在game.c里面来实现这个初始化棋盘这个函数:
初始化棋盘就是说将这个二维数组里面的元素先初始化为空格,有两种方法,我们一一来介绍:
第一种:遍历这个数组中的每一个元素,将其修改为空格
源文件: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] = ' ';
}
}
}
第二种:使用memset函数来初始化
void InitBoard(char board[ROW][COL], int row, int col)
{
memset(&board[row][col], ' ', row * col * sizeof(board[0][0]));
}
//使用memset时需要包含头文件#include
两种方法都可以用。
在初始化棋盘过后,我们把初始化的棋盘打印出来,再分装一个打印棋盘的函数
设定一个打印棋盘的函数:PrintfBoard
源文件:test.c:
void game()
{
char board[ROW][COL] = { 0 };
//初始化棋盘:
InitBoard(board, ROW, COL); //将数组,行,列都传给这个函数实现初始化棋盘
//打印棋盘
PrintfBoard(board, ROW, COL);
}
设定好了之后先在头文件里面声明
头文件game.h:
//函数的声明:
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘:
void PrintfBoard(char board[ROW][COL], int row, int col);
在game.c里面来实现这个打印棋盘的函数:
首先我们得知道我们要打印什么:
虽然我们初始化了棋盘,但是我们得给棋盘来分割一下,看起来比较明显,也利于玩家下棋
那这种分割线怎么来打印呢?
我们一步一步来进行分析:首先得设置总的打印行数,我们将一个“ %c | %c | %c |”(%c的前后都有空格)看作一组,将一个“---|---|---|”也看作一组,所以我们需要打印三行嘛,先写出这个代码:
void PrintfBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
printf(" %c | %c | %c |", board[i][0], board[i][1], board[i][2]);
printf("\n");
printf("---|---|---|", board[i][0], board[i][1], board[i][2]);
printf("\n");
}
}
如果这样写,就多打印了一行“---|---|---|”和“ %c | %c | %c |”,所以我们打印的时候就设置if语句来少打印一行
void PrintfBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
printf(" %c | %c | %c |", board[i][0], board[i][1], board[i][2]);
printf("\n");
if (i < row - 1)
{
printf("---|---|---|", board[i][0], board[i][1], board[i][2]);
printf("\n");
}
}
}
可以看到,在我们修改完之后,后面还是多了一列的“|”,再加上这种写法本身是存在缺陷,这里的列是固定的,无法灵活的修改,所以我们采用新的方法
我们可以将“ %c |”这样的一个看成一组,但是在打印最后一组时,只打印“ %c ”,不打印“|”,同时,我们也要将“---|”这样的看成一组,只需要打印两行即可。
//打印棋盘:
void PrintfBoard(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++) //设置打印“ %c |”的行数
{
printf(" %c ", board[i][j]);
if (j < col - 1) //因为最后一列不需要打印“|”
{
printf("|");
}
}
printf("\n"); //打印完之后换行
if (i < row - 1) //在打印“---|”是比打印“ %c |”少一行
{
for (j = 0; j < col; j++) //设置打印多少行的“---|”
{
printf("---");
if (j < col - 1) //最后一列也不需要打印“|”
{
printf("|");
}
}
}
printf("\n");
}
}
可以看到,棋盘很好的打印了出来,接下来就需要轮到我们来进行下棋的环节了
假如我们设置玩家先下棋把,然后再电脑下棋,那么首先来设置玩家下棋的函数
设定一个函数:PlayerMove
源文件:test.c:
void game()
{
char board[ROW][COL] = { 0 };
//初始化棋盘:
InitBoard(board, ROW, COL); //将数组,行,列都传给这个函数实现初始化棋盘
//打印棋盘:
PrintfBoard(board, ROW, COL);
//玩家下棋:
PlayerMove(board,ROW,COL);
PrintfBoard(board, ROW, COL); //下完棋之后打印出棋盘
}
设定好先在头文件里面声明
头文件:game.h:
//函数的声明:
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘:
void PrintfBoard(char board[ROW][COL], int row, int col);
//玩家下棋:
void PlayerBoard(char board[ROW][COL], int row, int col);
声明好了之后,我们在game.c中实现这个函数:
源文件:game.c:
//玩家下棋:
void PlayerBoard(char board[ROW][COL], int row, int col)
{
printf("玩家下棋\n");
int x = 0;
int y = 0;
while (1) //设置死循环,如果输入非法就一直输入,如果输入正确就跳出循环
{
printf("请输入你所要下棋的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col) //用来判断坐标的合法性
{
if (board[x-1][y-1] != ' ') //因为玩家通常不会认为数组的下标是从0开始的
{ //他们通常认为下标是1,所以玩家输入的坐标-1才能得到棋盘 //中的坐标
printf("该位置已经落子,请重新输入坐标:>");
}
else
{
board[x-1][y-1] = '*';
break; //输入成功,则跳出循环
}
}
else //如果输入非法,重新输入
{
printf("输入非法,请重新输入:>");
}
}
}
玩家下完棋打印出棋盘,再是电脑下完棋打印棋盘
电脑下棋的话,我们就让电脑随机下棋,下完棋再打印出棋盘,所以需要再设置一个电脑下棋的函数
设定一个函数:ComputerMove
源文件:test.c:
void game()
{
char board[ROW][COL] = { 0 };
//初始化棋盘:
InitBoard(board, ROW, COL); //将数组,行,列都传给这个函数实现初始化棋盘
//打印棋盘:
PrintfBoard(board, ROW, COL);
//玩家下棋:
PlayerBoard(board, ROW, COL);
PrintfBoard(board, ROW, COL);
//电脑下棋:
ComputerMove(board, ROW, COL);
PrintfBoard(board, ROW, COL); //下完棋打印出棋盘
}
头文件里面要声明这个函数:
头文件game.h:
//函数的声明:
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘:
void PrintfBoard(char board[ROW][COL], int row, int col);
//玩家下棋:
void PlayerBoard(char board[ROW][COL], int row, int col);
//电脑下棋:
void ComputerMove(char board[ROW][COL], int row, int col);
电脑下棋是随机下棋,所以我们需要用到rand函数来生成随机数,并且在主函数中需要设置
源文件:game.c:
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋:>\n");
x = rand() % row; //生成随机数,要在头文件中包含#include
y = rand() % col; //rang()%row的意思就是随机生成0~2之间的数
while (1)
{
if (board[x][y] == ' ') //因为电脑下棋就是按照二维数组的小标来下的所以不用改
{
board[x][y] = '#';
break;
}
}
}
在使用rand函数时要在main函数中加上
srand((unsigned int)time(NULL));
源文件:test.c:
int main()
{
int input = 0;
srand((unsigned int)time(NULL)); //在使用time函数时也需要包含头文件#include
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input) //将输入进来的值进行判断
{
case 1: //如果为1,则玩游戏
printf("三子棋游戏:\n");
game();
break;
case 0: //如果为0,则退出游戏
printf("退出游戏\n");
break;
default: //既不是1也不是0,选择错误,重新选择吧
printf("选择错误,请重新选择\n");
break;
}
} while (input);
return 0;
}
头文件:game.h:
//包含头文件:
#include
#include
#include
#include
在玩家下完棋之后需要进行判断输赢,如果赢了,则跳出,没赢就继续,在电脑下完棋之后也需要进行判断,那假如棋盘下满了,没有人胜出,则为平局。一共四种情况,所以我们要分装一个判断输赢的函数
这个函数一共要处理四种情况,玩家赢、电脑赢、平局、继续游戏,所以我们假设:如果玩家赢,返回‘*’,如果电脑赢,返回‘#’,如果平局,返回‘P’,谁都没赢游戏继续,返回‘Q’,所以我们要用一个值来接收返回的字符
设定一个函数:IsWin
源文件:test.c:
void game()
{
int ret = 0;
char board[ROW][COL] = { 0 };
//初始化棋盘:
InitBoard(board, ROW, COL); //将数组,行,列都传给这个函数实现初始化棋盘
//打印棋盘:
PrintfBoard(board, ROW, COL);
//玩家下棋:
PlayerBoard(board, ROW, COL);
PrintfBoard(board, ROW, COL);
//判断输赢:
ret = IsWIN(board, ROW, COL);
//电脑下棋:
ComputerMove(board, ROW, COL);
PrintfBoard(board, ROW, COL);
//判断输赢:
ret = IsWIN(board, ROW, COL);
}
头文件中也要声明函数
头文件:game.h:
//函数的声明:
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘:
void PrintfBoard(char board[ROW][COL], int row, int col);
//玩家下棋:
void PlayerBoard(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);
在源文件game.c中来实现我们的函数
判断玩家赢还是电脑赢就是行连成三子,列连成三子,对角线连成三子,若为平局,就证明整个棋盘满了,也就是没有空格了,但要注意,排除空格,因为三个空格连成一起也不行
源文件:game.c:
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 < row; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
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 (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
//判断平局再分装一个函数IsFull
if (IsFull(board, row, col)) //可以看到这里与上面的函数不同的是,
{
return 'P'; //平局返回‘P ’
}
return 'Q'; //若上面的条件一个都没有发生,则返回‘Q’
}
分装一个判断是否平局的函数:同样的也要在头文件中声明
头文件:game.h:
//函数的声明:
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘:
void PrintfBoard(char board[ROW][COL], int row, int col);
//玩家下棋:
void PlayerBoard(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);
//判断是否平局
int IsFull(char board[ROW][COL], int row, int col);
//由于这里要接收返回值所以设置返回类型为int
源文件:game.c:
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 < row; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
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 (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
if (IsFull(board, row, col)) //如果返回为真,则进入
{
return 'P';
}
return 'Q';
}
IsFull函数的实现:
源文件:game.c:
int IsFull(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函数里面来接收这些返回值了:
源文件:test.c:
void game()
{
int ret = 0;
char board[ROW][COL] = { 0 };
//初始化棋盘:
InitBoard(board, ROW, COL); //将数组,行,列都传给这个函数实现初始化棋盘
//打印棋盘:
PrintfBoard(board, ROW, COL);
while (1) //由于这些下棋的过程是一个循环,只有当有人胜出或者平局才会跳出循环
{
//玩家下棋:
PlayerBoard(board, ROW, COL);
PrintfBoard(board, ROW, COL);
//判断输赢:
ret = IsWIN(board, ROW, COL); //设置一个变量来接收返回值
if (ret != 'Q') //如果ret不是‘Q’,则证明就有人胜出或者平局,则会跳出循环
{
break;
}
//电脑下棋:
ComputerMove(board, ROW, COL);
PrintfBoard(board, ROW, COL);
//判断输赢:
ret = IsWIN(board, ROW, COL);
if (ret != 'Q')
{
break;
}
}
//当跳出循环后,我们就应该判断是谁赢,还是平局
if (ret == '*')
{
printf("恭喜你,你赢了!\n");
}
else if (ret == '#')
{
printf("很遗憾,你输了!\n");
}
else if (ret == 'p')
{
printf("平局\n");
}
}
一整套的程序都写完了,在写程序的时候,我们要注意几点:
使用函数时要在头文件里面声明
使用的每一个库函数都要注意包含头文件
写完一个函数先让它运行一下,测试当前写的这个函数对不对
在设定函数时要注意设定的函数的返回类型
头文件:game.h:
#pragma once
//包含头文件:
#include
#include
#include
#include
//行和列的定义
#define ROW 3
#define COL 3
//函数的声明:
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘:
void PrintfBoard(char board[ROW][COL], int row, int col);
//玩家下棋:
void PlayerBoard(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);
//判断是否平局
int IsFull(char board[ROW][COL], int row, int col);
源文件:game.c:
#define _CRT_SECURE_NO_WARNINGS 1
#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] = ' ';
}
}
//memset(&board[row][col], ' ', row * col * sizeof(board[0][0]));
}
//打印棋盘:
void PrintfBoard(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)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
//玩家下棋:
void PlayerBoard(char board[ROW][COL], int row, int col)
{
printf("玩家下棋\n");
int x = 0;
int y = 0;
while (1)
{
printf("请输入你所要下棋的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x-1][y-1] != ' ')
{
printf("该位置已经落子,请重新输入坐标:>\n");
}
else
{
board[x-1][y-1] = '*';
break;
}
}
else
{
printf("输入非法,请重新输入:>\n");
}
}
}
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋:>\n");
x = rand() % row;
y = rand() % col;
while (1)
{
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//判断平局:
int IsFull(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;
}
//判断输赢:
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 < row; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
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 (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
if (IsFull(board, row, col))
{
return 'P';
}
return 'Q';
}
源文件:test.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void game()
{
int ret = 0;
char board[ROW][COL] = { 0 };
//初始化棋盘:
InitBoard(board, ROW, COL); //将数组,行,列都传给这个函数实现初始化棋盘
//打印棋盘:
PrintfBoard(board, ROW, COL);
while (1)
{
//玩家下棋:
PlayerBoard(board, ROW, COL);
PrintfBoard(board, ROW, COL);
//判断输赢:
ret = IsWin(board, ROW, COL);
if (ret != 'Q')
{
break;
}
//电脑下棋:
ComputerMove(board, ROW, COL);
PrintfBoard(board, ROW, COL);
//判断输赢:
ret = IsWin(board, ROW, COL);
if (ret != 'Q')
{
break;
}
}
if (ret == '*')
{
printf("恭喜你,你赢了!\n");
}
else if (ret == '#')
{
printf("很遗憾,你输了!\n");
}
else if (ret == 'p')
{
printf("平局\n");
}
}
void menu()
{
printf("********************\n");
printf("**** 1. play *****\n");
printf("**** 0. exit *****\n");
printf("********************\n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input) //将输入进来的值进行判断
{
case 1: //如果为1,则玩游戏
printf("三子棋游戏:\n");
game();
break;
case 0: //如果为0,则退出游戏
printf("退出游戏\n");
break;
default: //既不是1也不是0,选择错误,重新选择吧
printf("选择错误,请重新选择\n");
break;
}
} while (input);
return 0;
}
三子棋小游戏就写完了,如果本篇有什么疑问或者不足,大家可以私信或者在评论区指出,感谢大家阅读!