詳細解讀用C語言編寫的 「掃雷」程序

2021-03-02 C語言題庫


用C語言編寫的掃雷程序

編寫前首先得有大致的思路吧,就是第一步幹啥第二部幹啥?以我目前的水平編寫的程序只能在黑框框裡運行。先讓大家提提神 。這個圖是windows裡面的掃雷程序。好!廢話不多,正題開始

game.c

一、遊戲的功能函數,統統放在game.c中。

1、那麼我們首先需要列印 「菜單函數」,來提醒玩家要不要玩遊戲?或者玩過一把還想不想玩下一把。

#define _CRT_SECURE_NO_WARNINGS 1#include"game.h"char show_mine[row][col] = { 0 }; //玩家數組char real_mine[row][col] = { 0 }; //設計者數組

void muen() //列印菜單{ printf("*******************************\n"); printf("*****1.play 0.exit*******\n"); printf("*******************************\n");}

2、然後就需要雷陣了,這時候你就要明白了,一個雷陣是不夠的,因為玩家贏了或者玩家輸了你要給玩家看一下你的存雷雷陣,所以兩個雷陣是正確的選擇,當然可以不列印你的存雷雷陣,我這裡為了方便兩個雷陣都列印了。好!要有雷陣,就先初始化雷陣 這是我定義的兩個數組。

show_mine[row][col];//玩家數組

real_mine[row][col];//設計者數組

在初始化過程中,有雷的地方用字符1表示,沒有雷的地方用字符0表示。

void init_mine(){  int i = 0;  int j = 0;  for (int i = 0; i < row; i++)  {    for (j = 0; j < col; j++)    {      show_mine[i][j] = '*';      real_mine[i][j] = '0';    }  }}

3、接下類就是要列印雷陣了。

注意給橫行和豎行都加上1-10數字,可以方便玩家輸入坐標。

void print_player(){  int i = 0;  int j = 0;  printf("0  ");  for (i = 1; i <row - 1; i++)  {    printf("%d ", i);  }  printf("\n");  for (i = 1; i <row - 2; i++)  {    printf("%d  ", i);    for (j = 1; j < col - 1; j++)    {      printf("%c ", show_mine[i][j]);    }    printf("\n");  }  printf("10 ");  for (i = 1; i < row - 1; i++)  {    printf("%c ", show_mine[10][i]);  }  printf("\n");}

void print_mine(){ int i = 0; int j = 0; printf("0 "); for (i = 1; i <row - 1; i++) { printf("%d ", i); } printf("\n"); for (i = 1; i <row - 2; i++) { printf("%d ", i); for (j = 1; j < col - 1; j++) { printf("%c ", real_mine[i][j]); } printf("\n"); } printf("10 "); for (i = 1; i < row - 1; i++) { printf("%c ", real_mine[10][i]); } printf("\n");}

4、接下來該存雷了,我們每一次玩的時候要讓雷出現的地方不一樣,那麼我們就採用隨機值來確定存雷的位置。利用rand()來產生隨機值。Rand()%10產生0-9.然後在加1.就可以產生1-10這10個數,然後就可以產生10個不同的坐標。我的這個程序的雷數是有玩家自己設定的。

void set_mine(int COUNT ){  int x = 0;  int y = 0;  int count = COUNT;  while (count)  {    int x = rand() % 10 + 1;    int y = rand() % 10 + 1;    if (real_mine[x][y] == '0')    {      real_mine[x][y] = '1';      count--;    }  }}

5、檢測一個點周圍雷的個數,然後輸出一個坐標周圍有幾個雷的數量。利用函數實現。

int count_mine(int x, int y)//檢測周圍8個區域雷的個數{  int count = 0;  if (real_mine[x - 1][y - 1] == '1')    count++;  if (real_mine[x - 1][y] == '1')    count++;  if (real_mine[x - 1][y + 1] == '1')    count++;  if (real_mine[x][y - 1] == '1')    count++;  if (real_mine[x][y + 1] == '1')    count++;  if (real_mine[x + 1][y - 1] == '1')    count++;  if (real_mine[x + 1][y] == '1')    count++;  if (real_mine[x + 1][y + 1] == '1')    count++;  return count;}

