C语言编写简单扫雷游戏

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;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值