初学C语言一个月,与大家分享一下,我的学习成果,希望能够得到大佬的指导。
一、小游戏中运用到所学知识
1.变量的初始化,赋值,改变
2.printf和scanf的使用
3.if语句的判断,switch语句的选择
4.循环语句的使用
5.数组和函数
二、扫雷游戏实现前的想法
1.扫雷游戏的规则
游戏的目的
找出所有的雷(点开所有的非雷方块)
基本游戏规则
在游戏棋盘上通过输入坐标的方式点开一个方格,若此方格为雷则游戏结束,若此方格不是雷则游戏继续,并显示出此方方格周围八个方格中雷的个数。
点开所有的非雷方格后,游戏结束。
2.扫雷游戏中棋盘的初始化,打印
游戏的实现要有两个棋盘,一个棋盘用来呈现给玩家,另一个棋盘用来存放答案。我们使用同一个函数对这两个棋盘初始化和打印。
3.棋盘中雷区的布置
棋盘中的雷必须是随机布置的,并且数量是一定的,我们可以先通过srand函数来生成一个种子,再通过rand函数生成两个随机数,用来表示坐标来布置雷。
4.空格的点开方式
我们用坐标的形式来表示每一个方块的位置,玩家通过输入坐标来掀开格子,玩家输入的合法性需要进行判断,输入的坐标有问题我们需要提醒玩家重新输入。
5.点开空格后显示的数字
若点开的方块不是雷,我们要使方块周围的雷数显示在原方块位置,我们可以通过一个函数来重复实现这一个功能。
6.游戏结束的判断
若点开了所有的非雷空格,游戏结束,我们需要知道显示数字的函数的执行次数来判断游戏是否结束。
7.可重复实现游戏
打印一个菜单让玩家选择游戏的进行与结束。
三、扫雷游戏的实现(附代码)
1.游戏的菜单实现
void Menu()
{
printf("*****************\n");
printf("***** MENU ****\n");
printf("***** 1.play ****\n");
printf("******0.exit*****\n");
printf("*****************\n");
}
2.两个棋盘的创建
char board_display[ROWS][COLS] = {0};//这里的ROWS表示玩家看到棋盘的行数,COLS表示列数
char board_answer[ROWS][COLS] = {0};//这里使用一样的行数列数,方便使用一个函数处理
3.棋盘的初始化
我们写一个函数来实现两个棋盘的初始化,我们需要把数组,数组的行数,列数,需要初始化成的字符传给这个函数
void IntialBoard(char board[ROWS][COLS],int rows, int cols, char set)
{
for(int i = 0; i < rows; i++)//i表示横坐标
{
for(int j = 0; j < cols; j++)//j表示纵坐标
{
board[i][j] = set;//用传来的字符赋值
}
}
}
4.棋盘的打印
我们写一个函数来实现棋盘的打印,我们需要把数组,数组的行数,列数传给这个函数。这里我们只要打印玩家需要看到的棋盘中间部分,并且为了方便玩家确定坐标,我们决定在打印的中间部分周围加上坐标,
void PrintBoard(char board[ROWS][COLS],int row ,int col)
{
for (int i = 1; i <= col; i++)//这里的col为COL,打印第一行为横坐标
{
printf("%d ",i);
}
printf("\n");
for(int i = 1;i <= row;i++)//这里的row为ROW
{
printf("%d ",i);//这里是在打印纵坐标
int j = 0;
for(j = 1;j <= col;j++)//这里的col为COL
{
printf("%c ",board[i][j]);//一个一个的打印方格
}
printf("\n");
}
}
5.雷的设置
我们写一个函数实现雷的设置,我们需要把数组,数组的行数,列数传给这个函数。这里我们需要注意设置雷的个数一定。
void SetMine(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = EASY_COUNT;//EASY_COUNT为设置雷的数量
while(count)//设定循环次数为雷的数量
{
x = rand()%row +1;//生成的0
6.方格周围雷的数计算
我们写一个函数来实现方格周围雷的计数,函数需要传入的参数为答案棋盘,用户输入的坐标值的x和y。
这里我们引入一个知识,'1'-'0'得到的值是1,因为ASCII码。
int GetMineCount(char board[ROWS][COLS], int x, int y)
{
int i = 0;
int count = 0;//创建一个返回值
for (i = -1; i <= 1; i++)//表示所输入坐标的周围数的行数
{
int j = 0;
for (j = -1; j <= 1; j++)//表示所输入坐标的周围数的列数
{
count += (board[x + i][y + j] - '0');//计算返回值
}
}
return count;//返回值count
}
7.雷的查找过程以及游戏胜利的判断
我们写一个函数来实现这个功能,需要传入的参数为两个棋盘,行数和列数。在这个函数中用户输入方块的坐标掀开方块,程序判断是否为雷,并调用GetMineCount函数的来显示周围的雷数。还要做到游戏是否胜利的判断。
void FindMine(char board_answer[ROWS][COLS], char board_display[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;//设置赢的标志
while (win < col*row - EASY_COUNT)
{
printf("请输入要排查的坐标:\n示例 2 4\n");
scanf("%d %d", &x, &y);//玩家输入坐标
if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标是否合理
{
if (board_answer[x][y] == '1')//输入的坐标是雷
{
printf("很遗憾,你踩雷了,游戏结束\n");
PrintBoard(board_answer, ROW, COL);//打印答案
break;
}
else //不是雷
{
int count = GetMineCount(board_answer, x, y);
board_display[x][y] = count + '0';//是int类型的count变为char类型再赋值
PrintBoard(board_display, ROW, COL);//每次都打印更新后的棋盘
win++;//标志自增
}
}
else
{
printf("输入的坐标有误x(1~9),y(1~9),重新输入\n");
}
}
if (win == row * col - EASY_COUNT)//判断赢得条件
{
printf("恭喜你,排雷成功\n");
PrintBoard(board_answer, ROW, COL);//打印答案
}
}
8.头文件问题
在上述代码中我们使用了printf()、scanf()、srand()、rand(),需要包含一些头文件,我们还定义了许多的变量,所以我们决定创建一个头文件。命名为game.h
#include
#include
#include
#ifndef game_h
#define game_h
#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
#define EASY_COUNT 10
#endif /* game_h */
void InitBoard(char board[ROWS][COLS],int rows,int cols,char set);
void PrintBoard(char board[ROWS][COLS],int row,int col);
void SetMine(char board[ROWS][COLS],int row,int col);
void FindMine(char board[ROWS][COLS], char show[ROWS][COLS], int row, int col);
9.整合代码
我们创建一个函数game()来整合一下代码,提高代码的可读性。
void game()
{
char board_answer[ROWS][COLS] = {0};//存放雷的信息
char board_display[ROWS][COLS] = {0};//存放排查出的雷的信息
//初始化棋盘
InitBoard(board_answer, ROWS, COLS, '0');
InitBoard(board_display, ROWS, COLS, '*');
//布置雷
SetMine(board_answer, ROW, COL);
//打印棋盘
PrintBoard(board_display, ROW, COL);
//排查雷
FindMine(board_answer, board_display, ROW, COL);
}
我们创建一个C语言文件来提高代码可读性,命名为game.c
#include "game.h"
void IntialBoard(char board[ROWS][COLS],int rows, int cols, char set)
{
for(int i = 0; i < rows; i++)//i表示横坐标
{
for(int j = 0; j < cols; j++)//j表示纵坐标
{
board[i][j] = set;//用传来的字符赋值
}
}
}
void PrintBoard(char board[ROWS][COLS],int row ,int col)
{
for (int i = 1; i <= col; i++)//这里的col为COL,打印第一行为横坐标
{
printf("%d ",i);
}
printf("\n");
for(int i = 1;i <= row;i++)//这里的row为ROW
{
printf("%d ",i);//这里是在打印纵坐标
int j = 0;
for(j = 1;j <= col;j++)//这里的col为COL
{
printf("%c ",board[i][j]);//一个一个的打印方格
}
printf("\n");
}
}
void SetMine(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = EASY_COUNT;//EASY_COUNT为设置雷的数量
while(count)//设定循环次数为雷的数量
{
x = rand()%row +1;//生成的0= 1 && x <= row && y >= 1 && y <= col)//判断坐标是否合理
{
if (board_answer[x][y] == '1')//输入的坐标是雷
{
printf("很遗憾,你踩雷了,游戏结束\n");
PrintBoard(board_answer, ROW, COL);//打印答案
break;
}
else //不是雷
{
int count = GetMineCount(board_answer, x, y);
board_display[x][y] = count + '0';//是int类型的count变为char类型再赋值
PrintBoard(board_display, ROW, COL);//每次都打印更新后的棋盘
win++;//标志自增
}
}
else
{
printf("输入的坐标有误x(1~9),y(1~9),重新输入\n");
}
}
if (win == row * col - EASY_COUNT)//判断赢得条件
{
printf("恭喜你,排雷成功\n");
PrintBoard(board_answer, ROW, COL);//打印答案
}
}
我们创建一个C语言文件作为main文件命名为main.c
#include "game.h"
void Menu()
{
printf("*****************\n");
printf("***** MENU ****\n");
printf("***** 1.play ****\n");
printf("******0.exit*****\n");
printf("*****************\n");
}
void game()
{
char board_answer[ROWS][COLS] = {0};//存放雷的信息
char board_display[ROWS][COLS] = {0};//存放排查出的雷的信息
//初始化棋盘
InitBoard(board_answer, ROWS, COLS, '0');
InitBoard(board_display, ROWS, COLS, '*');
//布置雷
SetMine(board_answer, ROW, COL);
//打印棋盘
PrintBoard(board_display, ROW, COL);
//排查雷
FindMine(board_answer, board_display, ROW, COL);
}
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;
}
四、反思与总结
以上的代码仍存在许多的问题。如无法实现游戏的重复运行,运行一次只能进行一次游戏。如排查雷的过程中,如果玩家输入多次相同的坐标会导致bug的出现。这些bug我会在不断的学习中进行更改。望大家能够不嫌弃。