6、剛開始掃雷,第一次一下子就踩到雷了,那不是掃了玩家的興趣麼,不好玩?那怎麼辦?我來給你說這樣做。第一次如果掃到雷,那就把那顆雷給它移走,移到不是雷的地方。利用函數實現。

void safe_mine(){  int x = 0;    int y = 0;    char ch = 0;  int count = 0;  int ret = 1;  printf("輸入坐標掃雷\n");  while (1)  {    scanf_s("%d%d", &x, &y);    if ((x >= 1 && x <= 10) && (y >= 1 && y <= 10))    {      if (real_mine[x][y] == '1')      {        real_mine[x][y] = '0';        char ch = count_mine(x, y);        show_mine[x][y] = ch + '0';        open_mine(x, y);        while (ret)        {          int x = rand() % 10 + 1;          int y = rand() % 10 + 1;          if (real_mine[x][y] == '0')          {            real_mine[x][y] = '1';            ret--;               break;            }        }break;      }      if (real_mine[x][y] == '0')      {        char ch = count_mine(x, y);        show_mine[x][y] = ch + '0';        open_mine(x, y);          break;      }    }    else    {      printf("輸入錯誤重新輸入\n");    }  }}

7、掃雷的時候要是周圍沒有雷,那麼還可以展開,一直到周圍有雷的坐標。周圍的坐標和本點的坐標都有關係,不懂看代碼。

void open_mine(int x, int y)//坐標周圍展開函數{  if (real_mine[x - 1][y - 1] == '0')  {    show_mine[x - 1][y - 1] = count_mine(x - 1, y - 1) + '0';//顯示該坐標周圍雷數  }  if (real_mine[x - 1][y] == '0')  {    show_mine[x - 1][y] = count_mine(x - 1, y) + '0';//顯示該坐標周圍雷數  }  if (real_mine[x - 1][y + 1] == '0')  {    show_mine[x - 1][y + 1] = count_mine(x - 1, y + 1) + '0';//顯示該坐標周圍雷數  }  if (real_mine[x][y - 1] == '0')  {    show_mine[x][y - 1] = count_mine(x, y - 1) + '0';//顯示該坐標周圍雷數  }  if (real_mine[x][y + 1] == '0')  {    show_mine[x][y + 1] = count_mine(x, y + 1) + '0';//顯示該坐標周圍雷數  }  if (real_mine[x + 1][y - 1] == '0')  {    show_mine[x + 1][y - 1] = count_mine(x + 1, y - 1) + '0';//顯示該坐標周圍雷數  }  if (real_mine[x + 1][y] == '0')  {    show_mine[x + 1][y] = count_mine(x + 1, y) + '0';//顯示該坐標周圍雷數  }  if (real_mine[x + 1][y + 1] == '0')  {    show_mine[x + 1][y + 1] = count_mine(x + 1, y + 1) + '0';//顯示該坐標周圍雷數  }}

8、然後就是我們的重點重點啦,掃雷函數。注意判斷輸入的坐標是否正確,不正確提示重新輸入。判斷雷的個數和剩餘未知區域的個數,如果相等,則玩家贏。如果點的坐標剛好存雷,那麼玩家就輸了。

int sweep_mine(int COUNT){  int x = 0;  int y = 0;  int count = 0;  printf("輸入坐標掃雷\n");  scanf_s("%d%d", &x, &y);  if ((x >= 1 && x <= 10) && (y >= 1 && y <= 10))  {    if (real_mine[x][y] == '0')    {      char ch = count_mine(x, y);      show_mine[x][y] = ch + '0';      open_mine(x, y);        if (count_show_mine() == COUNT)      {        print_mine();        printf("玩家贏!\n\n");        return 0;      }    }    else if (real_mine[x][y] == '1')    {      return 1;      }
} else { printf("輸入錯誤重新輸入\n"); } return 0;}

9、到最後需要確定遊戲勝利的條件,我們要統計當前狀態玩家棋盤中顯示的剩餘 * 的個數,如果個數等於總雷數時說明掃雷完成,遊戲勝利,定義一個函數實現。

