想必大家在学习了C语言之后,多多少少有想过自己做一些小游戏吧,那么,它来了!!!这次内容就给大家介绍一个简单的练手小游戏——三子棋( tic tac toe)!
1.游戏玩法
2.游戏实现
2.1 准备
1. tic_tac_toe.h 用于存放程序的声明
2. tic_tac_toe.c 用于实现完成三子棋游戏相关的函数
3. test.c 用于测试和存放主函数
2.2 tic_tac_toe.h
此次我们将用到以下函数:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#define ROW 3//行
#define COL 3//列
void InitBoard(char board[ROW][COL], int row, int col);//初始化棋盘
void PrintBoard(char board[ROW][COL], int row, int col);//打印棋盘
void PlayerMove(char board[ROW][COL], int row, int col, char playernum);//玩家操作
void ComputerMove(char board[ROW][COL], int row, int col);//电脑操作
/*
1:满了
0:没满
*/
int Is_Full(char board[ROW][COL], int row, int col);
/*
玩家赢:1
电脑赢:0
平局:T
继续:C
*/
char Is_Win(char board[ROW][COL], int row, int col);//判断是否赢了
//玩家对玩家
void Player_Player();
//玩家对电脑
void Player_Computer();
2.3 tic_tac_toe.c
2.3.1 初始化棋盘
首先,当棋盘上没有棋子时,我们用空格占据每个位置,从而达到初始化的效果,代码如下:
void InitBoard(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++)
{
board[i][j] = ' ';
}
}
}
2.3.2 打印棋盘
此处,我们通过 ‘|’ 和 ‘-’ 将棋盘分隔出来,代码如下:
void PrintBoard(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");
}
}
}
2.3.3 玩家行动
此处 playernum参数是为了在玩家vs玩家时,通过传入两个不同参数(’1‘和’2‘,可自行更改),判断区分以达到通过用相同的函数下不同类型的棋子(此处棋子为’1‘和’0‘,可自行更改)。
void PlayerMove(char board[ROW][COL], int row, int col, char playernum)
{
char ret = 0;//用于表示下棋的子,
int x = 0;//表示具体的行
int y = 0;//表示具体的列
//当玩家vs玩家时,区分下棋的子
if (playernum == '1')
ret = '1';
if (playernum == '2')
ret = '0';
while (1)
{
printf("请输入你要下的位置坐标,用空格隔开->");
scanf("%d %d", &x, &y);
//输入合理,可以落子
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//判断落子位置是否已被占用
if (board[x - 1][y - 1] == ' ')//x-1,y-1是为了转化为数组下表
{
board[x - 1][y - 1] = ret;
break;
}
else
{
printf("该位置已被占,请重新选择位置\n");
}
}
else//输入不合理
{
printf("坐标不合理,请重新输入\n");
}
}
}
2.3.4 电脑行动
电脑行动板块,我们需要用到随机数,由于是电脑自动操作,所以直接将其随机数通过取模限制在数组下标范围内,即:0~2,电脑下的棋在此处用’0‘表示。
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0; //0~row-1
int y = 0; //0~col-1
printf("电脑下棋\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '0';
break;
}
}
}
2.3.5 判断棋盘是否下满
在对局中如果达成平局,则棋盘一定下满了,此处我们将通过 Is_Full 函数的返回值来判断棋盘是否满了:
int Is_Full(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++)
{
if (board[i][j] == ' ')//若还有空格,则说明没下满
{
return 0;
}
}
}
return 1;//下满了返回1
}
2.3.6 判断对局是否结束
对局结束有三种情况:1.玩家(玩家1)获胜;2.电脑(玩家2)获胜;3.平局。在此,我们通过 Is_Win 函数对每次下棋后进行判断,通过其返回值表示不同结果,此处,若返回’1‘则表示情况1;若返回’0‘则表示情况2;若返回’T'则表示平局;若返回'C'则表示对局未结束,另一方接着下,代码实现如下:
char Is_Win(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[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];
}
//平局
if (Is_Full(board, row, col) == 1)
{
return 'T';
}
return 'C';
}
到此,三子棋需要的基本功能就大致已经实现了,剩下的就是对它们进行‘组装’。
2.3.7 玩家vs玩家
void Player_Player()
{
char board[ROW][COL] = { 0 };//用二维数组模拟棋盘
InitBoard(board, ROW, COL);//初始化棋盘
PrintBoard(board, ROW, COL);//打印棋盘
char ret = 0;
while (1)
{
printf("玩家1请下棋\n");
PlayerMove(board, ROW, COL,'1');//玩家行动
PrintBoard(board, ROW, COL);
//判断是否产生输赢
ret = Is_Win(board, ROW, COL);
if (ret != 'C')//当返回值不为C,则说明已经产生了结果
{
break;
}
printf("玩家2请下棋\n");
PlayerMove(board, ROW, COL,'2');//玩家行动
PrintBoard(board, ROW, COL);
//判断是否产生输赢
ret = Is_Win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '1')
{
printf("玩家1赢\n");
}
if (ret == '0')
{
printf("玩家2赢\n");
}
if (ret == 'T')
{
printf("平局\n");
}
}
2.3.8 玩家vs电脑
void Player_Computer()
{
char board[ROW][COL] = { 0 };//用二维数组模拟棋盘
InitBoard(board, ROW, COL);//初始化棋盘
PrintBoard(board, ROW, COL);//打印棋盘
char ret = 0;
while (1)
{
printf("玩家请下棋\n");
PlayerMove(board, ROW, COL,'1');//玩家行动
PrintBoard(board, ROW, COL);
//判断是否产生输赢
ret = Is_Win(board, ROW, COL);
if (ret != 'C')当返回值不为C,则说明已经产生了结果
{
break;
}
ComputerMove(board, ROW, COL);//电脑行动
PrintBoard(board, ROW, COL);
//判断是否产生输赢
ret = Is_Win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '1')
{
printf("玩家赢\n");
}
if (ret == '0')
{
printf("电脑赢\n");
}
if (ret == 'T')
{
printf("平局\n");
}
}
2.4 test.c
2.4.1 菜单
void menu()//菜单
{
printf("**********************************\n");
printf("********** 三子棋小游戏 **********\n");
printf("********* 1.玩家vs玩家 *********\n");
printf("********* 2.玩家vs电脑 *********\n");
printf("********** 0.退出游戏 **********\n");
printf("**********************************\n");
}
2.4.2 进入游戏
void tic_tac_toe(int input)//三子棋游戏
{
system("cls");//清理界面
switch (input)
{
case 1:
Player_Player();
break;
case 2:
Player_Computer();
break;
}
printf("\n按任意键返回主菜单......");
int ret = getch();
system("cls");//清理界面
}
2.4.3 主函数
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择->");
scanf("%d", &input);
switch (input)
{
case 1:
tic_tac_toe(input);
break;
case 2:
tic_tac_toe(input);
break;
case 0:
printf("退出游戏");
break;
default:
printf("选择错误,请重新选择");
break;
}
} while (input);
return 0;
}
3. 运行演示
本次内容就到这里啦,期待大家的点赞和关注,也欢迎大家提出意见!