整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          C語言開發:一篇文章帶你還原童年,掃雷游戲完整源碼分

          C語言開發:一篇文章帶你還原童年,掃雷游戲完整源碼分析

          必屏幕前的你,肯定玩過windows系統自帶的那個游戲,掃雷

          回想當年,我根本沒看懂這個游戲是怎么玩的

          比起掃雷,三維彈球對我更有吸引力

          跑題了

          本篇博客就讓我們一起來試試,如何通過C語言代碼,制作出一個“掃雷游戲se”

          1.游戲程序主函數

          在編寫這類游戲代碼時,我們要用到的主函數基本是一致的

          掃雷游戲的主函數和猜數字游戲的主函數相差很小

          void menu()//簡易目錄
          {
            printf("***************************\n");
            printf("**** 1. play   0. exit*****\n");
            printf("***************************\n");
          }
          
          int main()
          {
            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);
            return 0;
          }?

          2.游戲實現原理

          想寫好一串代碼,首先我們要知道掃雷游戲需要通過什么方式來實現

          我們需要一個9x9的棋盤,用于生成我們的雷以及玩家的游玩

          在c語言中當然無法直接產生這樣的畫面

          但我們可以同符號*或者#來代替網格,用1和0來表示有無雷

          如果我們只生成一個棋盤,那1和0會直接顯示出來,達不到隱藏的效果

          所以我們需要用二維數組生成兩個棋盤,一個用于存放雷,一個用于玩家的游玩

          	char mine[ROWS][COLS];//雷區布置
          	char show[ROWS][COLS];//玩家看到的界面 

          掃雷游戲我們使用頭文件+源文件的形式撰寫代碼

          這樣寫代碼的優點在于后續我們可以直接通過更改.h文件中的數組,從而更改我們的格子大小

          如: 改成12x12的游玩界面,改變雷區布雷個數等等

          所以我們需要在game.h中定義這些符號

          #include <stdio.h>
          #include <stdlib.h>
          #include <time.h>
          
          #define ROW 9
          #define COL 9
          
          #define ROWS ROW+2
          #define COLS COL+2

          同時我們要在主函數的最上面引用這個自己寫的頭文件

          只要把庫函數頭文件放入game.h文件,在其他源文件中只需引用game.h

          不需要再次引用<stdio.h>、<stdlib.h>之類

          #include 'game.h'

          棋盤大小為什么需要11x11?

          你可能注意到了,在生成數組的時候,我使用了ROWS,其值為ROW+2

          我們最終展示的只是9x9的游戲界面,但生成的棋盤其實是11x11的

          這是因為我們需要在mine數組中實現掃描雷區的操作

          玩過掃雷游戲的你肯定知道:在你點擊一個格子的時候,如果這個格子不是雷

          它會顯示一個數字,告訴你它周圍的8個格子中有幾顆雷

          如圖所示:

          在C語言中,我們可以用函數統計周圍8個格子中雷’1’的個數

          但是如果你來到邊緣,那就出現問題了

          如果我們想統計邊緣的格子周邊有幾顆雷,就會遇到這種溢出數組的情況

          此時代碼會報錯

          為了避免這個問題,我們可以在原來9x9的基礎上在周圍加一圈空白的格子

          也就是代碼所示的ROW(行)COL(列)都要+2的情況

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

          游戲過程

          這里簡單梳理一下我們的游戲過程

          (1)玩家選擇開始游戲

          (2)生成兩個棋盤,一個放置雷\掃描雷,一個向玩家展示游戲界面

          (3)玩家輸入坐標,選擇排雷位置

          (4)有雷–>玩家被炸死,游戲結束;無雷–>顯示周邊有幾顆雷,游戲繼續

          (5)所有雷被排出,游戲勝利


          3.游戲代碼實現

          接下來就進入我們的游戲代碼部分

          3-1.初始化和打印

          	//初始化掃雷
          	InitBoard(mine, ROWS, COLS, '0');
          	InitBoard(show, ROWS, COLS, '*');
          
          	//打印掃雷
          	DisplayBoard(mine, ROW, COL);
          	DisplayBoard(show, ROW, COL); 

          我們需要初始化兩個棋盤,其中雷區初始化為0(0代表無雷),展示區初始化為’*’,用?代替界面

          同時我們打印這兩個棋盤,查看初始化效果

          因為這是我們的自定義函數,所以需要在.h文件中定義函數,在另外一個.c文件中包含函數的實現

          //初始化棋盤
          void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
          //打印
          void DisplayBoard(char board[ROWS][COLS], int row, int col);

          初始化函數和打印函數比較簡單,使用for語句達成我們的需求

          void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
          {
          	int i=0;
          	int j=0;
          	for (i=0; i < rows; i++)
          	{
          		for (j=0; j < cols; j++)
          		{
          			board[i][j]=set;
          		}
          	}
          }
          
          void DisplayBoard(char board[ROWS][COLS], int row, int col)
          {
          	int i=0;
          	int j=0;
          	printf("------掃雷游戲------\n");
          	//打印列號
          	for (i=0; i <=col; i++)
          	{
          		printf("%d ", i);
          	}
          	printf("\n");
          	for (i=1; i <=row; i++)//只打印中心的99方格
          	{
          		printf("%d ", i);//打印行號
          		for (j=1; j <=col; j++)//只打印中心的99方格
          		{
          			printf("%c ", board[i][j]);
          		}
          		printf("\n");
          	}
          	printf("--------------------\n");
          }

          需要注意的是我們的最后打印棋盤的時候是從i=1開始的,這樣就能避開添加的空白邊緣區域,只打印中心的99方格

          同時我們添加了列號和行號,這樣能讓玩家清除的知道自己應該輸入什么坐標

          3-2.布置雷區

          	//布置雷
          	SetMine(mine, ROW, COL); 

          同樣的,我們需要在game.h中定義這個函數

          //布置地雷
          void SetMine(char mine[ROWS][COLS], int row, int col);

          在game.c中寫入自定義函數的實現

          //放置雷
          void SetMine(char  mine[ROWS][COLS], int row, int col)
          {
            int count=EASY_COUNT;
            while (count)
            {
              int x=rand() % row + 1;
              int y=rand() % col + 1;
              if (mine[x][y]=='0')
              {
                mine[x][y]='1';
                count--;
              }
            }
          }?

          這里面出現了一個前面沒有提到的變量,EASY_COUNT

          本來這個位置只是個10

          但如果我們想更改布雷個數,那每次都需要更改這里的10,后面的代碼中也需要更改,非常麻煩

          所以我們改為使用一個自定義變量,在game.h中定義這個變量的值

          #define EASY_COUNT 10

          這個值就代表我們布置雷的個數了

          3-3.玩家排查雷

          //在主函數中引用這個函數
          	FindMine(mine,show, ROW, COL);//需要把mine數組中排查的雷放入show
          
          //在game.h中定義這個函數
          void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS],int row, int col);

          因為我們需要把mine數組中排查出的雷的個數放入show數組中打印出來

          所以這里我們需要把兩個數組都傳送過去

          1.輸入排查的坐標

          2.檢查坐標處是不是雷

          ·是雷 -boom!炸死 -游戲結束

          ·不是雷 -統計坐標周圍有幾個雷-存儲排雷的信息到show數組,游戲繼續

          void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
          {
            int x=0;
            int y=0;
              
            while (1)
            {
              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
                {
                  //不是雷的情況下,統計坐標周圍有幾個雷
                  int count=get_mine_count(mine, x, y);
                  show[x][y]=count + '0';
                }
              }
              else
              {
                printf("坐標錯誤,請重新輸入 \n");
              }
            }
          }

          注意,這里面我們需要添加一個代碼來判斷坐標合法性

          我們的棋盤是9x9,玩家要是輸入一個(99,99)的坐標,那肯定不在數組中的,是無效的

          我們需要提醒玩家他輸錯了

          ‘0’的作用

          show[x][y]=count + '0';

          你可能會對這行代碼感到疑惑

          為什么要在count后面+上一個‘0’?

          這里就和我們ascii碼表有關了

          因為我們初始化數組和布置雷的時候,我們給數組傳入的都是1和0這兩個符號,并不是數字!

          但是在show數組中我們需要給玩家顯示一個數字的字符

          這里面我們提供的是1的字符,并不是1它本身

          而我們在計算周邊雷的個數的時候,傳回來的是一個具體的數字

          觀察表格,你會發現數字和對應的字符中間,都差了48

          而48恰好是字符’0’對應的ASCII碼值

          所以我們需要用count加上字符’0’,以此在界面中向玩家展示周邊8格有幾顆雷

          3-4. 系統掃描雷

          如何把玩家選擇的格子周邊的雷掃描出來呢?

          設玩家的選擇的坐標為x和y

          我們只需要把這些坐標全部在二維數組中鍵入,就能逐個掃描出雷的個數

          //統計雷的個數
          static int get_mine_count(char mine[ROWS][COLS], int x, int y)
          {
            return mine[x - 1][y - 1] +
              mine[x - 1][y] +
              mine[x - 1][y + 1] +
              mine[x][y - 1] +
              mine[x][y + 1] +
              mine[x + 1][y - 1] +
              mine[x + 1][y] +
              mine[x + 1][y + 1] - 8 * '0';
          }

          這里因為我們掃描出來的也是‘1’的字符,系統中是字符1的ascii碼值49

          所以我們需要減去8個字符‘0’,這樣就能得到雷的個數的數字

          (然后在之前的那個函數中接受,count+‘0’,在show數組中顯示)

          這個函數是在玩家排查雷的函數之前的

          因為在主函數中我們不需要使用這個自定義函數,所以不需要在game.h中定義

          我們想讓它只在game.c中生效,所以用static修飾它

          static的作用

          1.修飾局部變量

          2.修飾全局變量

          3.修飾函數

          上面的代碼其實還少了一個東西

          我們需要判斷玩家什么時候勝利——雷區的0(無雷方塊)全部被玩家找出,玩家就勝利了

          	int win=0;
          	while (win< row * col - EASY_COUNT) 

          這里我們需要更改的是whlie函數

          其中 row * col - EASY_COUNT 指方格總數減去雷的個數,得到的是無雷方塊的個數

          玩家每成功排除一個無雷方塊,win就會加一個數字

          	else
          	{
          		//不是雷的情況下,統計坐標周圍有幾個雷
          		int count=get_mine_count(mine, x, y);
          		show[x][y]=count + '0';
          		//顯示排查出來的信息
          		DisplayBoard(show, ROW, COL);
                  win++;
          	} 

          當win達到無雷方塊個數的時候,whlie循環就會停止

          隨后我們判斷玩家是否勝利,如果勝利,就打印棋盤,讓玩家知道雷的位置

          	if (win==row * col - EASY_COUNT)
          	{
          		printf("恭喜你,游戲勝利!\n");
          		DisplayBoard(mine, ROW, COL);
          	} 

          這里必須要判斷,因為你失敗了也是會跳出循環的!

          到此,我們的掃雷代碼就是完成了

          4.查看結果

          這里我作弊,將雷的個數設置為80并打印出布置雷之后的棋盤

          輸入最后一個雷的位置,系統提示我們游戲勝利

          輸入雷的坐標后,也會提示你被炸死了

          到這里我們可以確認代碼是編寫成功了!

          對啦對啦!另外的話為了幫助大家,輕松,高效學習C語言/C++,我給大家分享我收集的資源,從最零基礎開始的教程到C語言項目案例,幫助大家在學習C語言的道路上披荊斬棘!可以來我粉絲群領取哦~

          編程學習書籍分享:

          編程學習視頻分享:

          整理分享(多年學習的源碼、項目實戰視頻、項目筆記,基礎入門教程)最重要的是你可以在群里面交流提問編程問題哦!

          對于C/C++感興趣可以關注小編在后臺私信我:【編程交流】一起來學習哦!可以領取一些C/C++的項目學習視頻資料哦!已經設置好了關鍵詞自動回復,自動領取就好了!

          經以為掃雷很難,根本沒有什么思路。昨晚想了想,其實一步一步分解開來還是可以做的。于是乎,今天就寫了一個。本來想用pygame做一個圖形界面,可是太懶了不想做了,就用最簡單的方法實現了。

          掃雷有幾個要點:

          • 你掃的第一塊不能有雷。也就是說當你操作之后才會隨機產生雷。
          • 空白展開,也就是說一個格子,周邊沒有雷那么上面是沒有數字。如果你玩的一個非常的方陣的話,總不能一直一個個的點格子。如果你點到空白的格子,與之相連的空白格子要同時展開。對我來說這個挺難的,我花了很多的時間。
          • 掃雷,每塊格子上的數字表示是這個格子周圍一圈(不在邊緣的話有八個格子)的雷的數量。我覺得和上一個問題有聯系。你要解決二維數組中的某個數與周邊的關系。不能超過列表的索引范圍。
          • 還記得右鍵鼠標可以標記嗎,這個小功能當然不能少了。
          from random import randint
          
          class Lawn():
              def __init__(self, cols, rows, mines_num):
                  self.mines_map=[[0 for row in range(rows)] for col in range(cols)]
                  self.lawn_map=[['■' for row in range(rows)] for col in range(cols)]
                  self.cols, self.rows=cols, rows
                  self.mines_num=mines_num
                  self.game_active=True
          
              def initialize(self, col, row):
                  self.plant_mines(col, row)
                  self.cells_neighbor_mines()
          
              def sweep_mine(self, col, row):
                  if self.game_active:
                      self.initialize(col, row)
                      self.game_active=False
                  self.lawn_map[col][row]=str(self.mines_map[col][row])
                  self.check_res(col, row)
                  self.unfold_nomine_place(col, row)
          
              def flag(self, col, row):
                  if self.lawn_map[col][row]=='#':
                      self.lawn_map[col][row]='?'
                  elif self.lawn_map[col][row]=='?':
                      self.lawn_map[col][row]='■'
                  elif self.lawn_map[col][row]=='■':
                      self.lawn_map[col][row]='#'
                  
              def unfold_nomine_place(self, col, row):
                  check_list, checked_list=[(col, row)], []
                  while check_list:
                      deal_list, stack=[], []
                      i, j=check_list[0][0], check_list[0][1]
                      self.cell_neighbor(deal_list, check_list[0][0], check_list[0][1])
                      self.get_cell_neighbor(stack, deal_list)
                      checked_list.append(check_list.pop(0))
                      if self.lawn_map[i][j]=='0':
                          for k in range(len(stack)):
                              x, y=stack[k][0], stack[k][1]
                              if self.lawn_map[x][y] in '#?':
                                  continue
                              self.lawn_map[x][y]=str(self.mines_map[x][y])
                              if (x, y) not in checked_list and (x, y) not in check_list:
                                  check_list.append((x, y))
                         
              def show_underlawn(self):
                  for col in range(self.cols):
                      print(self.mines_map[col])
          
              def show(self):
                  for col in range(self.cols):
                      print(self.lawn_map[col])
          
              def plant_mines(self, col, row):
                  deal_list=[] 
                  self.cell_neighbor(deal_list, col, row)
                  deal_list.append((col, row))
                  mines_count=self.mines_num
                  while mines_count > 0:
                      mine_x, mine_y=randint(0, self.cols - 1), randint(0, self.rows - 1)
                      if self.mines_map[mine_x][mine_y] !=9:
                          self.mines_map[mine_x][mine_y]=9
                          mines_count -=1
                      for i in range(len(deal_list)):
                          x, y=deal_list[i][0], deal_list[i][1]
                          if self.mines_map[x][y] !=0:
                              self.mines_map[x][y]=0
                              mines_count +=1
          
              def cells_neighbor_mines(self):
                  for col in range(self.cols):
                      for row in range(self.rows):
                          if self.mines_map[col][row]==9:
                              deal_list, stack=[], []
                              self.cell_neighbor(deal_list, col, row)         
                              self.get_cell_neighbor(stack, deal_list)
                              for i in range(len(stack)):
                                  x, y=stack[i][0], stack[i][1]
                                  if self.mines_map[x][y] !=9:
                                      self.mines_map[x][y] +=1
          
              def cell_neighbor(self, deal_list, col, row):
                  for x in range(col - 1, col + 2):
                      for y in range(row - 1, row + 2):
                          if x !=col or y !=row:
                              deal_list.append((x,y))
           
              def get_cell_neighbor(self, stack, deal_list):
                  for i in range(len(deal_list)):
                      if deal_list[i][0] not in range(self.cols) or deal_list[i][1] not in range(self.rows):
                          continue
                      else:
                          stack.append(deal_list[i])
          
              def check_res(self, col , row):
                  count=0
                  if self.mines_map[col][row]==9:
                      print('你踩到雷了!!!')
                  for i in range(self.cols):
                      for j in range(self.rows):
                          if self.lawn_map[i][j] in '#?■':
                              count +=1              
                  if count==self.mines_num:
                      print('你勝利了!!!')
          
          def play(col, row, mode=0):
              if mode==0:
                  lawn.sweep_mine(col, row)
              else:
                  lawn.flag(col, row)
          
          
          col, row, num=eval(input('請輸入方陣的大小,地雷的數量【例如:8,8,10。8X8的方陣,10個地雷。】:'))
          lawn=Lawn(col, row, num)
          while True:
              lawn.show()
              lawn.show_underlawn()
              col,row,mode=eval(input('請輸入要鏟多少行多少列的地方,并且加一個數。如果最后一個數非0,表示鼠標右鍵【插旗】:'))
              play(col, row, mode)

          小編還準備了一下項目資料 有:視頻教學 和源碼 有需要關注評論區留言或者

          們先和大家說好,本次C語言開發的掃雷游戲是通過Easy X實現的,但是很多和我一樣的新手,一開始不知道Easy X是什么,到時源碼拿過去寫之后,運行報錯。Easy X是很多和我一樣的新手在學習的時候用到的一個繪圖工具,畢竟都不想天天對著一個黑漆漆的控制臺,有需要的小伙伴可以關注筆者,進群領取哦~

          同樣這個掃雷的小游戲是很多和我一樣新手學習中所制作的一個小項目,僅當練手。厲害的大佬肯定有用win32或者QT實現的,但是小萌新現在還不會這么高端,僅限新手!

          在分享源碼之前,我先來給大家展示一下咱們這個項目完成之后是什么樣的一個效果:

          掃雷游戲效果圖

          接下來,就正式給大家分享這個項目的源碼,每一處都會有較為詳細的注釋,就不給大家一一說明了,直接上源碼了!

          項目頭文件以及參數設置:


          編寫函數初始化游戲:①隨機生成的個數:


          ②遍歷數組,進行判斷:


          ③加密格子,設置圖片:


          二、繪制游戲界面


          三、處理鼠標消息


          四、遍歷打開空白格:


          五、游戲判定:


          六、主函數:

          希望本篇源碼文章對你有幫助,另外本項目需要圖形庫插件和圖片素材哦!大家做之前可以先去準備好這些東西,圖片可以百度,當然可以找筆者直接領取的!

          學習C/C++編程知識,想要成為一個更加優秀的程序員,或者你學習C/C++的時候有難度,可以關注+私信小編【C/C++編程】筆者的C語言C++零基礎編程學習圈,里面不僅有學習視頻和文件源碼,還有更多志同道合的朋友,歡迎轉行也學習編程的伙伴,和大家一起交流成長會比自己琢磨更快哦!


          上一篇:Bootstrap 基礎
          下一篇:CSS 鏈接
          主站蜘蛛池模板: 色窝窝免费一区二区三区| 精品国产毛片一区二区无码| 国产一区二区三区免费在线观看| 国产高清精品一区| 精品福利一区二区三区免费视频 | 国产亚洲情侣一区二区无码AV| 狠狠色综合一区二区| 亚洲日韩精品一区二区三区无码| 精品无码一区二区三区水蜜桃| 亚洲乱色熟女一区二区三区蜜臀| 秋霞无码一区二区| 精品无码av一区二区三区| 精品少妇一区二区三区视频| 东京热无码av一区二区| 日本一区二区三区免费高清在线| 精品久久久中文字幕一区| 中文字幕av日韩精品一区二区| 亚洲码一区二区三区| 一区二区三区高清| 日韩中文字幕一区| 无码日本电影一区二区网站 | 精品人妻一区二区三区四区在线| eeuss鲁片一区二区三区| 亚洲熟妇无码一区二区三区| 亚洲欧美日韩中文字幕在线一区| 97久久精品无码一区二区| 精品女同一区二区三区免费站| 91精品乱码一区二区三区| 国产精品电影一区| 免费看无码自慰一区二区| 亚洲AV日韩综合一区| 国产伦精品一区二区三区四区| 波多野结衣中文字幕一区二区三区| 日本免费一区尤物| 国产午夜三级一区二区三| 寂寞一区在线观看| 亚洲av色香蕉一区二区三区蜜桃| 国产成人一区二区三区电影网站| aⅴ一区二区三区无卡无码| 国产在线无码视频一区二区三区| 亚洲无删减国产精品一区|