C语言——扫雷

扫雷大家应该都应该玩过,这是电脑上一个十分经典的游戏,今天我将给大家讲解如何用C语言来实现扫雷,这个扫雷有如下几个功能:

1.第一次下子,不炸死。
2.坐标周围没雷,可以实现展开。
3.显示该点周围雷的个数。

我们就需要用二维数组来打印棋盘,假如我们要打印10X10的棋盘,那我们的二维数组元素也要为10X10个吗?,不能,因为我们在设计算法时需要统计坐标周围8个方位雷的个数,假如要统计边界坐标周围雷的个数,那么就会有数组越界的问题,那我们就要在10X10的边界多上一圈元素,也就要定义12X12的数组元素

#define ROWS ROW+2
#define COLS COL+2
#define ROW  10
#define COL  10

在这里插入图片描述
1.初始化雷盘,其实这个雷盘只需设计者知道,玩家不必知道。 “ 0 ” 代表没有雷。

void InitMine(char mine[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			mine[i][j] = '0';
		}
	}
}

2.初始化展示的雷盘,这个是展示给玩家看的,雷盘用 “ * ” 覆盖。

void InitShow(char show[ROWS][COLS], int row, int col) 
{
	int i = 0;
	int j = 0;
	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			show[i][j] = '*';
		}
	}
}

3.随机布雷,用 “ 1 ” 表示有雷。

void SetMine(char mine[ROWS][COLS], int row, int col, int count)
{
	while(count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		mine[x][y] = '1';
		count--;
	}
}

4.第一次下子,不炸死,则重新布雷。

void ResetMine(char mine[ROWS][COLS], int row, int col, int x, int y, int count) 
{
	mine[x][y] = '0';
	while(count)
	{
		int i = rand() % row + 1;
        int j = rand() % col + 1;
        if ((mine[i][j] != '1') && i != x && j != y)
		{
			mine[i][j] = '1';
			count--;
		}
	}
}

5.坐标周围没雷,可以实现展开。

void expand(char mine[ROWS][COLS], int x, int y, char show[ROWS][COLS], int *p)
{

    int i = -1;
    int j = -1;
    for (i = -1; i < 2; i++)      //边界
    {
        for (j = -1; j < 2; j++)
        {
            if (i != 0 || j != 0)      // 避免排到自己注意此处的逻辑关系
            {
                if (x + i >= 1 && x + i <= ROW && y + j >= 1 && y + j <= COL)     //x y坐标是否合法
                {
                    if (show[x + i][y + j] == '*'&&mine[x+i][y+j]!='1')
                    {

                        int count = GetMineCount(mine, x + i, y + j);
                        if (count != 0)
                        {
                            show[x + i][y + j] = count + '0';
                            (*p)++;
                        }
                        else
                        {
                            show[x + i][y + j] = ' ';
                            (*p)++;
                            expand(mine, x + i, y + j, show, p);
                        }

                    }

                }
            }
        }
    }


}

6.统计周围雷的个数。

int  GetMineCount(char mine[ROWS][COLS], int i, int j)
{
    return mine[i - 1][j] +
        mine[i - 1][j - 1] +
        mine[i][j - 1] +
        mine[i + 1][j - 1] +
        mine[i + 1][j] +
        mine[i + 1][j + 1] +
        mine[i][j + 1] +
        mine[i - 1][j + 1] - 8 * '0';
}

使用工具: VS 2012
完整代码分为三部分 game.h(函数声明) game.c(实现函数功能) test.c(main函数)

game.h

#ifndef __GAME_H__
#define __GAME_H__

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define ROWS ROW+2
#define COLS COL+2
#define ROW  10
#define COL  10
#define MINECOUNT  10      //布置雷的个数

void menu();  //游戏菜单
void InitMine(char mine[ROWS][COLS], int row, int col);  //初始化雷盘
void InitShow(char show[ROWS][COLS], int row, int col);  //初始化展示的雷盘
void SetMine(char mine[ROWS][COLS], int x, int y, int count);  // 随机布雷
void DisplayBoard(char arr[ROWS][COLS], int row, int col);  // 打印展示雷盘
void ResetMine(char mine[ROWS][COLS], int row, int col);  // 第一次踩到雷,重新布雷
int  GetMineCount(char mine[ROWS][COLS], int i, int j);  //统计雷的个数
void expand(char mine[ROWS][COLS], int x, int y, char show[ROWS][COLS], int *p);  //扩展函数
void PlayGame(char mine[ROWS][COLS], char show[ROWS][COLS]);  // 主逻辑

#endif

game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

void menu()  //游戏菜单
{
	printf("****************************\n");
	printf("****      扫雷游戏      ****\n");
	printf("****     1.开始游戏     ****\n");
	printf("****     0.退出游戏     ****\n");
	printf("****************************\n");
}

void InitMine(char mine[ROWS][COLS], int row, int col) // 初始化雷盘
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			mine[i][j] = '0';
		}
	}
}

void InitShow(char show[ROWS][COLS], int row, int col) //初始化展示的雷盘
{
	int i = 0;
	int j = 0;
	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			show[i][j] = '*';
		}
	}
}

