1.游戏设计与分析
1.1 扫雷游戏的功能说明
使⽤控制台实现经典的扫雷游戏。
游戏可以通过菜单实现继续玩或者退出游戏。
扫雷的棋盘是n*n的格⼦ • 默认随机布置m个雷。
可以排查雷 ◦
1.2 游戏结束条件
如果位置不是雷,就显⽰周围有⼏个雷 ◦ 如果位置是雷,就炸死游戏结束 ◦
把除m个雷之外的所有雷都找出来,排雷成功,游戏结束。
2.程序设计
第一步:定义游戏的基本参数
首先,定义游戏板的大小、地雷的数量等基本参数。这些可以作为全局变量或通过命令行参数传入。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_ROWS 20
#define MAX_COLS 20
int rows, cols, mines;
int mineBoard[MAX_ROWS][MAX_COLS];
int revealedBoard[MAX_ROWS][MAX_COLS];
int gameOver = 0;
第二步:初始化游戏板
编写一个函数来初始化游戏板,包括随机放置地雷和计算每个非地雷格子周围的地雷数量。
void initializeBoard() {
// 初始化地雷板
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
mineBoard[i][j] = 0; // 0表示无雷
revealedBoard[i][j] = 0; // 0表示未揭示
}
}
// 放置地雷
srand(time(NULL));
int count = 0;
while (count < mines) {
int row = rand() % rows;
int col = rand() % cols;
if (mineBoard[row][col] == 0) {
mineBoard[row][col] = 1;
count++;
}
}
// 计算每个格子周围的地雷数
// (此部分代码略,作为练习)
}
注意:上面的initializeBoard函数只初始化了地雷板,并没有计算每个格子周围的地雷数。需要添加额外的逻辑来完成这部分。
第三步:揭示格子
编写一个函数来揭示玩家选择的格子,并根据需要显示地雷、数字或空白。
void revealTile(int x, int y) {
if (x < 0 || x >= rows || y < 0 || y >= cols || revealedBoard[x][y] || mineBoard[x][y] == 1) {
if (mineBoard[x][y] == 1) {
gameOver = 1;
printf("Game Over! You hit a mine at (%d, %d).\n", x+1, y+1); // 假设用户输入从1开始
}
return;
}
revealedBoard[x][y] = 1;
// 这里需要根据mineBoard[x][y]的值来决定显示什么
// 如果mineBoard[x][y]是0,则需要计算并显示周围的地雷数
// 如果不是0,则直接显示'X'表示地雷(但通常不会在这里显示,因为已经gameOver了)
// 这里只是示意,具体实现略
}
第四步:处理用户输入
在main函数中,需要循环处理用户的输入,直到游戏结束。
int main() { // 初始化rows, cols, mines(这里可以通过命令行参数传入,或者硬编码) rows = 10; cols = 10; mines = 20; initializeBoard(); // 初始化游戏板 int x, y; while (!gameOver) { printf("Enter row and column to reveal (e.g., 3 4): "); scanf("%d %d", &x, &y); x--; y--; // 转换为从0开始的索引 revealTile(x, y); // 可以在这里添加打印游戏板的逻辑 } return 0; }第五步:整合修改,调试运行
#include <stdio.h> #include <stdlib.h> #include <time.h> #define MAX_ROWS 10 #define MAX_COLS 10 #define EMPTY_CELL 0 #define MINE_CELL 1 #define REVEALED_CELL 2 int rows = MAX_ROWS, cols = MAX_COLS, mines = 20; int mineBoard[MAX_ROWS][MAX_COLS]; int revealedBoard[MAX_ROWS][MAX_COLS]; int gameOver = 0; int gameWon = 0; // 辅助函数:计算并返回给定格子周围的地雷数 int countMinesAround(int x, int y) { int count = 0; for (int dx = -1; dx <= 1; dx++) { for (int dy = -1; dy <= 1; dy++) { int nx = x + dx, ny = y + dy; if (nx >= 0 && nx < rows && ny >= 0 && ny < cols && mineBoard[nx][ny] == MINE_CELL) { count++; } } } return count; } // 初始化游戏板 void initializeBoard() { // ...(与之前相同,但省略了计算周围地雷数的部分) // 现在计算每个格子周围的地雷数 for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { if (mineBoard[i][j] == EMPTY_CELL) { revealedBoard[i][j] = countMinesAround(i, j); } } } } // 揭示格子,包括自动展开周围安全的格子(可选) void revealTile(int x, int y, int autoExpand) { if (x < 0 || x >= rows || y < 0 || y >= cols || revealedBoard[x][y] != EMPTY_CELL) { if (mineBoard[x][y] == MINE_CELL) { gameOver = 1; printf("Game Over! You hit a mine at (%d, %d).\n", x+1, y+1); } return; } revealedBoard[x][y] = REVEALED_CELL; if (mineBoard[x][y] == MINE_CELL) { gameOver = 1; return; } if (autoExpand && revealedBoard[x][y] == 0) { // 自动展开周围安全的格子 for (int dx = -1; dx <= 1; dx++) { for (int dy = -1; dy <= 1; dy++) { int nx = x + dx, ny = y + dy; if (nx >= 0 && nx < rows && ny >= 0 && ny < cols && revealedBoard[nx][ny] == EMPTY_CELL) { revealTile(nx, ny, 1); // 递归展开 } } } } // 检查游戏是否胜利 int safeTiles = 0; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { if (revealedBoard[i][j] == REVEALED_CELL) { safeTiles++; } } } if (safeTiles + mines == rows * cols) { gameWon = 1; printf("Congratulations! You've won the game!\n"); } } int main() { // ...(与之前相同,但省略了部分细节) initializeBoard(); int x, y; while (!gameOver && !gameWon) { printf("Enter row and column to reveal (e.g., 3 4), or type 'exit' to quit: "); if (scanf("%d %d", &x, &y) != 2)另一种实现方式
头文件
game.h
//写游戏需要的数据类型和函数声明等#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> #include<Windows.h> #include<time.h> #define ROW 9 #define COL 9 #define ROWS ROW+2//扩展雷区 #define COLS COL+2//扩展雷区 #define BOMBNUM 10//炸弹数量 //菜单打印 void GameMenu(); //游戏页面主体 void MainGame(); void Game(); //棋盘初始化和打印 void BoardInit(char Board[ROWS][COLS], char a); void BoardPrint(char Board[ROWS][COLS]); //放雷 void PutBomb(char Board[ROWS][COLS]); //正式游戏开始 int GameBegain(char realboard[ROWS][COLS], char showboard[ROWS][COLS], int x, int y); //连锁扫雷 void ChainFindBomb(char realboard[ROWS][COLS], char showboard[ROWS][COLS], int x, int y); //周围雷区查找 void SroundFind(char RealBoard[ROWS][COLS], char ShowBoard[ROWS][COLS], int x, int y); //标记雷 void MarkBomb(char showboard[ROWS][COLS], char realboard[ROWS][COLS], int* cou); //取消标记雷 void DisMarkBomb(char showboard[ROWS][COLS], char realboard[ROWS][COLS], int* cou);源文件
game.c
//游戏中函数的实现
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//菜单打印
void GameMenu()
{
printf("扫雷游戏\n");
printf("1.进入游戏\n");
printf("0.退出游戏\n");
}
//扫雷游戏主体
void Game()
{
char ShowBoard[ROWS][COLS];
char RealBoard[ROWS][COLS];
char n = '*', m = '0';
BoardInit(ShowBoard, n);
BoardInit(RealBoard, m);
PutBomb(RealBoard);
//BoardPrint(RealBoard);
BoardPrint(ShowBoard);
int flag = 1;
int count = 0;
while (flag)
{
int x, y;
printf("请输入要排查的坐标:"); scanf("%d %d", &x, &y);
if (x > ROW || x < 1 || y>COL || y < 1) {
printf("输入错误,请重新输入!");
continue;
}
flag = GameBegain(RealBoard, ShowBoard, x, y);
if (flag)
{
SroundFind(RealBoard, ShowBoard, x, y);
system("cls"); BoardPrint(ShowBoard);
//BoardPrint(RealBoard);
while (1) {
int n;
printf("是否需要标记雷(输入1(是),0(否)):"); scanf("%d", &n);
if (n == 0)break;
else if (n == 1) {
MarkBomb(ShowBoard, RealBoard, &count);
system("cls");
BoardPrint(ShowBoard);
}
else printf("非法输入!\n");
}
while (1) {
int n;
printf("是否需要取消标记雷(输入1(是),0(否)):"); scanf("%d", &n);
if (n == 0)break;
else if (n == 1) {
DisMarkBomb(ShowBoard, RealBoard, &count);
system("cls");
BoardPrint(ShowBoard);
}
else printf("非法输入!\n");
}
system("cls"); BoardPrint(ShowBoard);
}
if (count == BOMBNUM) {
printf("恭喜你找出了所有的雷,排雷成功!\n");
system("pause");
system("cls");
break;
}
}
}
//棋盘初始化和打印
void BoardInit(char Board[ROWS][COLS], char a)
{
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
Board[i][j] = a;
}
}
void BoardPrint(char Board[ROWS][COLS])
{
for (int i = 0; i <= ROW; i++)
printf("%d ", i);
printf("x轴\n");
for (int i = 1; i <= ROW; i++)
{
printf("%d ", i);
for (int j = 1; j <= COL; j++)
printf("%c ", Board[j][i]);
printf("\n");
}
printf("y轴\n");
}
//放雷
void PutBomb(char Board[ROWS][COLS])
{
int count = BOMBNUM;
while (count)
{
int x = rand() % 9 + 1;
int y = rand() % 9 + 1;
if (Board[x][y] == '0') {
Board[x][y] = '1';
count--;
}
}
}
//正式游戏开始
int GameBegain(char realboard[ROWS][COLS], char showboard[ROWS][COLS], int x, int y)
{
//printf("%c %d %d", realboard[x][y],x,y);
if (realboard[x][y] == '1') {
system("cls");
printf("你被炸死了!!\n");
BoardPrint(realboard);
system("pause"); system("cls");
return 0;
}
else
{
showboard[x][y] = (realboard[x - 1][y - 1] - '0') + (realboard[x - 1][y] - '0') + (realboard[x - 1][y + 1] - '0') + (realboard[x][y - 1] - '0') + (realboard[x][y + 1] - '0') + (realboard[x + 1][y - 1] - '0') + (realboard[x + 1][y] - '0') + (realboard[x + 1][y + 1]);
return 1;
}
}
void ChainFindBomb(char realboard[ROWS][COLS], char showboard[ROWS][COLS], int x, int y)
{
if (realboard[x][y] != '1' && 1 <= x && x <= ROW && 1 <= y && y <= COL) {
char a = (realboard[x - 1][y - 1] - '0') + (realboard[x - 1][y] - '0') + (realboard[x - 1][y + 1] - '0') + (realboard[x][y - 1] - '0') + (realboard[x][y + 1] - '0') + (realboard[x + 1][y - 1] - '0') + (realboard[x + 1][y] - '0') + (realboard[x + 1][y + 1]);
if (a == '0' || a == '1') {
if (showboard[x][y] != '*' || showboard[x][y] == '+') {
return;
}
showboard[x][y] = a;
SroundFind(realboard, showboard, x, y);
}
else return;
}
}
void SroundFind(char RealBoard[ROWS][COLS], char ShowBoard[ROWS][COLS], int x, int y) {
ChainFindBomb(RealBoard, ShowBoard, x - 1, y - 1);
ChainFindBomb(RealBoard, ShowBoard, x - 1, y);
ChainFindBomb(RealBoard, ShowBoard, x - 1, y + 1);
ChainFindBomb(RealBoard, ShowBoard, x, y - 1);
ChainFindBomb(RealBoard, ShowBoard, x, y + 1);
ChainFindBomb(RealBoard, ShowBoard, x + 1, y - 1);
ChainFindBomb(RealBoard, ShowBoard, x + 1, y);
ChainFindBomb(RealBoard, ShowBoard, x + 1, y + 1);
}
//标记雷
void MarkBomb(char showboard[ROWS][COLS], char realboard[ROWS][COLS], int* cou)
{
int x, y;
printf("请输入要标记的坐标:"); scanf("%d %d", &x, &y);
if (x > ROW || x < 1 || y>COL || y < 1 || showboard[x][y] != '*') {
printf("非法输入!\n"); return;
}
showboard[x][y] = '+';
if (realboard[x][y] == '1')
*cou += 1;
}
//取消标记雷
void DisMarkBomb(char showboard[ROWS][COLS], char realboard[ROWS][COLS], int* cou)
{
int x, y;
printf("请输入要标记的坐标:"); scanf("%d %d", &x, &y);
if (x > ROW || x < 1 || y>COL || y < 1 || showboard[x][y] != '+') {
printf("非法输入!\n"); return;
}
showboard[x][y] = '*';
if (realboard[x][y] == '1')
*cou -= 1;
}
test.c
//运行逻辑,便于测试修改。
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
int main()
{
srand((unsigned int)time(NULL));
while (1) {
GameMenu();
int n;
printf("请输入你的选择:");
scanf("%d", &n);
switch (n) {
case 0:
break;
case 1:
system("cls");
printf("进入游戏\n");
printf("游戏规则:\n");
printf("1.输入要排查雷的坐标\n");
printf("2.通过标记雷来完成游戏,标记够数且标记对即可获得胜利\n");
printf("3.扫出的数字为周围雷的数量\n");
system("pause");
system("cls");
Game();
break;
default:
system("cls");
printf("输入错误,请重输入!\n");
system("pause");
system("cls");
break;
}
}
return 0;
}
1086

被折叠的 条评论
为什么被折叠?