int count_show_mine(){  int count = 0;  int i = 0;  int j = 0;  for (i = 1; i <= row - 2; i++)  {    for (j = 1; j <= col - 2; j++)    {      if (show_mine[i][j] == '*')      {        count++;      }    }
} return count;}

test.c

二、遊戲的主函數,負責調用功能函數,來實現程序。放在test.C中。相當於test.c中是程序的整體構架。

#define _CRT_SECURE_NO_WARNINGS 1#include"game.h"double  start, finish;
void game(){
int ret = 0; int COUNT = 0; init_mine(); printf("請輸入雷數:>"); scanf_s("%d",&COUNT); set_mine(COUNT); print_mine(); printf("\n"); print_player(); start = clock(); safe_mine();
if (count_show_mine() == COUNT) { print_mine(); printf("玩家贏!\n\n"); return; }print_player();
while (1) { int ret = sweep_mine(COUNT); if (count_show_mine() == COUNT) { print_mine(); printf("玩家贏!\n\n"); finish = clock(); printf("用時%d 秒\n", (int)(finish - start) / CLOCKS_PER_SEC); break; } if (ret) { printf("被雷炸死\t"); finish = clock(); printf("用時%d 秒\n", (int)(finish - start) / CLOCKS_PER_SEC); print_mine(); break; }print_player(); }}

int main(){ srand((unsigned int)time(NULL)); int input = 0; muen(); do { scanf("%d", &input); switch (input) { case 1:game(); break; case 0:exit(1); break; default: printf("輸入錯誤,重新輸入\n"); break; } muen(); printf("contiue?\n"); } while (1); system("pause"); return 0;}

game.h

三、頭文件,負責申明各種函數。

#ifndef __GAME_H__#define __GAME__H__
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<time.h>
#define row 12#define col 12char show_mine[row][col];char real_mine[row][col];
void muen();void init_mine();void set_mine(int COUNT);int count_mine();void print_player();void print_mine();int sweep_mine(int COUNT);void safe_mine();void open_mine(int x, int y);int count_show_mine();
#endif

在配幾張圖。

最後給各位老鐵附上game.c函數整體的原始碼。
#define _CRT_SECURE_NO_WARNINGS 1#include"game.h"char show_mine[row][col] = { 0 }; char real_mine[row][col] = { 0 }; 

void muen() { printf("*******************************\n"); printf("*****1.play 0.exit*******\n"); printf("*******************************\n");}

void init_mine(){ int i = 0; int j = 0; for (int i = 0; i < row; i++) { for (j = 0; j < col; j++) { show_mine[i][j] = '*'; real_mine[i][j] = '0'; } }}
void print_player(){ int i = 0; int j = 0; printf("0 "); for (i = 1; i <row - 1; i++) { printf("%d ", i); } printf("\n"); for (i = 1; i <row - 2; i++) { printf("%d ", i); for (j = 1; j < col - 1; j++) { printf("%c ", show_mine[i][j]); } printf("\n"); } printf("10 "); for (i = 1; i < row - 1; i++) { printf("%c ", show_mine[10][i]); } printf("\n");}

void print_mine(){ int i = 0; int j = 0; printf("0 "); for (i = 1; i <row - 1; i++) { printf("%d ", i); } printf("\n"); for (i = 1; i <row - 2; i++) { printf("%d ", i); for (j = 1; j < col - 1; j++) { printf("%c ", real_mine[i][j]); } printf("\n"); } printf("10 "); for (i = 1; i < row - 1; i++) { printf("%c ", real_mine[10][i]); } printf("\n");}

