【C语言】扫雷游戏实现(初阶)

1.扫雷实现步骤

首先先来分析一下扫雷的必须物件
1.棋盘 2.雷 3.坐标九宫格内雷的数量 4.掩盖雷的布
这三样东西都不难搞定,我们可以使用二维数组中不同的元素来模拟雷。但是一个数组的一个位置仅仅可以存储一个数据,我们可以使用 * 字符表示该位置未知,但这样如何存储雷区的数据呢?

为了解决上述问题,我们使用两幅棋盘,第一个棋盘是给玩家看的,使用 * 字符表示该位置没有被翻开过。翻开后显示周围有多少个雷。另外一个棋盘存储雷区信息。哪个地方有雷使用1字符标出,0字符表示无雷

但是如果处在数组边界,九宫格就很难统计,需要将边界,边角等分开统计。所以在实际操作过程中,让棋盘扩大一圈,在mine(雷棋盘)中将所有外圈都设置为零。然后所有有效棋盘的格子都有自己的九宫格了

1.1游戏菜单

void Menu()
  4 {
  5   printf("\n");
  6   printf("welcome to the three chess game\n");
  7   printf("-------------------------------\n");
  8   printf("----1.Start         2.out------\n");
  9   printf("-------------------------------\n");
 10   printf("\n");
 11 }

1.2初始化棋盘

void InitBoard(char board[ROWS][COLS], size_t row, size_t col, char ch)
 14 {
 15   for (size_t i = 0; i < row; i++)
 16   {
 17     for (size_t j = 0; j < col; j++)
 18     {
 19       board[i][j] = ch;
 20     }
 21   }
 22 }

将数组中所有的元素都设置成同一个字符ch,show为玩家棋盘(数组)’*‘表示未被翻开,数字代表九宫格内雷的数量。mine为后台棋盘(数组),0代表没有雷,1代表有雷

1.3打印棋盘

 void DisplayBoard(char board[ROWS][COLS])
 24 {
 25   printf("  ");
 26   for(size_t i = 1; i <= COL; i++)
 27   {
 28     printf(" %lu ", i);
 29   }
 30   printf("\n");
 31   for (size_t i = 1; i <= ROW; i++)
 32   {
 33     printf("%lu ", i);
 34     for (size_t j = 1; j <= COL; j++)
 35     {
 36       printf(" %c ", board[i][j] );
 37     }
 38     printf("\n");
 39   }
 40   printf("\n\n");                                                                                                                                                                   
 41 }

最外圈打印编号,直接遍历数组获得棋盘

1.4设置雷

void SetMine(char board[ROWS][COLS])
 43 {
 44   size_t count = BOMB_COUNT;
 45   while (count)
 46   {
 47     size_t row = rand() % ROW + 1;
 48     size_t col = rand() % COL + 1;
 49     if (board[row][col] == '0')  //无雷放雷,有雷不进去继续随机
 50     {
 51       board[row][col] = '1';
 52       count--;                
 53     }
 54 
 55   }
 56 }

使用随机函数在无雷区设置雷,通过BOMB_COUNT的大小来控制雷的数量

1.5排雷

size_t get_mine_count(char mine[ROWS][COLS], size_t x, size_t  y)
 95 {
 96   size_t count = 0; //计数器
 97   for (size_t i = x -1; i <= x + 1; i++)
 98   {
 99     for (size_t j = y - 1; j <= y + 1; j++)
100     {
101       if (mine[i][j] == '1')
102       {
103         count++;   //有雷+1
104       } 
105     }
106   }
107   return count;
108 }

