**本文是用C语言写的扫雷小游戏———一个C语言前期寓教于乐的小游戏。
🌱博客主页:大寄一场.
🌱系列专栏:C语言学习笔记
😘博客制作不易欢迎各位👍点赞+⭐收藏+➕关注
目录
一.游戏菜单的创建
二.游戏实现的思路
1.初始化雷盘
2.打印雷盘
3.布置雷
4.显示周围雷数
5.标记和取消标记雷
6.周围雷数为零,展开
7.扫雷并判断输赢
完整代码
game.h
game.c
text.c
一.游戏菜单的创建
在我们进入游戏时,首先出现的就应该是我们的菜单界面。
我们选择使用“菜单函数”menu()来实现这一功能,提高程序的可重复性,确保代码块的函数分块使用。
游戏菜单应该实现这几个功能:
- 游戏的进入
- 游戏的退出
接下来是我们实现这一功能的代码:
void menu()
{printf("┌-----------------------------┐\n");printf("├**********1.扫雷*************┤\n");printf("├**********0.退出*************┤\n");printf("└-----------------------------┘\n");
}
menu 2()为小游戏的拓展 方便进行标记雷操作。
void menu2()
{printf("┌-----------------------------┐\n");printf("├**********1.排雷*************┤\n");printf("├**********2.标记*************┤\n");printf("├**********3.取消标记*********┤\n");printf("└-----------------------------┘\n");}
二.游戏实现的思路
测试的逻辑——test.c
游戏的实现——game.h
游戏函数的声明——game.c
1.初始化雷盘
void Init(char board[ROWS][COLS], int rows, int cols, char set)
{int i = 0;for (i = 0; i < rows; i++){int j = 0;for (j = 0; j < cols; j++){board[i][j] = set;}}
}
2.打印雷盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{system("cls");//清屏操作,使界面更简洁printf("---------扫雷----------\n");int i = 0;int j = 0;for (j = 0; j <= col; j++)//打印列{printf("%d ", j);}printf("\n");for (i = 1; i <= row; i++){printf("%d ", i);//打印行for (j = 1; j <= col; j++){printf("%c ", board[i][j]);}printf("\n");}printf("---------扫雷----------\n");
}
3.布置雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{int count = Easy_Count;while (count){int i = rand() % row + 1;int j = rand() % col + 1;if (mine[i][j] == '0'){mine[i][j] = '1';count--;}}
}
4.显示周围雷数
//法一:逐个遍历
static int get_mine_count(char mine[ROWS][COLS], int x, int y)
{return mine[x - 1][y] + mine[x - 1][y - 1] +mine[x - 1][y + 1] + mine[x][y - 1] +mine[x][y + 1] + mine[x + 1][y] +mine[x + 1][y - 1] + mine[x + 1][y + 1] - 8 * '0';
}
//法二:循环遍历
static int get_mine_count2(char mine[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++){if (mine[x + i][y + j] == '1')count++;}}return count;
}
5.标记和取消标记雷
//标记雷
void flag(char show[ROWS][COLS], int row, int col)
{while (1){int x = 0;int y = 0;printf("请输入标记坐标(输入:行 列 退出):>");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 0 && y <= col){if (show[x][y] != '#'){show[x][y] = '#';break;}else{printf("该坐标已经标记,请重新选择\n");}}else{printf("坐标越界,请重新输入\n");}if (x == y && x == 0)break;}
}//取消标记雷
static void cancel_flag(char show[ROWS][COLS], int row, int col)
{while (1){int x = 0;int y = 0;printf("请输入取消标记坐标(输入:0 0退出):>");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 0 && y <= col){if (show[x][y] == '#')//比较用双等号!!!{show[x][y] = '*';break;}else{printf("该坐标还未标记,请重新选择\n");}}else{printf("坐标越界,请重新输入\n");}if (x == y && x == 0)break;}
}
6.周围雷数为零,展开
void Digit_boom(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y, int row, int col, int* win)
{if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标合法性{int ret = get_mine_count2(mine, x, y);//接受坐标周围雷的数量if (ret == 0)//递归条件--周围雷数为0{(*win)++;//每排查一个坐标,排查次数加1,为判断输赢做准备show[x][y] = '0';int i = 0;int j = 0;//用两个循环遍历周围8个坐标for (i = -1; i <= 1; i++){for (j = -1; j <= 1; j++){if (show[x + i][y + j] == '*')//递归的坐标必须是未排查过的坐标,防止死递归{Digit_boom(show, mine, x + i, y + j, row, col, win);}}}}else{//条件不满足退出递归(*win)++;//排查坐标,次数加1show[x][y] = ret + '0';}}}
7.扫雷并判断输赢
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{int choice = -1;int x = 0;int y = 0;int win = 0;while (win < col * row - Easy_Count){/*调用菜单2进行排雷和标记操作*/menu2();printf("请选择:>");scanf("%d", &choice);if (2 == choice) //标记雷{flag(show, ROW, COL);DisplayBoard(show, ROW, COL);}else if (3 == choice)//取消标记雷{cancel_flag(show, ROW, COL);DisplayBoard(show, ROW, COL);}else if (1 == choice)//进行排雷操作{printf("请输入排查坐标:>");scanf("%d%d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (mine[x][y] == '1'){printf("很遗憾,你被炸死了!\n");DisplayBoard(mine, ROW, COL);break;}else if (show[x][y] == '*'){Digit_boom(show, mine, x, y, row, col, &win);//展开雷DisplayBoard(show, row, col);}else/*show[x][y] != '*' */{printf("该坐标已排查,请重新选择\n");}}else{printf("输入坐标错误,请重新输入\n");}}else{printf("坐标非法,重新输入\n");}}if (win == col * row - Easy_Count){printf("恭喜你,排雷成功\n");DisplayBoard(mine, ROW, COL);}
}
完整代码
game.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
//包含头文件
#include <stdio.h>
#include <time.h>
#include<string.h>
#include<windows.h>
#include<stdlib.h>
//宏定义
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define Easy_Count 11
//初始化雷盘
void Init(char board[ROWS][COLS], int rows, int cols, char x);
//打印雷盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);
//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col);
//排雷并判断输赢
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
game.c
#include"game.h"
//初始化雷盘
void Init(char board[ROWS][COLS], int rows, int cols, char set)
{int i = 0;for (i = 0; i < rows; i++){int j = 0;for (j = 0; j < cols; j++){board[i][j] = set;}}
}
//打印雷盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{system("cls");//清屏操作,使界面更简洁printf("---------扫雷----------\n");int i = 0;int j = 0;for (j = 0; j <= col; j++)//打印列{printf("%d ", j);}printf("\n");for (i = 1; i <= row; i++){printf("%d ", i);//打印行for (j = 1; j <= col; j++){printf("%c ", board[i][j]);}printf("\n");}printf("---------扫雷----------\n");
}
//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{int count = Easy_Count;while (count){int i = rand() % row + 1;int j = rand() % col + 1;if (mine[i][j] == '0'){mine[i][j] = '1';count--;}}
}
//显示周围雷数
//法一:逐个遍历
static int get_mine_count(char mine[ROWS][COLS], int x, int y)
{return mine[x - 1][y] + mine[x - 1][y - 1] +mine[x - 1][y + 1] + mine[x][y - 1] +mine[x][y + 1] + mine[x + 1][y] +mine[x + 1][y - 1] + mine[x + 1][y + 1] - 8 * '0';
}
//法二:循环遍历
static int get_mine_count2(char mine[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++){if (mine[x + i][y + j] == '1')count++;}}return count;
}
//标记雷
static void flag(char show[ROWS][COLS], int row, int col)
{while (1){int x = 0;int y = 0;printf("请输入标记坐标(输入:行 列 退出):>");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 0 && y <= col){if (show[x][y] != '#'){show[x][y] = '#';break;}else{printf("该坐标已经标记,请重新选择\n");}}else{printf("坐标越界,请重新输入\n");}if (x == y && x == 0)break;}
}
//取消标记雷
static void cancel_flag(char show[ROWS][COLS], int row, int col)
{while (1){int x = 0;int y = 0;printf("请输入取消标记坐标(输入:0 0退出):>");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 0 && y <= col){if (show[x][y] == '#')//比较用双等号!!!{show[x][y] = '*';break;}else{printf("该坐标还未标记,请重新选择\n");}}else{printf("坐标越界,请重新输入\n");}if (x == y && x == 0)break;}
}
//如果排雷坐标周围雷数为零,递归展开
static void Digit_boom(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y, int row, int col, int* win)
{if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标合法性{int ret = get_mine_count2(mine, x, y);//接受坐标周围雷的数量if (ret == 0)//递归条件--周围雷数为0{(*win)++;//每排查一个坐标,排查次数加1,为判断输赢做准备show[x][y] = '0';int i = 0;int j = 0;//用两个循环遍历周围8个坐标for (i = -1; i <= 1; i++){for (j = -1; j <= 1; j++){if (show[x + i][y + j] == '*')//递归的坐标必须是未排查过的坐标,防止死递归{Digit_boom(show, mine, x + i, y + j, row, col, win);}}}}else{//条件不满足退出递归(*win)++;//排查坐标,次数加1show[x][y] = ret + '0';}}}
//扫雷菜单
static void menu2()
{printf("┌-----------------------------┐\n");printf("├**********1.排雷*************┤\n");printf("├**********2.标记*************┤\n");printf("├**********3.取消标记*********┤\n");printf("└-----------------------------┘\n");}
//扫雷并判断输赢void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{int choice = -1;int x = 0;int y = 0;int win = 0;while (win < col * row - Easy_Count){/*调用菜单2进行排雷和标记操作*/menu2();printf("请选择:>");scanf("%d", &choice);if (2 == choice) /*标记雷*/{flag(show, ROW, COL);DisplayBoard(show, ROW, COL);}else if (3 == choice)/*取消标记雷*/{cancel_flag(show, ROW, COL);DisplayBoard(show, ROW, COL);}else if (1 == choice)/*进行排雷操作*/{printf("请输入排查坐标:>");scanf("%d%d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (mine[x][y] == '1'){printf("很遗憾,你被炸死了!\n");DisplayBoard(mine, ROW, COL);break;}else if (show[x][y] == '*'){Digit_boom(show, mine, x, y, row, col, &win);/*展开*/DisplayBoard(show, row, col);}else/*show[x][y] != '*' */{printf("该坐标已排查,请重新选择\n");}}else{printf("输入坐标错误,请重新输入\n");}}else{printf("坐标非法,重新输入\n");}}if (win == col * row - Easy_Count){printf("恭喜你,排雷成功\n");DisplayBoard(mine, ROW, COL);}
}
text.c
#include"game.h"
//游戏菜单
menu()
{printf("┌-----------------------------┐\n");printf("├**********1.扫雷*************┤\n");printf("├**********0.退出*************┤\n");printf("└-----------------------------┘\n");
}
//扫雷游戏
void game()
{//创建扫雷棋盘char mine[ROWS][COLS];char show[ROWS][COLS];//初始化扫雷棋盘Init(mine, ROWS, COLS, '0');Init(show, ROWS, COLS, '*');//布置雷SetMine(mine, ROW, COL);//打印扫雷棋盘DisplayBoard(show, ROW, COL);//开始扫雷并判断输赢FindMine(mine, show, ROW, COL);
}
void test()
{srand((unsigned int)time(NULL));int input = 0;do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case 1:game();break;case 0:printf("退出游戏\n");break;default:printf("选择错误,重新选择!\n");break;}} while (input);
} /*交互界面*/
int main()
{test();return 0;
}