void set_mine(int COUNT ){ int x = 0; int y = 0; int count = COUNT; while (count) { int x = rand() % 10 + 1; int y = rand() % 10 + 1; if (real_mine[x][y] == '0') { real_mine[x][y] = '1'; count--; } }}
int count_mine(int x, int y){ int count = 0; if (real_mine[x - 1][y - 1] == '1') count++; if (real_mine[x - 1][y] == '1') count++; if (real_mine[x - 1][y + 1] == '1') count++; if (real_mine[x][y - 1] == '1') count++; if (real_mine[x][y + 1] == '1') count++; if (real_mine[x + 1][y - 1] == '1') count++; if (real_mine[x + 1][y] == '1') count++; if (real_mine[x + 1][y + 1] == '1') count++; return count;}
void safe_mine(){ int x = 0; int y = 0; char ch = 0; int count = 0; int ret = 1; printf("輸入坐標掃雷\n"); while (1) { scanf_s("%d%d", &x, &y); if ((x >= 1 && x <= 10) && (y >= 1 && y <= 10)) { if (real_mine[x][y] == '1') { real_mine[x][y] = '0'; char ch = count_mine(x, y); show_mine[x][y] = ch + '0'; open_mine(x, y); while (ret) { int x = rand() % 10 + 1; int y = rand() % 10 + 1; if (real_mine[x][y] == '0') { real_mine[x][y] = '1'; ret--; break; } }break; } if (real_mine[x][y] == '0') { char ch = count_mine(x, y); show_mine[x][y] = ch + '0'; open_mine(x, y); break; } } else { printf("輸入錯誤重新輸入\n"); } }}
void open_mine(int x, int y){ if (real_mine[x - 1][y - 1] == '0') { show_mine[x - 1][y - 1] = count_mine(x - 1, y - 1) + '0'; } if (real_mine[x - 1][y] == '0') { show_mine[x - 1][y] = count_mine(x - 1, y) + '0'; } if (real_mine[x - 1][y + 1] == '0') { show_mine[x - 1][y + 1] = count_mine(x - 1, y + 1) + '0'; } if (real_mine[x][y - 1] == '0') { show_mine[x][y - 1] = count_mine(x, y - 1) + '0'; } if (real_mine[x][y + 1] == '0') { show_mine[x][y + 1] = count_mine(x, y + 1) + '0'; } if (real_mine[x + 1][y - 1] == '0') { show_mine[x + 1][y - 1] = count_mine(x + 1, y - 1) + '0'; } if (real_mine[x + 1][y] == '0') { show_mine[x + 1][y] = count_mine(x + 1, y) + '0'; } if (real_mine[x + 1][y + 1] == '0') { show_mine[x + 1][y + 1] = count_mine(x + 1, y + 1) + '0'; }}

int sweep_mine(int COUNT){ int x = 0; int y = 0; int count = 0; printf("輸入坐標掃雷\n"); scanf_s("%d%d", &x, &y); if ((x >= 1 && x <= 10) && (y >= 1 && y <= 10)) { if (real_mine[x][y] == '0') { char ch = count_mine(x, y); show_mine[x][y] = ch + '0'; open_mine(x, y); if (count_show_mine() == COUNT) { print_mine(); printf("玩家贏!\n\n"); return 0; } } else if (real_mine[x][y] == '1') { return 1; }
} else { printf("輸入錯誤重新輸入\n"); } return 0;}


int count_show_mine(){ int count = 0; int i = 0; int j = 0; for (i = 1; i <= row - 2; i++) { for (j = 1; j <= col - 2; j++) { if (show_mine[i][j] == '*') { count++; } }
} return count;}

程序的優勢在於:

1、 第一次踩到雷不會死,而會把這顆雷移到別處,保證玩家的興趣。嘿嘿。

2、 可以展開。即選中一點可以展開周圍8個點也沒有雷的坐標,只是8個,我還沒有做到展開再外圈。

3、 可以由玩家自己設定雷的個數,玩家可以挑戰自己。哈哈

4、 可以計時,即遊戲結束,包括輸贏,玩家所用的時間。

原文連結:https://blog.csdn.net/qq_40421919/article/details/79916214