在我们排雷过程中,点下一个未知的格子要么有雷爆炸了,要么显示该格子周围雷的数量。这个函数就是统计周围雷的数量的。使用一个计数器遍历九宫格,就可以得到雷的数量了

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS])
 58 {
 59   size_t x, y;
 60   size_t count = ROW * COL - BOMB_COUNT; //表示非雷区域的数量
 61   while (1)
 62   {
 63     printf("请输入坐标(x,y)并用空格分开:>");
 64     scanf("%lu%lu", &x, &y);
 65     if (x >= 1 && x <= ROW && y >= 1 && y <= COL)//检验坐标合法
 66     {
 67       if (mine[x][y] == '1')
 68       {
 69         DisplayBoard(mine);
 70         printf("踩到雷了,你输了\n"); //若踩到雷直接结束游戏,并且公布雷区(mine)的信息
 71         break;
 72       }
 73       else 
 74       {
 75         show[x][y] = get_mine_count(mine, x, y) + '0'; //没踩到雷,公布周围雷的数量                                                                                                                            
 76         DisplayBoard(show);
 77         count--;  //非雷区域被探清了一个,计数器减少1
 78       }
 79     }
 80     else 
 81     {
 82       printf("输入错误坐标,请重新输入\n");
 83     }
 84     if (count == 0) //当所有非雷区被探完,获得胜利
 85     {
 86       printf("恭喜你,你赢了\n");
 87       DisplayBoard(mine);
 88       break;
 89     }
 90   }
 91 
 90
 93 }

1.6游戏实现

void game()
{
  char mine[ROWS][COLS];
  char show[ROWS][COLS];
  Menu();
  InitBoard(mine, ROWS, COLS, '0');
  InitBoard(show, ROWS, COLS, '*');
  SetMine(mine);
  DisplayBoard(show);
  FindMine(mine, show);

}
void game_test()
{
  size_t chess;
  do 
  {
    Menu();
    printf("请输入 1进入游戏 0退出游戏:>");
    scanf("%lu", &chess);
    switch(chess)
    {
      case 1:
            {
             game();
             break;
            }
      case 0:
           {
             printf("退出游戏\n");
             break;
           }
    default:
           {
             printf("输入非法,请重新输入\n");
             break;
           }

    }
}while(chess);


}

int main()
{
  srand((unsigned int)time(NULL)); //rand()函数使用前提
  game_test(); 
  return 0;
}

调用了上面构造的函数,构造一个小的循环体来打印菜单退出游戏等。比较简单就不赘述了。
注意: srand((unsigned int)time(NULL));要在main函数中写进去。不然rand函数无法使用

2.扫雷源码

2.1Makefile

test:test.o game.o
		gcc -o $@ $^ -std=c99
test.o:test.c
		gcc -c $< -std=c99 
game.o:game.c
		gcc -c $< -std=c99