void SetMine(char mine[ROWS][COLS], int row, int col, int count) // 随机布雷
{
	while(count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		mine[x][y] = '1';
		count--;
	}
}

void DisplayBoard(char arr[ROWS][COLS], int row, int col) // 打印展示雷盘
{
	int i = 0;
	int j = 0;
	printf(" ");
	for (i = 0; i <= row; i++)
	{
		printf("%d ",i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%2d",i);
		for (j = 1; j <= col; j++)
		{
			printf(" %c",arr[i][j]);
		}
		printf("\n");
	}
}

void ResetMine(char mine[ROWS][COLS], int row, int col, int x, int y, int count) // 第一次踩到雷,重新布雷
{
	mine[x][y] = '0';
	while(count)
	{
		int i = rand() % row + 1;
        int j = rand() % col + 1;
        if ((mine[i][j] != '1') && i != x && j != y)
		{
			mine[i][j] = '1';
			count--;
		}
	}
}

int  GetMineCount(char mine[ROWS][COLS], int i, int j)   //统计雷的个数
{
    return mine[i - 1][j] +
        mine[i - 1][j - 1] +
        mine[i][j - 1] +
        mine[i + 1][j - 1] +
        mine[i + 1][j] +
        mine[i + 1][j + 1] +
        mine[i][j + 1] +
        mine[i - 1][j + 1] - 8 * '0';
}

void expand(char mine[ROWS][COLS], int x, int y, char show[ROWS][COLS], int *p)    //扩展函数
{

    int i = -1;
    int j = -1;
    for (i = -1; i < 2; i++)      //边界
    {
        for (j = -1; j < 2; j++)
        {
            if (i != 0 || j != 0)      // 避免排到自己注意此处的逻辑关系
            {
                if (x + i >= 1 && x + i <= ROW && y + j >= 1 && y + j <= COL)     //x y坐标是否合法
                {
                    if (show[x + i][y + j] == '*'&&mine[x+i][y+j]!='1')
                    {

                        int count = GetMineCount(mine, x + i, y + j);
                        if (count != 0)
                        {
                            show[x + i][y + j] = count + '0';
                            (*p)++;
                        }
                        else
                        {
                            show[x + i][y + j] = ' ';
                            (*p)++;
                            expand(mine, x + i, y + j, show, p);
                        }

                    }

                }
            }
        }
    }


}

// 主逻辑
void PlayGame(char mine[ROWS][COLS], char show[ROWS][COLS])
{
    int x = 0;
    int y = 0;
    int win = 0;        //统计排雷的个数
    int count = 0;     // 统计雷的个数
    while (win < ROW*COL - count)
    {
        printf("请输入坐标:>");
        scanf("%d %d", &x, &y);
        if (show[x][y] == count + '0')    //避免重复排雷
        {
            printf("已经排过雷\n");
        }
        if (x >= 1 && x <= ROW && y >= 1 && y <= COL)   //输入坐标是否合法
        {
            if (mine[x][y] == '1')
            {
                if (0 == win)      //为了游戏体验,第一次踩到雷,重新布雷
                {
                    ResetMine(mine, ROW, COL, x, y, 1);
                    //display(mine, ROW, COL);
                    count = GetMineCount(mine, x, y);

                    if (count == 0)
                    {
                        show[x][y] = ' ';
                        win++;
                        expand(mine, x, y, show, &win);  //如果周围没有雷,进行扩展
                        DisplayBoard(show, ROW, COL);
                    }
                    else
                    {
                        show[x][y] = count + '0';
                        DisplayBoard(show, ROW, COL);
                    }
                }
                else
                {
                    printf("很遗憾,你被炸死了\n");
                    DisplayBoard(mine, ROW, COL);
                    break;
                }
            }
            else
            {
                count = GetMineCount(mine, x, y);
                if (count == 0)
                {
                    show[x][y] = ' ';
                }
                else
                {
                    show[x][y] = count + '0';
                }
                win++;
                expand(mine, x, y, show, &win);
                DisplayBoard(show, ROW, COL);
                //display(mine, ROW, COL);
            }
        }

        else
        {
            printf("输入坐标不合法\n");
        }

    }
    if (win == ROW*COL - count)
    {
        printf("排雷成功\n");
        DisplayBoard(mine, ROW, COL);
    }
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"

void game()
{
	char mine[ROWS][COLS];                 //扫雷数组
	char show[ROWS][COLS];                 //展示数组
	srand((unsigned int)time(NULL));       //产生随机数
	InitMine(mine, ROWS, COLS);            //初始化的雷盘
	InitShow(show, ROW, COL);              //初始化展示的雷盘
	SetMine(mine, ROW, COL, MINECOUNT);    //随机布雷
	DisplayBoard(show, ROW, COL);          //打印雷盘
	PlayGame(mine, show);                  //主逻辑函数
}

int main()
{
	int input = 0;

	do
	{
		menu();
		printf("请选择是否开始游戏(1/0):>");
		scanf("%d",&input);
		switch(input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("游戏退出!");
			break;
		default:
			printf("输入错误!请重新输入:");
			break;
		}
	}while(input);
	return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 17
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值