相關焦點

  • 使用C語言寫一個簡易版掃雷小遊戲
    一、問題描述用C語言實現簡易版掃雷。二、基本流程如果不是地雷,統計當前位置周圍雷的個數, 並顯示到地圖上.。微信關注公眾號【C語言中文社區】,免費領取200G精品學習資料#define MAX_ROW 9#define MAX_COL 9 char show[MAX_ROW][MAX_COL] = { 0 }; char mine[MAX_ROW][MAX_COL] = { 0 };mine地圖是由0,1組成的
  • C語言學習-02 編譯器與IDE
    源文件後綴大都根據程式語言本身的名字來命名,以下是幾種語言的源文件:源文件其實就是純文本文件,它的內部並沒有特殊格式,能證明這一結論的典型例子是:在 Windows 下用記事本程序新建一個文本文檔,並命名為demo.txt,輸入一段C語言代碼並保存,然後將該文件強制重命名為demo.c(後綴從.txt變成了.c),發現編譯器依然能夠正確識別其中的C語言代碼,並順利生成可執行文件。
  • 戰術單位如何編寫自己的標準作業程序(SOP)
    (本文中所提到的「指南」是指用來詳細說明SOP如何實施的書面材料)標準作業程序(Standard Operating Procedure)是一種應用十分廣泛的工作方法。根據美國陸軍的說法,「標準作業程序是一套書面的方法說明,詳細說明了執行日常或重複性任務、學習的程序。」
  • Linux驅動實踐:如何編寫【 GPIO 】設備的驅動程序?
    在前幾篇文章中,我們一塊討論了:在 Linux 系統中,編寫字符設備驅動程序的基本框架,主要是從代碼流程和 API 函數這兩方面觸發。這篇文章,我們就以此為基礎,寫一個有實際應用功能的驅動程序:在驅動程序中,初始化 GPIO 設備,自動創建設備節點;在應用程式中,打開 GPIO 設備,並發送控制指令設置 GPIO 口的狀態;示例程序目標 編寫一個驅動程序模塊:mygpio.ko。
  • [系統安全] 一.什麼是逆向分析、逆向分析應用及經典掃雷遊戲逆向
    第一篇文章先帶領大家學習什麼是逆向分析,然後詳細講解逆向分析的典型應用,接著通過OllyDbg工具逆向分析經典的遊戲掃雷,再通過Cheat Engine工具複製內存地址獲取,實現一個自動掃雷程序。該篇文章也是作者學習科銳錢林松老師在華中科技大學的分享視頻,這裡非常推薦大家去看看。話不多說,讓我們開始新的徵程吧!
  • 為什麼指針被譽為 C 語言靈魂?
    因此,如果能更好地理解內存的模型,以及 C 如何管理內存,就能對程序的工作原理洞若觀火,從而使編程能力更上一層樓。大家真的別認為這是空話,我大一整年都不敢用 C 寫上千行的程序也很抗拒寫 C。在 C 語言中我們會這樣定義變量:int a = 999;char c = 'c';當你寫下一個變量定義的時候,實際上是向內存申請了一塊空間來存放你的變量。
  • C語言實現掃雷小遊戲,自學C語言小項目!
    %d ", col); } printf("\n"); printf("--+---\n"); for (int row = 0; row < MAX_ROW; row++) {  printf(" %d|", row);  for (int col = 0; col < MAX_COL; col++) {   printf("%c
  • 掃雷程序外掛分析記錄
    所謂遊戲外掛,是一種遊戲輔助程序,可以協助玩家自動產生遊戲動作、修改遊戲網絡數據包以及修改遊戲內存數據等。
  • 既然C編譯器是C語言寫的,那第一個C編譯器是怎樣來的?
    C語言是很低級的語言,很多方面都近似於彙編語言,在《Intel 32位彙編語言程序設計》一書中,甚至介紹了手工把簡單的C語言翻譯成彙編的方法。對於編譯器這種系統軟體,用C語言來編寫是很自然不過的,即使是像Python這樣的高級語言依然在底層依賴於C語言。
  • (宇宙最強C/C++編譯器)樂創DIY C語言講義​——2.6 GCC的使用
    其實早期的計算機生成成本太貴,體積太大,都是以小型機或者大型機形式存在的,可能每個公司也就一臺,其他用戶都是使用串口插到這臺大型機上面來工作的,他們面前只有一個叫做「終端」(或者控制臺的設備,上面跑的程序叫做Shell)檔或者其他辦公,因此Unix最早期的設計哲學就是中心化數據處理的多用戶多任務作業系統,而Linux完美繼承了這一點。這種方式是不是有點類似於現在的伺服器架構?
  • 如何給右鍵添加任何啟動程序 | 十分鐘詳細教程
    最關鍵的,是其他幾個選項,我們看到了有各種Open with,還全是JetBrains家的,比如編寫C/C++語言的Clion,編寫Java語言的IDEA,編寫python語言的PyCharm和編寫JS語言的WebStorm,當然了這是因為我安裝了這些軟體,然後他們自動寫入了註冊表,畢竟大廠的軟體啥都考慮到了。對於更加小眾、獨立的軟體就暫時不支持這麼牛哄哄的底層操作了(或者不敢,怕說流氓)。
  • 關於C語言堆棧的經典講解
    - 程序結束後有系統釋放文字常量區—常量字符串就是放在這裡的。程序結束後由系統釋放程序代碼區—存放函數體的二進位代碼。例子程序    這是一個前輩寫的,非常詳細。    接觸過編程的人都知道,高級語言都能通過變量名來訪問內存中的數據。那麼這些變量在內存中是如何存放的呢?程序又是如何使用這些變量的呢?下面就會對此進行深入的討論。下文中的C語言代碼如沒有特別聲明,默認都使用VC編譯的release版。
  • C語言關鍵字應用技巧!
    編譯器並不給普通const只讀變量分配空間,而是將它們保存到符號表中,無需讀寫內存操作,程序執行效率也會提高。3、 修飾指針C語言中const修飾指針要特別注意,共有兩種形式,一種是用來限定指向空間的值不能修改;另一種是限定指針不可更改。
  • C語言編譯器之二,Clang
    2.1、Clang和GCC編譯器架構從原始碼到可執行程序一般經過預處理、編譯、連結過程,而編譯是編譯器的工作,編譯分為三個階段,分別為前端、優化器、後端。其詳細過程包括:詞法分析、語法分析、生成中間代碼;ii.優化器:對編譯器生成的中間代碼進行一些優化,最終提供給編譯後端;iii.
  • C語言代碼中 extern "C"的前世今生
    另外,C++程序的構造方式仍然繼承了C語言的傳統:編譯器把每一個通過命令行指定的原始碼文件看做一個獨立的編譯單元,生成目標文件;然後,連結器通過查找這些目標文件的符號表將它們連結在一起生成可執行程序。編譯和連結是兩個階段的事情;事實上,編譯器和連結器是兩個完全獨立的工具。編譯器可以通過語義分析知道那些同名的符號之間的差別;而連結器卻只能通過目標文件符號表中保存的名字來識別對象。
  • 淺談C語言break和continue用法
    C語言關鍵字break,僅只用在switch 語句或循環語句中, 其作用是跳出switch語句或跳出本層循環,轉去執行後面的程序。下面分析下break,這兩種情況下的用法。 一、switch-case-break-default構成多種選擇結構基本語句。
  • 用 Webhook+Python+Shell 編寫一套 Unix 類系統監控工具
    它接收用戶命令,然後調用相應的應用程式。同時它又是一種程序設計語言。作為命令語言,它交互式解釋和執行用戶輸入的命令,或者自動地解釋和執行預先設定好的一連串的命令;作為程序設計語言,它定義了各種變量和參數,並提供了許多在高級語言中才具有的控制結構,包括循環和分支。
  • 學習C語言,有哪些好用的編譯器可以推薦嗎?
    收錄於話題 #c語言VS(Visual Studio)Visual Studio號稱「宇宙最強IDE」,不僅可以用來開發C/C++,還可以用來開發Python、TypeScript、C#等眾多語言,而且代碼補全、語法高亮、項目版本管理等功能的集成程度是目前所有
  • C語言堆和棧的區別,非常全面~
    - 程序結束後由系統釋放。4、文字常量區:常量字符串就是放在這裡的。程序結束後由系統釋放5、程序代碼區:存放函數體的二進位代碼。例子程序這是一個前輩寫的,非常詳細#include "stdio.h"int a = 0;//全局初始化區 char *p1;//   全局未初始化區    void main(void)    {      int   b;//   棧      char
  • C 語言實現Linux cp 命令
    小編今天介紹的項目課程就是教你用C語言來實現這個Linux cp命令,對C語言學習者來說是非常不錯的練手項目。項目名稱:【C 語言實現Linux cp 命令】項目簡介:該項目通過完成C 語言實現Linux cp 命令,掌握Linux作業系統中的文件IO相關的系統函數和目錄相關操作的系統函數,比如open, write, opendir, readir。深入了解Linux環境系統編程。