.PHONY:clean
clean:
		rm -f ./*.o test

2.2game.h

#pragma once 
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define BOMB_COUNT 10

void Menu();
void InitBoard(char board[ROWS][COLS], size_t row, size_t col, char ch);
void DisplayBoard(char board[ROWS][COLS]);
void SetMine(char board[ROWS][COLS]);
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS]);
size_t get_mine_count(char mine[ROWS][COLS], size_t x, size_t  y);

2.3game.c

void Menu()
{
  printf("\n");
  printf("welcome to the three chess game\n");
  printf("-------------------------------\n");
  printf("----1.Start         2.out------\n");
  printf("-------------------------------\n");
  printf("\n");
}

void InitBoard(char board[ROWS][COLS], size_t row, size_t col, char ch)
{
  for (size_t i = 0; i < row; i++)
  {
    for (size_t j = 0; j < col; j++)
    {
      board[i][j] = ch;
    }
  }
}
void DisplayBoard(char board[ROWS][COLS])
{
  printf("  ");
  for(size_t i = 1; i <= COL; i++)
  {
    printf(" %lu ", i);
  }
  printf("\n");
  for (size_t i = 1; i <= ROW; i++)
  {
    printf("%lu ", i);
    for (size_t j = 1; j <= COL; j++)
    {
      printf(" %c ", board[i][j] );
    }
    printf("\n");
  }
  printf("\n\n");
}
void SetMine(char board[ROWS][COLS])
{
  size_t count = BOMB_COUNT; 
  while (count)
  {
    size_t row = rand() % ROW + 1;
    size_t col = rand() % COL + 1;
    if (board[row][col] == '0')
    {
      board[row][col] = '1';
      count--;
    }

  }
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS])
{
  size_t x, y;
  size_t count = ROW * COL - BOMB_COUNT;
  while (1)
  {
    printf("请输入坐标(x,y)并用空格分开:>");
    scanf("%lu%lu", &x, &y);
    if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
    {
      if (mine[x][y] == '1')
      {
        DisplayBoard(mine);
        printf("踩到雷了,你输了\n");
        break;
      }
      else 
      {
        show[x][y] = get_mine_count(mine, x, y) + '0';
        DisplayBoard(show);
        count--;
      }
    }
    else 
    {
      printf("输入错误坐标,请重新输入\n");
    }
    if (count == 0)
    {
      printf("恭喜你,你赢了\n");
      DisplayBoard(mine);
      break;
    }
  }


}
size_t get_mine_count(char mine[ROWS][COLS], size_t x, size_t  y)
{
  size_t count = 0;
  for (size_t i = x -1; i <= x + 1; i++)
  {
    for (size_t j = y - 1; j <= y + 1; j++)
    {
      if (mine[i][j] == '1')
      {
        count++;
      }
    }
  }
  return count;
}

2.4test.c

#include "game.h"

void game()
{
  char mine[ROWS][COLS];
  char show[ROWS][COLS];
  Menu();
  InitBoard(mine, ROWS, COLS, '0');
  InitBoard(show, ROWS, COLS, '*');
  SetMine(mine);
  DisplayBoard(show);
  FindMine(mine, show);

}
void game_test()
{
  size_t chess;
  do 
  {
    Menu();
    printf("请输入 1进入游戏 0退出游戏:>");
    scanf("%lu", &chess);
    switch(chess)
    {
      case 1:
            {
             game();
             break;
            }
      case 0:
           {
             printf("退出游戏\n");
             break;
           }
    default:
           {
             printf("输入非法,请重新输入\n");
             break;
           }

    }
}while(chess);


}

int main()
{
  srand((unsigned int)time(NULL));
  game_test(); 
  return 0;
}

【小结】

这个扫雷游戏还是比较简陋,还存在比较多的缺陷,如:
1.无法展开一片无雷区域
2.无法主动插旗标记雷点
可能以后会慢慢完善。感谢观看。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
C语言扫雷游戏排行榜是一个用于记录玩家在扫雷游戏中的得分和排名的榜单。在C语言中,我们可以使用数组和结构体来实现这个排行榜。 首先,我们可以创建一个结构体来表示每个玩家的信息,如玩家的姓名和得分。结构体的定义可以像这样: ``` struct Player { char name[20]; int score; }; ``` 然后,我们创建一个数组来存储多个玩家的信息,数组的大小可以根据需要进行调整。例如: ``` struct Player leaderboard[10]; ``` 接下来,我们可以编写函数来实现对排行榜的操作,如添加玩家、更新得分和显示排行榜等。 添加玩家的函数可以接受玩家的姓名和得分,并将其添加到排行榜中。例如: ``` void addPlayer(char name[20], int score) { // 找到排行榜中得分低于当前得分的位置,并将其后的玩家信息依次后移一位 // 将当前玩家信息插入到空出的位置 } ``` 更新得分的函数可以接受玩家的姓名和新得分,并根据姓名找到对应的玩家并更新其得分。例如: ``` void updateScore(char name[20], int newScore) { // 根据姓名找到对应的玩家,并更新其得分 } ``` 最后,我们可以编写显示排行榜的函数,按照得分从高到低的顺序显示玩家信息。例如: ``` void showLeaderboard() { // 对排行榜中的玩家根据得分进行排序,并输出玩家信息 } ``` 以上是用C语言实现扫雷游戏排行榜的基本思路,具体的实现细节可以根据实际需求进行调整和完善。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白在进击

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值