小游戏流程概述
完成一个游戏,我们首先要考虑的就是游戏大体框架.那我们就从流程开始入手,我们就使用game();函数来实现基本流程.
- 首先要有的肯定是游戏菜单,俗称目录.我们就使用menu()函数来展示基本菜单功能.
- 第二呢我们就需要创建我们的棋盘并初始化.我们使用InitBoard();函数来初始化我们的棋盘.
- 棋盘初始化之后我们使用display_board();函数来打印棋盘.并在每次落子之后重新打印棋盘.
- 拥有基本条件后,我们就可以使玩家之间落子博弈了.当然,我们还需要在每次落子之后判定游戏是否结束.
- 当游戏结束后,我们就需要重新展示菜单.询问玩家下一步流程.
当我们有了基本流程,我们就可以依次着手进行模块设计了
首先我们需要创建两个源文件和一个头文件.
| 名称 | 使用 |
|---|---|
| test.c | 使用test.c来实现游戏的基本流程 |
| game.h | 使用game.h来声明我们需要的函数和头文件 |
| game.c | 使用game.c来书写游戏具体实现 |
接下来我们就在test.c中写入main()函数.使用input变量来控制流程.
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;
}
srand((unsigned int)time(NULL)); 此条语句是生成随机数要使用的经典语句.看到它,我们就知道后面模块中要使用随机数.如果不理解这里暂且忘掉它,因为它的存在不会对代码产生影响.
代码向下走,我们就进入了一个简单的循环,首先menu(); 函数会打印我们的菜单,使得用户选择流程并进入switch语句.
void menu()
{
printf("**************************\n");
printf("********** 1.play ********\n");
printf("********** 0.exit ********\n");
printf("**************************\n");
}
简单的菜单使得用户的选择用三种返回,而我们用input来当做循环的结束条件,巧妙地完成了菜单的简易功能.
而当玩家选择了1,也就是进行游戏时,我们就进入到了game(); 模块开始了我们的游戏.
void game()
{
char ret;
char board[ROW][COL] = { 0 };
init_board(board,ROW,COL);
display_board(board, ROW, COL);
while (1)
{
player_move(board, ROW, COL);
display_board(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
break;
computer_move(board, ROW, COL);
display_board(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
break;
}
if (ret == 'O')
{
printf("玩家赢\n");
}
else if (ret == 'X')
{
printf("电脑赢\n");
}
else if (ret == 'Q')
{
printf("平局\n");
}
}
进入游戏,我们首先就是要初始化并打印出我们的棋盘.这里我们调用init_board(board,ROW,COL); 和 display_board(board, ROW, COL); 两个函数来实现初始化.
| 参数 | 属性 |
|---|---|
| board | 使用二维数组表示棋盘 |
| ROW | 表示棋盘的行数 |
| COL | 表示棋盘的列数 |
初始化完成后我们就要进入游戏,我们使用player_move(board, ROW, COL); 和 computer_move(board, ROW, COL); 来分别实现玩家落子和电脑落子.我们这里的流程设置为玩家和电脑对弈,如果需要改变玩法,可以更改这里的设置来实现.
落子之后我们使用is_win(board, ROW, COL); 来判断游戏是否结束.并返回一个用于流程运行的字符.我们使用ret来接收并进行判断.
这些就是我们需要在test.c中书写的代码了.下面展示test.c中的完整代码.(VS2019)
//三子棋 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()
{
char ret;
char board[ROW][COL] = { 0 };
init_board(board,ROW,COL);
display_board(board, ROW, COL);
while (1)
{
player_move(board, ROW, COL);
system("cls");
display_board(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
break;
computer_move(board, ROW, COL);
//system("cls");
display_board(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
break;
}
if (ret == 'O')
{
printf("玩家赢\n");
}
else if (ret == 'X')
{
printf("电脑赢\n");
}
else if (ret == 'Q')
{
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;
}
当然test.c中除了上述代码外还需要添加头文件game.h.因为game.h中声明了我们需要的所有函数和头文件.
接下来我们来看game.c中具体的实现.
由于game.c中是对模块的具体实现.那我们就根据test.c中的函数步骤来展示具体实现过程.
首先是初始化函数void init_board(char board[ROW][COL], int row, int col);.
void init_board(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
我们将棋盘中元素全都初始化为 ' ',这样有利于我们后续打印和更改.
接下来是打印棋盘函数void display_board(char board[ROW][COL], int row, int col);.
void display_board(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf(" %c ",board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
for (int j = 0; j < col; j++)
{
if (i < col - 1)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
我们使用'|'和'---'配合打印出一个简单的棋盘供我们使用.
下来就是我们玩家和电脑的落子过程.分别是void player_move(char board[ROW][COL], int row, int col); 和void computer_move(char board[ROW][COL], int row, int col) 两个函数.
void player_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家下棋->\n");
while (1)
{
printf("请输入下棋坐标-> ");
printf("提示:坐标(1,1 -- %d,%d)\n", row, col);
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] = 'O';
break;
}
else
{
printf("该坐标已被占用,请重新输入\n");
}
}
else
{
printf("坐标非法,重新输入\n");
}
}
}
由于我们写的是一个简单的三子棋游戏,所以我们这里只要求电脑可以下棋的程度.而最简单的电脑,那就是随机生成一组(x,y)来表示棋盘中的一个位置,并且判断该位置没有被占用的情况下落子即可.
void computer_move(char board[ROW][COL], int row, int col)
{
printf("电脑下棋:>\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = 'X';
break;
}
}
}
由于我们需要使用rand() 生成随机数,所以在前面main函数里,书写了和它配套使用的语句. 而且由于我们生成的随机数范围是(0-65535),所以我们还需要给(x,y)%行和列;
落子之后,我们需要使用char is_win(char board[ROW][COL], int row, int col); 判断游戏是否结束.
char is_win(char board[ROW][COL], int row, int col)
{
int j = 0;
for (j = 0; j < row; j++)
{
if (board[j][0] == board[j][1] && board[j][1] == board[j][2] && board[j][2] !=' ')
{
return board[j][0];
}
}
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[2][j] != ' ')
{
return board[0][j];
}
}
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[2][2] != ' ')
{
return board[0][0];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][2] && board[2][0] != ' ')
{
return board[2][0];
}
if (is_full(board,row,col))
{
return 'Q';
}
return 'C';
}
我们这里书写的判断是三子棋的输赢判断,如果ROW和COL不等于3的话,可能判断就不适用了.判断还使用了int is_full(char board[ROW][COL], int row, int col); 函数用来判断棋盘是否还有空位置.
int is_full(char board[ROW][COL], int row, int col)
{
int j = 0;
for (j = 0; j < row; j++)
{
for (int m = 0; m < col; m++)
{
if (' ' == board[j][m])
{
return 0;
}
}
}
return 1;
}
而写到这里,我们的game.c文件中具体的代码已经全都书写完了.下面展示game.c中的完整代码.(VS2019)
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void init_board(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
void display_board(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf(" %c ",board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
for (int j = 0; j < col; j++)
{
if (i < col - 1)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
void player_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家下棋->\n");
while (1)
{
printf("请输入下棋坐标-> ");
printf("提示:坐标(1,1 -- %d,%d)\n", row, col);
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] = 'O';
break;
}
else
{
printf("该坐标已被占用,请重新输入\n");
}
}
else
{
printf("坐标非法,重新输入\n");
}
}
}
void computer_move(char board[ROW][COL], int row, int col)
{
printf("电脑下棋:>\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = 'X';
break;
}
}
}
int is_full(char board[ROW][COL], int row, int col)
{
int j = 0;
for (j = 0; j < row; j++)
{
for (int m = 0; m < col; m++)
{
if (' ' == board[j][m])
{
return 0;
}
}
}
return 1;
}
char is_win(char board[ROW][COL], int row, int col)
{
int j = 0;
for (j = 0; j < row; j++)
{
if (board[j][0] == board[j][1] && board[j][1] == board[j][2] && board[j][2] !=' ')
{
return board[j][0];
}
}
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[2][j] != ' ')
{
return board[0][j];
}
}
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[2][2] != ' ')
{
return board[0][0];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][2] && board[2][0] != ' ')
{
return board[2][0];
}
if (is_full(board,row,col))
{
return 'Q';
}
return 'C';
}
game.c的头和test.c相同,都要引入game.h头文件.
接下来我们来看game.h中具体的书写
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 3
#define COL 3
void init_board(char board[ROW][COL], int row, int col);
void display_board(char board[ROW][COL],int row,int col);
void player_move(char board[ROW][COL], int row, int col);
void computer_move(char board[ROW][COL], int row, int col);
char is_win(char board[ROW][COL], int row, int col);
game.h就是用来引入我们的头文件和声明函数
以上就是实现简单三子棋的全部代码了.
让我们以简单的游戏截图来结束这篇小游戏吧.