游戏效果
三子棋,顾名思义就是:有一个三行三列的棋盘,然后玩家和电脑各自下棋。
游戏的运行如下:
- 有一个3 x 3的一个棋盘
- 玩家下棋用
* 表示 - 电脑下棋用
# 表示 - 下棋方式就是输入棋盘的坐标
代码规划
因为这是一个小游戏,涉及到游戏的代码比较多,不是几十行就能搞定的,所以我不可能全部写在一个test.c 的文件里面去;
这里规划一下代码存放,创建三个文件:
test.c :游戏的测试逻辑game.c :游戏的实现逻辑game.h :游戏实现函数的声明
创建代码
这里使用的是VS2019
设置一下布局
游戏搭建
任何一个项目的实现,最重要的就是逻辑结构搭建,而各个功能的实现就是采取函数(模块化)进行细分;
所以我们需要搭建逻辑,那么逻辑结构是啥呢?
往下看👇
主函数
- 运行游戏的时候,内容显示为:1.开始游戏;0.退出游戏;输入其他数字提示:输入错误,请重新输入!
- 按1开始游戏
- 按0退出游戏
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
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;
}
游戏game函数
前面的逻辑结构已经搭建,而我们需要实现的就是game() 函数模块
那game() 函数实现的功能是什么呢?
- 首先是数据存储到一个字符的二维数组中,数组的内容应该全部都是空格;
- 使用
InitBoard() 函数,初始化棋盘; - 使用
DisplayBoard() 函数,打印棋盘(3x3); - 玩家和电脑的对战模块,也就是:玩家下棋
Player() 函数和电脑下棋Compuer() 函数; - 每一局对战后,都要判断电脑或玩家是否赢,所以需要一个判断输赢的
IsWin() ;函数;
void game()
{
char board[ROW][COL] = {0};
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
int ret = 0;
while (1)
{
Player(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
Computer(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("恭喜您取得胜利!!!!!!!!!\n\n");
}
else if (ret == '#')
{
printf("你也太辣鸡了吧,电脑都下不赢\n");
}
else
{
printf("哎~~,你的技术不行啊,居然和电脑达成平手\n");
}
}
菜单menu函数
菜单功能十分简单
代码示例如下:
void menu()
{
printf("************************\n");
printf("****EDC's Game World****\n");
printf("****** 1.Play ******\n");
printf("****** 0.Exit ******\n");
printf("************************\n");
}
初始化棋盘InitBoard函数
既然是初始化函数,说明我们的要求就是把二维数组board 初始化为全空格
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] = ' ';
}
}
}
打印棋盘DisplayBoard函数
首先我们来设计一个棋盘,如下:
首先,看这个棋盘,是由带+ 的四行行,加上带| 的四行组成
先来看看一组规则:斜杠+空格+空格+空格
再来看一组规则:+---+
最后因为我们下棋落子的地方在中间,也就是我红色标记的地方;
该地方需要用字符来输入,也就是用%c 打印
代码如下:
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
printf("+---+---+---+\n");
for (j = 0; j < col; j++)
{
printf("| %c ", board[i][j]);
}
printf("|\n");
}
printf("+---+---+---+\n");
}
玩家下棋Player函数
玩家下棋采用的是坐标输入的方式;
玩家输入一个坐标,那么棋盘上的相应位置就应该用* 表示;
输入坐标时候还要检验该位置是否已经落子了;
void Player(char board[ROW][COL], int row, int col)
{
printf("请分别输入横纵坐标(输入数字请用空格隔开):> ");
int x = 0;
int y = 0;
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("该坐标位置已经落子,然后重新输入坐标:> ");
}
}
else
{
printf("该坐标超界,请重新输入:> ");
}
}
DisplayBoard(board, ROW, COL);
}
上面代码中为什么要用x - 1 和y - 1 呢?
因为数组的下标是从0开始的;
比如我们输入:1 2 ,而实际落子的地方用数组表示是应该是:0 1 ;
考虑到玩家不一定是程序员,他也不知道数组是从0开始数的,
电脑下棋Computer函数
由于是电脑下棋,我们无法操作,于是只有让电脑随机下了;
缺陷是电脑就有点智障 了,哈哈哈!
void Computer(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋:> \n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
DisplayBoard(board, ROW, COL);
}
大家可能都注意到了srand((unsigned long)time(NULL)) ,这个函数经常跟rand 函数一起使用,是对随机数发生器的初始化函数
在C语言中它们都位于<stdlib.h> 头文件中
- 原型:
void srand(unsigned int seed) - 原型:
void rand(void)
seed 相当于一个种子,srand 函数根据这个种子seed ,设置一个随机的起点,rand 函数就根据这个起点,返回一个随机数[seed , RAND_MAX]
rand 函数每一次调用的时候,都会看看之前是否调用了srand 函数,如果调用了,就会调用srand(seed) 来初始化她的随机值,如果没有,则会默认的调用srand(1) 来初始化它的值。
大家可能会问那调不调用不都一样吗?是的!
但是为了让每一次程序的调用都产生不同的值,所以经常使用系统时间来初始化,也就是time(NULL)
判断输赢IsWin函数
玩家或者电脑下子后,需要判断双方有一方是否赢;
IsWin 的作用就是判断是否有一方赢;
其中:
- 返回值:
* 代表玩家胜利; - 返回值:
Q 代表双方平局; - 返回值:
# 代表电脑胜利; - 返回值:
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;
}
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][1] != ' ')
{
return board[i][1];
}
}
for (i = 0; i < col; 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[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 (1 == IsFull(board, ROW, COL))
{
return 'Q';
}
return 'C';
}
完整代码
test.c :游戏的测试逻辑game.c :游戏的实现逻辑game.h :游戏实现函数的声明
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
printf("************************\n");
printf("****EDC's Game World****\n");
printf("****** 1.Play ******\n");
printf("****** 0.Exit ******\n");
printf("************************\n");
}
void game()
{
char board[ROW][COL] = {0};
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
int ret = 0;
while (1)
{
Player(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
Computer(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("恭喜您取得胜利!!!!!!!!!\n\n");
}
else if (ret == '#')
{
printf("你也太辣鸡了吧,电脑都下不赢\n");
}
else
{
printf("哎~~,你的技术不行啊,居然和电脑达成平手\n");
}
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
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;
}
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] = ' ';
}
}
}
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
printf("+---+---+---+\n");
for (j = 0; j < col; j++)
{
printf("| %c ", board[i][j]);
}
printf("|\n");
}
printf("+---+---+---+\n");
}
void Player(char board[ROW][COL], int row, int col)
{
printf("请分别输入横纵坐标(输入数字请用空格隔开)>: ");
int x = 0;
int y = 0;
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("该坐标超界,请重新输入\n");
}
}
DisplayBoard(board, ROW, COL);
}
void Computer(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋:> \n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
DisplayBoard(board, ROW, COL);
}
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][1] != ' ')
{
return board[i][1];
}
}
for (i = 0; i < col; 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[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 (1 == IsFull(board, ROW, COL))
{
return 'Q';
}
return 'C';
}
game.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.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 Player(char board[ROW][COL], int row, int col);
void Computer(char board[ROW][COL], int row, int col);
char IsWin(char board[ROW][COL], int row, int col);
动画演示
|