1.概要
为了提高C初学者对C语言基本语法的掌控能力,一个极简版的扫雷游戏是十分适合锻炼代码能力的。下面分享仅用数组、函数这些C语言基本语法实现的一个小游戏——“Minesweeper”。
我需要说明的是仅仅是用来练习简单C语言基础语法代码能力的,而并非去尽力完善这个游戏,当然自己有时间有能力也可以去自己完善一下。
2.实现核心思想
用两个二维数组,一个数组用来对外展示,我们称之为show,另一个mine数组记录"雷"与"非雷"。
- 对于show数组,默认是’*'状态,用来模拟未扫描的区域;倘若已经扫过了,且没有雷我们将其替换为该位置周围雷的数量。
- 对于mine数组,我们’0’标识非雷,'1’标识雷。
同时,因为要在下文统计到某个位置周围雷的个数,为了防止数组越界,因而对该棋盘周围多加一圈。
3.实现过程
我们设计的小游戏,整体用三个文件来进行设计的。
- game.c文件:用来实现具体核心游戏函数
- game.h文件:用来作为该游戏的小目录,包括一些宏定义和函数声明
- Test.c文件:用来实现游戏的整体框架以及测试
3.1游戏框架
设计一个很简单的游戏框架是一个游戏设计的开始。该内容没有什么重点,略。
// Test.c文件中 void menu() { printf("---------------------\n"); printf("-----1.play game-----\n"); printf("-----0.exit game-----\n"); printf("---------------------\n"); } TestGame() { srand((unsigned int)time(0)); int input = 0; do { menu(); printf("Input options, please:\n"); scanf("%d", &input); switch (input) { case 1: printf("Minesweeper begins!\n"); game(); break; case 0: printf("Successfully exited the game\n"); break; default: printf("The input value is invalid\n"); break; } } while (input); } int main() { TestGame(); return 0; }
实现好了游戏的整体框架,我们要来想一想这个游戏该怎么做了。
3.2游戏逻辑
- 初始化棋盘:首先我们得准备两个二维数组来当作棋盘,并初始化其值。
- 打印show棋盘:打印要对外展示的棋盘。
- 设置雷:在mine棋盘中设置雷,用’1’进行标识
- 扫雷:玩家输入坐标并接收,然后作出反馈
然后对于我们要在上面框架中写的game()
,我们就得出下面游戏逻辑:
#include"game.h" void game() { char Mine[ROWS_MAX][COLS_MAX]; char show[ROWS_MAX][COLS_MAX]; MineInit(Mine, ROWS_MAX, COLS_MAX, '0'); MineInit(show, ROWS_MAX, COLS_MAX, '*'); printf("----------Minesweeper interface-----------\n"); //MinePrint(Mine, ROW_MAX, COL_MAX); MinePrint(show, ROW_MAX, COL_MAX); SetMines(Mine, ROW_MAX, COL_MAX); ClearMines(Mine, show, ROW_MAX, COL_MAX); }
具体的game.h文件内容如下:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> #include<time.h> #include<windows.h> #define ROW_MAX 9 #define COL_MAX 9 #define ROWS_MAX ROW_MAX + 2 #define COLS_MAX COL_MAX + 2 #define MINE_COUNT 5 void MineInit(char(*arr)[COLS_MAX], int rows, int cols, char val); void MinePrint(char(*arr)[COLS_MAX], int row, int col); void SetMines(char(*arr)[COLS_MAX], int row, int col); void ClearMines(char(*Mine)[COLS_MAX], char(*Show)[COLS_MAX], int row, int col);
初始化棋盘 MineInit
那如何进行初始化棋盘呢?因为有两个棋盘,一个需要置0,另一个需要置✳
这里需要指出的是不需要写两个函数哈,只需要把需要初始化的值当作参数传入函数里就可以通过一个函数来处理了。
void MineInit(char(*arr)[COLS_MAX], int rows, int cols, char val) { for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { *(*(arr + i) + j) = val; } } }
打印棋盘 MinePrint
对棋盘里的值进行打印即可,双重嵌套循环即可。
其中,第一个循环是为了打印显示中的行号。
void MinePrint(char(*arr)[COLS_MAX], int row, int col) { for (int i = 0; i <= col; i++) { printf("%d ", i); } printf("\n"); for (int i = 1; i <= row; i++) { printf("%d ", i); for (int j = 1; j <= col; j++) { printf("%c ", *(*(arr + i) + j)); } printf("\n"); } printf("----------Minesweeper interface-----------\n"); }
设置雷 SetMines
这里用一个随机数即可,需要注意设置雷的条件是之前不是雷才行,重复设置(同一位置)的不算。
void SetMines(char(*arr)[COLS_MAX], int row, int col) { size_t count = 0; while (count < MINE_COUNT) { int x = rand() % 9 + 1; int y = rand() % 9 + 1; if (*(*(arr + x) + y) == '0') { *(*(arr + x) + y) = '1'; count++; } } }
扫雷 ClearMines
扫雷的话要一边展示show信息,一边接收用户输入的行号列号并给出对应的反馈即可。
这里需要注意的是拿到一个位置多少个雷后要用char的形式存入show中,而不是int的形式。
int GetMines(char(*Mine)[COLS_MAX], int x, int y) { return (Mine[x - 1][y - 1] + Mine[x - 1][y] + Mine[x - 1][y + 1] + Mine[x][y - 1] + Mine[x][y + 1] + Mine[x + 1][y - 1] + Mine[x + 1][y] + Mine[x + 1][y + 1] - 8 * '0'); } void ClearMines(char (*Mine)[COLS_MAX], char(*Show)[COLS_MAX], int row, int col) { int sum = ROW_MAX * COL_MAX - MINE_COUNT; int count = 0; while (count < sum) { //MinePrint(Mine, row, col); MinePrint(Show, row, col); printf("Enter the coordinates you want to check\n"); int x = 0, y = 0; scanf("%d%d", &x, &y); if (x >= 1 && y <= 9) { if (Mine[x][y] == '1') { printf("Sorry, you were killed.\n"); printf("Below is the mine layout diagram for this game:\n"); MinePrint(Mine, row, col); //MinePrint(Show, row, col); break; } else { int z_count = GetMines(Mine, x, y); if (Show[x][y] == '*') count++; else printf("This location has been scanned and is invalid.\n"); Sleep(1000); Show[x][y] = z_count + '0'; //MinePrint(Mine, row, col); MinePrint(Show, row, col); } } else { printf("The coordinates you entered are out of bounds\n"); } } if (count == sum) { printf("Congratulations, the mine clearance was successful!!!\n"); } }
4.总结
整体来说,该游戏是用来复习基本语法知识的,比较简单,游戏逻辑清晰明了,功能单一,适合C初学者。
EOF