小伙伴们,今天让我们来设计一个小游戏吧!三子棋是怎样通过代码实现的呢?让我们一探究竟吧😉
文章目录
前言
一、理清创建思路
创建几个文件来实现:
test.c //测试游戏逻辑
游戏的模块:
game.h //函数的声明
game.c //函数的实现
二、test.c代码块
**注意:**详细的分析具体到每一步是什么操作以及思路步骤的顺序,请打开下面的代码查看,按序号指引结合game.c和game.h代码块一步步理清操作思路哦🤗🤗
#define _CRT_SECURE_NO_WARNINGS 1
//13.将头文件移到game.h中,注释头文件
//#include<stdio.h>
//6.在代码前面包含头文件game.h,就可以用了
#include "game.h"
void menu() {
printf("***************************************************\n");
printf("***************** 1.play *************\n");
printf("***************** 0.exit *************\n");
printf("***************************************************\n");
}
void game() {
//5.三子棋存放数据需要一个3*3的二维数组 char board[3][3] = { 0 };
//如果在这里写成char board[3][3] = { 0 };的形式,以后扩大棋盘的时候再修改非常不方便
//所以将棋盘的行和列定义变量ROW,COL;在game.h中声明,以后修改棋盘大小的时候在game.h中修改变量的大小即可
char board[ROW][COL] = { 0 };
//7.初始化棋盘
//当开始的时候棋盘中放的是空格,下棋之后空格里面变成符号
//创建一个初始化棋盘的函数,把棋盘,几行几列传进来
InitBoard(board, ROW, COL); //8.初始化函数的实现怎么实现?在game.h中声明,请见game.h
//14.显示棋盘(在数字打印的基础上还要打印棋盘的框框)
DisplayBoard(board, ROW, COL);
char ret = 0; //48.因为最后也要用到ret,所以最好把ret定义到外面
while (1) {
//20.下棋:一人下一步,每人下完打印棋盘,判断输赢
//21.玩家下棋:实际上是要落子,落到棋盘board里面,传参的时候数组要传过去,几行几列也要给过来
PlayerMove(board, ROW, COL);
//25.打印棋盘
DisplayBoard(board, ROW, COL);
//35.判断输赢:判断数组里面是否有三行三列或者对角线上有三个相同的元素
//还是判断数组,把数组传进去,还有几行几列
//46.要知道返回值才知道谁赢,定义变量ret来接受返回值
ret = IsWin(board, ROW, COL); //如果ret返回的不是C的话,游戏就结束
if (ret != 'C') {
break;
}
//36.实际上还要判断四种结果:(1)电脑赢(2)玩家赢(3)平局(4)继续(如果不是玩家赢电脑赢平局,那么游戏继续)
//如果电脑赢,返回'#'
//如果玩家赢,返回'*'
//如果平局.返回'Q'
//如果继续,返回'C'
//26.电脑下棋
Computermove(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
//47.判断输赢:同样的道理这里也接收一下判断输赢的结果
ret = IsWin(board, ROW, COL); //如果ret返回的不是C的话,游戏就结束
if (ret != 'C') {
break;
}
}
//48.跳出上面的循环判断谁赢了,而不是在每次判断输赢的时候写上下面这段代码,避免了代码的冗余
if ('*' == ret) {
printf("玩家赢\n");
}else if('#'==ret) {
printf("电脑赢\n");
}
else if('Q'==ret){
printf("平局\n");
}
}
int main() {
int input = 0;
srand((unsigned int)time(NULL)); //30.使用rand()函数前必须调用srand();用时间戳作为随机数生成的起点,返回类型定义为unsigned int
//31.需要包含头文件,直接写到game.h中
do //1.制作一个游戏,玩玩一把不够玩,再来一把,采用do while循环
{
menu(); //2.创建一个菜单函数,让它操控玩游戏和退出游戏的功能
printf("请选择:>");
scanf("%d", &input);
switch (input) { //3.根据input输入的值做出判断
case 1: //选择1进入游戏
game(); //4.game函数来设计游戏
break;
case 0: //选择0退出游戏
printf("退出游戏\n");
break;
default: //选择的既不是1又不是0弹出选择错误
printf("选择错误,请重新选择\n");
break;
}
} while (input);
return 0;
}
三、game.h代码块
#pragma once
#define ROW 3
#define COL 3
//9.函数的声明(在game.c中去写这个函数)
//初始化棋盘
void InitBoard(char board[ROW][COL], int row,int col); //初始化数组里面的形参,棋盘用数组来接收,再给定行和列的形参,使用小写用于区分
//13.将头文件移到game.h中
#include<string.h>
#include<stdio.h>
//32.包含头文件
#include<stdlib.h> //rand()头文件
#include<time.h> //time头文件
//15.打印棋盘(棋盘传进来,几行几列)
void DisplayBoard(char board[ROW][COL], int row, int col);
//22.声明玩家下棋:(记得写void)
void PlayerMove(char board[ROW][COL], int row, int col);
//27.声明电脑下棋的函数:(记得写void)
void Computermove(char board[ROW][COL], int row, int col);
//37.声明判断输赢的函数:
char IsWin(char board[ROW][COL], int row, int col);
四、game.c代码块
#define _CRT_SECURE_NO_WARNINGS 1
//10.实现初始化函数的时候,要用到行和列即ROW,COL,所以要包含头文件
#include "game.h"
//11.(2.2)memset函数需要头文件
//#include<string.h>
//12.通过观察test.c和game.c的头文件,我们发现其实只要把头文件全部写入game.h然后包含一下就都可以使用了,这样的写法更简单
// 接下来去把头文件全部写到game.h中,这里的话为了使读者看的更清晰,我就把test.c中的#include<stdio.h>注释了
//所以如果使用memset函数,那么将game.c中的#include<string.h>写在game.h中即可
//11.(1)写初始化函数方法一:
void InitBoard(char board[ROW][COL], int row, int col) {
int i = 0;
for (i = 0; i < row; i++) { //i遍历多行
int j = 0;
for (j = 0; j < col; j++) { //j遍历多列
board[i][j] = ' '; //将每个格子放空格占位
}
}
//11.(2.1)写初始化函数方法一:
//memset(&board[0)[0], ' ', row* col * sizeof(board[0][0]);
//解释:
//memset(数组首地址,置为空格,数组的总大小(把这么多字节置为空格) );
}
//16.写打印棋盘的函数
//即使没有下棋的时候也要把棋盘的格子打印出来
//棋盘:
// 一行数据
// 一行分割
// 一行数据
// 一行分割
// 一行数据
// (一行分割)
//上面可以看成两个两个一组,最后一行分割不用打印,可以通过控制条件不用打印
//void DisplayBoard(char board[ROW][COL], int row, int col) {
// int i = 0;
// int j = 0;
// for (i = 0; i < row; i++) { //二维数组的遍历
// printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]); //17.这里把列写死了,列写成三列了,当将game.h中的ROW,COL改为十行十列,打印出棋盘的运行结果是十行三列就是因为这里写死了
// //18.优化一下,注释这一整段代码
// if (i < row - 1) //最后一组的时候不打印分割线
// printf("---|---|---\n");
//
// }
//}
//19.优化打印棋盘:
void DisplayBoard(char board[ROW][COL], int row, int col) {
int i = 0;
int j = 0;
for (i = 0; i < row; i++) {
int j = 0;
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"); //分割的符号打印完换行
}
}
//23.实现玩家下棋:
void PlayerMove(char board[ROW][COL], int row, int col) {
int x=0; //行用x来控制
int y=0; //列用y来控制
printf("玩家下棋>:\n");
while(1){ //24.落棋的这个动作反复操作,所以用while循环,直到落棋正确break跳出
printf("请输入要下棋的坐标:>\n"); //输入坐标要输入行和列,所以前面要定义两个变量
scanf("%d%d", &x, &y); //请玩家输入坐标,在玩家的认识里行和列都是从第一行第一列开始,当然也有乱输入坐标的玩家,这个时候就要对他们输入的进行判断
if (x >= 1 && x <= row && y >= 1 && y <= col) {
//判断玩家落棋的地方是不是空格,
//但是
//比如玩家输入的1 2,对应到数组里面并不是第一行第二列,数组的下标是从0开始的,所以玩家输入的行和列的值都要-1
if (board[x - 1][y - 1] == ' ') { //是空格的时候可以落棋
board[x - 1][y - 1] = '*';
break;
}
else {
printf("坐标被占用,请重新输入\n"); //不是空格的时候进行提示
}
}
else {
printf("坐标非法,请重新输入\n");
}
}
}
//28.实现电脑下棋的函数:
//电脑随机下棋
void Computermove(char board[ROW][COL], int row, int col) {
int x = 0; //创建坐标
int y = 0;
printf("电脑下棋>:\n");
while (1) { //35.下棋的位置如果不是空格,重新生成就好了,不用提示,所以用while循环控制
x = rand() % row; //29.随机生成0-2的数字,%上row余数就是0-2,下面同理
y = rand() % col;
//33.生成的坐标所在的位置万一已经有棋就不行了,需要重新设置坐标,所以要进行判断
if (board[x][y] == ' ') {
board[x][y] = '#'; //34.下棋的位置如果是空格,就放置为#,break跳出,
break;
}
}
}
//44.创建棋盘是否满了的函数:有空格说明没满,没空格说明满了,返回类型设置为int
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] == ' ') { //如果是空格的话,返回0;不是的话返回1
return 0;
}
}
}
return 1;
}
//38.实现判断输赢的函数:
//如果电脑赢,返回'#'
//如果玩家赢,返回'*'
//如果平局.返回'Q'
//如果继续,返回'C'
char IsWin(char board[ROW][COL], int row, int col) {
int i = 0;
for (i = 0; i < row; i++) { //39.循环row次,判断三行
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++) { //40.循环col次,判断三列
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ') { //判断一列三个是否相等,但是这三个不能都是空格,所以要排除这种情况
return board[0][i]; //如果三个一样满足赢得条件,返回这三个里面一个的符号,因为在前面已经约定好电脑赢和玩家赢的标志符号,这样做非常方便,这样的设计非常好
}
}
//41.判断两条对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ') {
return board[0][0];
}
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ') {
return board[0][0];
}
//42.以上四种情况中的一种都是玩家赢或者是电脑赢,下面这种情况是平局情况
//判断是否为平局:前面没人赢的情况下,棋盘满了,就是平局
//也就是判断棋盘满了
if (IsFull(board, row, col)) { //43.在上面需要创建判断棋盘是否满了的函数
return 'Q';
}
//45.如果前面都没有返回的话,游戏继续
return 'C';
}
}
五、简易版代码块
1.test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
printf("*******************************\n");
printf("******** 1. play ******\n");
printf("******** 0. exit ******\n");
printf("*******************************\n");
}
void game()
{
//存放数据需要一个3*3的二维数组
char board[ROW][COL] = {0};
//初始化棋盘
InitBoard(board, ROW, COL);
//显示棋盘
DisplayBoard(board, ROW, COL);
char ret = 0;
while (1)
{
//玩家下棋
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
//电脑下棋
ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if ('*' == ret)
{
printf("玩家赢\n");
}
else if ('#' == ret)
{
printf("电脑赢\n");
}
else if ('Q' == ret)
{
printf("平局\n");
}
}
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.game.h
#pragma once
//头文件的包含
#include <string.h>
#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 PlayerMove(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);
3.game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
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] = ' ';
}
}
//memset(&board[0][0], ' ', row*col*sizeof(board[0][0]));
}
//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]);
// }
// printf("\n");
// }
//}
//void DisplayBoard(char board[ROW][COL], int row, int col)
//{
// int i = 0;
// int j = 0;
// for (i = 0; i < row; i++)
// {
// printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
// if(i < row-1)
// printf("---|---|---\n");
// }
//}
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 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 PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
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");
}
}
}
//电脑随机下棋
void ComputerMove(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;
}
}
}
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;
}
//判断输赢
//玩家赢 - '*'
//电脑赢 - '#'
//平局 - 'Q'
//继续 - '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 < 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 (IsFull(board, row, col))
{
return 'Q';
}
//游戏继续
return 'C';
}
六、运行结果
(1)第一次测试
(2)第二次测试
总结
今天你学会制作这个小游戏了呢小伙伴们?💕
如果哪里写的有问题,欢迎大家帮我指正.
最后,如果对友友们有所帮助的话,可以留下关注点赞收藏哦~🥰💕❤️