C语言代码实现简单的扫雷小游戏
一、游戏规则
扫雷是一款经典的单人益智小游戏,游戏场景是一个区块是由许多个格子组成的矩形网格,有一部分格子下面隐藏着地雷,玩家通过揭露不带雷的部分,最终找到所有地雷的位置。
具体游戏规则:
- 鼠标左键点开或标记可疑格子。
- 若点击的是地雷,则游戏结束,显示所有地雷的位置。
- 若点击的是数字,则显示周边8个格子中地雷的数量。
- 若点击的是空格,则显示周边8个格子是否带雷,若为空格则可以扩散一定范围。
- 当所有空格(不带雷的格子)都被打开时,成功过关。
二、代码设计
1. 生成游戏区块
使用二维数组来生成游戏区块,-1表示该位置存在雷,其他数字表示该位置周边8个格子中雷的数量。
int block[ROW][COLUMN]; // 游戏区块
int show[ROW][COLUMN]; // 展示区块
void init_block()
{
int i, j, k;
memset(block, 0, sizeof(block));
memset(show, 0, sizeof(show));
srand((unsigned)time(NULL));
for (k = 0; k < MINE_NUM; k++) { // MINE_NUM 表示雷的数量
i = rand() % ROW;
j = rand() % COLUMN;
if (block[i][j] == -1) {
k--;
continue;
}
block[i][j] = -1;
for (int h = -1; h <= 1; h++) {
for (int w = -1; w <= 1; w++) {
if (i + h >= 0 && i + h < ROW && j + w >= 0 && j + w < COLUMN && block[i+h][j+w] != -1) {
block[i+h][j+w]++;
}
}
}
}
}
2. 游戏的初始化
void init_game() {
int x, y;
init_block(); // 初始化游戏区块
for (y = 0; y < ROW; y++) { // ROW 表示行数
for (x = 0; x < COLUMN; x++) { // COLUMN 表示列数
// 设置每个格子的默认状态为未点击(idx=0),未标记(idx=1)
opened[y][x] = 0;
marked[y][x] = 0;
}
}
}
3. 游戏的主循环
该部分使用SDL库实现,包含初始化、事件循环、图像渲染等多个小模块,需要结合完整代码查看。
while (1) {
// 事件循环
while (SDL_PollEvent(&event)) {
// 处理鼠标事件
switch (event.type) {
case SDL_MOUSEBUTTONDOWN:
if (event.button.button == SDL_BUTTON_LEFT) {
click_left_down(event);
}
else if (event.button.button == SDL_BUTTON_RIGHT) {
click_right_down(event);
}
break;
case SDL_MOUSEBUTTONUP:
if (event.button.button == SDL_BUTTON_LEFT) {
click_left_up(event);
}
else if (event.button.button == SDL_BUTTON_RIGHT) {
click_right_up(event);
}
break;
case SDL_QUIT:
quit();
default:
break;
}
}
// 渲染游戏区块
draw_game();
}
4. 点击事件的处理
void click_left_down(SDL_Event event)
{
int x = event.button.x / CSIZE;
int y = event.button.y / CSIZE;
if (opened[y][x] == 0 && marked[y][x] == 0) {
if (block[y][x] == -1) {
show_all_mines();
printf("Game Over!\n");
game_over = 1;
}
else if (block[y][x] > 0) {
show[y][x] = 1;
opened[y][x] = 1;
}
else {
open_area(y, x);
}
}
}
void click_left_up(SDL_Event event)
{
// do nothing
}
void click_right_down(SDL_Event event)
{
int x = event.button.x / CSIZE;
int y = event.button.y / CSIZE;
if (opened[y][x] == 0) {
marked[y][x] = !marked[y][x];
}
}
void click_right_up(SDL_Event event)
{
// do nothing
}
5. 扩散函数的实现
使用递归实现,对于空白格子,向周围的8个格子扩散。若周围的格子没有地雷,则再次扩散。
void open_area(int y, int x)
{
if (opened[y][x]) {
return;
}
show[y][x] = 1;
opened[y][x] = 1;
if (block[y][x] > 0) {
return;
}
// 扩散
for (int h = -1; h <= 1; h++) {
for (int w = -1; w <= 1; w++) {
if (y + h >= 0 && y + h < ROW && x + w >= 0 && x + w < COLUMN) {
if (block[y+h][x+w] == 0 && !opened[y+h][x+w]) {
open_area(y+h, x+w);
}
else {
show[y+h][x+w] = 1;
opened[y+h][x+w] = 1;
}
}
}
}
}
三、示例说明
示例一
void init_block()
{
int i, j;
memset(block, 0, sizeof(block));
srand((unsigned)time(NULL));
for (i = 0; i < ROW; i++) {
for (j = 0; j < COLUMN; j++) {
// 设置每个格子的默认状态为未点击(idx=0),未标记(idx=1)
opened[y][x] = 0;
marked[y][x] = 0;
if (rand() % (ROW*COLUMN) <= MINE_NUM) { // MINE_NUM 表示雷的数量
block[i][j] = -1;
}
else {
block[i][j] = 0;
}
}
}
}
该部分的修改增加了一定的随机性,不再是预先固定的雷的位置。随着雷的数量的增加,用户的运气也将会对游戏过程产生影响。
示例二
void open_area(int y, int x)
{
if (opened[y][x] || marked[y][x]) {
return;
}
show[y][x] = 1;
opened[y][x] = 1;
if (block[y][x] > 0) {
return;
}
// 扩散
for (int h = -1; h <= 1; h++) {
for (int w = -1; w <= 1; w++) {
if (y + h >= 0 && y + h < ROW && x + w >= 0 && x + w < COLUMN) {
if (block[y+h][x+w] == 0) {
open_area(y+h, x+w);
}
else if (block[y+h][x+w] > 0) {
show[y+h][x+w] = 1;
opened[y+h][x+w] = 1;
}
}
}
}
}
该部分的修改是调整了代码的逻辑结构,将相似的else if语句合并,提高了代码的可读性并减少了重复代码的编写。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言代码实现简单的扫雷小游戏 - Python技术站