數據結構課程設計------掃雷游戲(升級版,可展開)

本程序由團隊中的一個人所寫,本人看懂并寫下此文章

題目:掃雷

3.1問題描述

掃雷游戲
[基本要求]
(1)完成棋盤的初始化并在標準顯示器中顯示
(2)通過輸入行列值確定用戶輸入
(3)游戲進行給出提示信息
(4)給出游戲的測試程序。

3.2.算法設計與分析

3.2.1設計思路分析
首先定義一個二維數組的棋盤,用偽隨機數在棋盤上生成地雷。通過從鍵盤上輸入坐標,判斷此位置是不是存在地雷,存在則游戲結束,不存在則展開棋盤。展開的周圍顯示出附近存在的地雷個數。依次類推,直到找出所有地雷。
3.2.2設計程序流程圖(要求圖文并茂)
在這里插入圖片描述
首先進入菜單,選擇開始游戲,生成棋盤與地雷,然后顯示棋盤,用戶輸入相應的位置坐標,程序進行判斷該位置是否為地雷,是的話游戲結束,不是的話則展開棋盤,繼續輸入并統計地雷個數,依次類推,直到地雷數統計完則游戲結束。
3.2.3數據結構定義

#define COUNT 10
#define ROW 9
#define CLO 9
#define ROWS 11
#define CLOS 11
char arr[ROW][CLO] = { 0 };    //顯示棋盤
char arrs[ROWS][CLOS] = { 0 };   //真正操作的棋盤

3.2.4算法的時間復雜度分析
棋盤初始化模塊的算法,對定義好的二維數組元素進行定義,時間復雜度為O(1)。
模擬棋盤初始化算法,對定義好的二維數組元素進行定義,時間復雜度為O(1)。
打印棋盤的算法,通過依次遍歷二維數組打印數據元素,時間復雜度為O(n)。
地雷生成算法,通過偽隨機數在棋盤上生成地雷,時間復雜度為O(n)。
判斷是否為地雷算法,通過數據匹配的方式進行判斷,時間復雜度為O(1)。
統計地雷個數的算法,通過數據匹配的方式進行統計,時間復雜度為O(n)。
棋盤展開算法,每次輸入坐標展開棋盤,時間復雜度為O(1)。

3.3源程序清單(帶注釋)

Game.h
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#define COUNT 10
#define ROW 9
#define CLO 9
#define ROWS 11
#define CLOS 11
void printbroad(char arr[ROW][CLO], int row, int clo);
void arr_init(char arr[ROW][CLO], int row, int clo);
void menu();
void arrs_randinit(char arrs[ROWS][CLOS], int row, int clo);     //生成隨機雷
void arrs_init(char arrs[ROWS][CLOS], int row, int clo);
void print(char arrs[ROWS][CLOS], int row, int clo);
void sweep(char arrs[ROWS][CLOS], char arr[ROW][CLO], int row, int clo);  //掃雷
int is_thunder(char arrs[ROWS][CLOS], char arr[ROW][CLO], int row, int clo);
int count(char arrs[ROWS][CLOS], int row, int clo);         //計算周圍雷的數目
void movefirst(char arrs[ROWS][CLOS], int row, int clo);
void open(char arrs[ROWS][CLOS], char arr[ROW][CLO], int i, int j);
Game.c
#pragma warning(disable:4996)
#include"game.h"
int num = ROW*CLO - COUNT;
void menu()
{printf("****************************************\n");printf("***************  1.play   **************\n");printf("***************  0.exit   **************\n");printf("****************************************\n");}
//打印掃雷棋盤
void printbroad(char arr[ROW][CLO], int row, int clo)
{int i = 0;int j = 0;printf("   ");//打印掃雷棋盤的橫坐標for (i = 1; i <= row; i++){printf("%d ", i );}printf("\n");for (i = 1; i <= row; i++){printf("--");}printf("--");printf("\n");for (i = 0; i < row; i++){//打印掃雷棋盤的縱坐標printf("%d| ", i+1);for (j = 0; j < clo; j++){printf("%c ", arr[i][j]);}printf("\n");}printf("\n");
}void arr_init(char arr[ROW][CLO], int row, int clo)
{//這個函數的功能是將該數組所有置*memset(&arr[0][0], '*', row*clo*sizeof(arr[0][0]));
}
void arrs_init(char arrs[ROWS][CLOS], int row, int clo)
{memset(&arrs[0][0], '0', row*clo*sizeof(arrs[0][0]));
}//生成隨機地雷,1代表地雷,0代表沒有地雷;
void arrs_randinit(char arrs[ROWS][CLOS], int row, int clo)
{int count = COUNT;int i = 0;int j = 0;do{//生成隨機橫縱坐標i = rand() % 9+1;  //生成1~9的橫坐標j = rand() % 9+1;  //生成1~9的縱坐標if (arrs[i][j] != '1') //如果此處有地雷,則繼續循環{arrs[i][j] = '1';count--;}} while (count);}
void print(char arrs[ROWS][CLOS], int row, int clo)
{int i = 0;int j = 0;printf("   ");for (i = 1; i < row - 1; i++){printf("%d ", i);}printf("\n");for (i = 1; i < row - 1; i++){printf("--");}printf("--");printf("\n");printf("1|");for (i = 1; i < row-1; i++){printf(" ");for (j = 1; j < clo-1; j++){printf("%c ", arrs[i][j]);}printf("\n");if (i == 9){continue;}printf("%d|", i+1);}//int i = 0;//int j = 0;//printf("   ");打印掃雷棋盤的橫坐標//for (i = 1; i <= row-2; i++)//{//	printf("%d ", i);//}//printf("\n");//for (i = 1; i <= row-2; i++)//{//	printf("--");//}//printf("--");//printf("\n");//for (i = 0; i < row-2; i++)//{//	//打印掃雷棋盤的縱坐標//	printf("%d| ", i + 1);//	for (j = 0; j < clo-2; j++)//	{//		printf("%c ", arrs[i][j]);//	}//	printf("\n");//}//printf("\n");
}int is_thunder(char arrs[ROWS][CLOS],char arr[ROW][CLO], int row, int clo)
{if (arrs[row][clo] == '1'){return 0;}else{return 1;}
}//計算周圍一圈(8個數)有多少個地雷
int count(char arrs[ROWS][CLOS], int row, int clo)
{int count = 0;return ((arrs[row - 1][clo - 1] +arrs[row - 1][clo] +arrs[row - 1][clo + 1] +arrs[row][clo - 1] +arrs[row][clo + 1] +arrs[row + 1][clo - 1] +arrs[row + 1][clo] +arrs[row + 1][clo + 1])-'0'*8);}
//當玩家第一次就點到地雷時,得把地雷移走
void movefirst(char arrs[ROWS][CLOS], int row, int clo)
{int x = 0;int y = 0;while (1){x = rand() % 9 + 1;y = rand() % 9 + 1;if (arrs[x][y] != '1'){arrs[x][y] = '1';break;}}arrs[row][clo] = '0';
}void sweep(char arrs[ROWS][CLOS], char arr[ROW][CLO], int row, int clo)
{//判斷是否為第一次掃雷的標志位int first = 0;int x = 0;int y = 0;int flag = 1;int ret = 0;while (flag){printf("請輸入坐標>\n");scanf("%d%d", &x, &y);//如果是雷,則返回0,否則返回1;ret = is_thunder(arrs, arr, x, y);if (x >= 1 && x <= 9 && y >= 1 && y <= 9){first++;switch (ret){case 1:if (count(arrs, x, y) == 0){open(arrs, arr, x - 1, y - 1);}else {arr[x - 1][y - 1] = count(arrs, x, y) + '0';num--;}printbroad(arr, ROW, CLO);//printf("\n%d\n", num);break;case 0://如果第一次就碰到了雷,就將雷移走,提升游戲體驗if (first == 1){movefirst(arrs, x, y);if (count(arrs, x, y) == 0){open(arrs, arr, x - 1, y - 1);}else {arr[x-1][y-1] = count(arrs, x, y) + '0';num--;}printbroad(arr, ROW, CLO);break;}printf("你被炸掉了\nGAMEOVER!!!!!!!!\n");print(arrs, ROWS, CLOS);flag = 0;break;}if (0 == num){printf("游戲結束,玩家贏!!!\n");break;}}else{printf("輸入錯誤,請重新輸入:\n");}}
}
int right(int i, int j)
{if (  (i + 1)>=1 && (i + 1)<=9 && (j + 1)>=1 &&(j + 1)<= 9  ){return 1;}return 0;
}void open(char arrs[ROWS][CLOS], char arr[ROW][CLO], int i, int j)
{//如果當前位置沒有地雷,而且當前位置在棋盤上沒有被顯示,則顯示出周圍一圈雷的數量;if (arrs[i+1][j+1] == '0' && arr[i][j] == '*'&&right(i,j)){arr[i][j] = count(arrs, i+1, j+1) + '0';num--;}//左一位置if (arrs[i + 1][j] == '0' && arr[i][j - 1] == '*'&&right(i, j-1)){arr[i][j-1] = count(arrs, i+1, j) + '0';num--;if (count(arrs, i+1, j) == 0){open(arrs, arr, i, j-1);}}//右一位置if (arrs[i + 1][j + 2] == '0' && arr[i][j + 1] == '*'&&right(i, j+1)){arr[i][j + 1] = count(arrs, i+1, j + 2) + '0';num--;if (count(arrs, i+1, j + 2) == 0){open(arrs, arr, i, j + 1);}}//上一位置if (arrs[i][j + 1] == '0' && arr[i - 1][j] == '*'&&right(i-1, j)){arr[i - 1][j] = count(arrs, i, j+1) + '0';num--;if (count(arrs, i, j+1) == 0){open(arrs, arr, i-1, j);}}//左上位置if (arrs[i][j] == '0' && arr[i - 1][j - 1] == '*'&&right(i-1, j-1)){arr[i - 1][j - 1] = count(arrs, i, j) + '0';num--;if (count(arrs, i, j) == 0){open(arrs, arr, i - 1, j - 1);}}//右上if (arrs[i][j + 2] == '0' && arr[i - 1][j + 1] == '*'&&right(i-1, j+1)){arr[i - 1][j + 1] = count(arrs, i, j + 2) + '0';num--;if (count(arrs, i, j + 2) == 0){open(arrs, arr, i-1, j + 1);}}//右下if (arrs[i + 2][j + 2] == '0' && arr[i + 1][j + 1] == '*'&&right(i+1, j+1)){arr[i + 1][j + 1] = count(arrs, i + 2, j + 2) + '0';num--;if (count(arrs, i + 2, j + 2) == 0){open(arrs, arr, i + 1, j + 1);}}//下if (arrs[i + 2][j + 1] == '0' && arr[i + 1][j] == '*'&&right(i+1, j)){arr[i + 1][j] = count(arrs, i + 2, j+1) + '0';num--;if (count(arrs, i + 2, j+1) == 0){open(arrs, arr, i + 1, j);}}//左下if (arrs[i + 2][j] == '0' && arr[i + 1][j - 1] == '*'&&right(i+1, j-1)){arr[i + 1][j - 1] = count(arrs, i + 2, j) + '0';num--;if (count(arrs, i + 2, j) == 0){open(arrs, arr, i + 1, j - 1);}}
}
Test.c
#pragma warning(disable:4996)
#include"game.h"
void playgame()
{char arr[ROW][CLO] = { 0 };    //顯示棋盤char arrs[ROWS][CLOS] = { 0 };   //真正操作的棋盤arr_init(arr, ROW, CLO);arrs_init(arrs, ROWS, CLOS);arrs_randinit(arrs, ROWS, CLOS);printbroad(arr, ROW, CLO);print(arrs, ROWS, CLOS);sweep(arrs, arr, ROW, CLO);}
int main()
{srand((unsigned int)time(NULL));int key = 0;do{menu();scanf("%d", &key);if (key == 1)playgame();else if (key == 0)printf("退出游戲\n");elseprintf("輸入有誤,請重新輸入:\n");} while (key);return 0;
}

3.4執行結果

在這里插入圖片描述
生成棋盤與地雷
在這里插入圖片描述
輸入坐標進行判斷
在這里插入圖片描述
輸入坐標進行判斷
在這里插入圖片描述
游戲結束
在這里插入圖片描述

3.5存在問題分析

(1)沒有實現插旗的功能。
(2)不能統計以往的游戲信息,沒有實現數據保存。
(3)沒有排行榜功能。
(4)不能進行游戲難度的設定。

3.6結論

這次的掃雷程序代碼量比較大,一開始給我們小組造成了一些困難,但經過我們的查找資料,相互交流,將這些困難一一克服,其中的展開函數經過我們的不斷調試,終于將正確的參數確定。完成了這項代碼,我覺得我的代碼能力提高了很多,對問題的分析有了進一步的提升,即使出現問題,經過不斷的調試,耐心的對待,最后總會成功的。在以后的學習中更要腳踏實地,不怕困難。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/383342.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383342.shtml
英文地址,請注明出處:http://en.pswp.cn/news/383342.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C語言的編譯鏈接過程的介紹

發布時間: 2012-11-08 10:17 作者: 未知 來源: 51Testing軟件測試網采編 字體: 小 中 大 | 上一篇 下一篇 | 打印 | 我要投稿 | 推薦標簽&#xff1a; DotNet 軟件開發 | 感言十年 C語言的編譯鏈接過程要把我們編寫的一個c程序&#xff08;源代碼&#x…

vs2013鏈接Mysql時出現 (由于找不到libmysql.dll,無法繼續執行代碼。重新安裝程序可能會解決此問題)

將MySQL安裝目錄下的lib文件夾中 的libmysql.dll文件拷貝到C:\Windows\System32目錄下即可

gcc 優化選項 -O1 -O2 -O3 -Os 優先級,-fomit-frame-pointer

少優化->多優化&#xff1a; O0 -->> O1 -->> O2 -->> O3 -O0表示沒有優化,-O1為缺省值&#xff0c;-O3優化級別最高 英文解析&#xff1a; -O -O1 Optimize. Optimizing compilation takes somewhat more time, an…

const 和 #define 區別總結

const有類型&#xff0c;可進行編譯器安全檢查&#xff0c;#define 無類型&#xff0c;不可進行類型檢查const 有作用域&#xff0c;而#define 不重視作用域&#xff0c;默認定義在指定作用域下有效的常量&#xff0c;那么#define 就不能用&#xff08;可以用#undef結束宏定義生…

Eclipse : Unresolved inclusion

Eclipse 中新建C 或C 到項目時&#xff0c;頭文件報警&#xff0c;顯示“Unresolved inclusion:<stdio.h>” 雖然不影響項目到編譯和運行&#xff0c;確也無法查看頭文件&#xff0c;讓人感覺實在不爽。下面是在國外到網站上看到解決方案&#xff0c;自己整理了一下拿來分…

c++對const增強 和cosnt分配內存情況

const增強 c語言中const是偽常量&#xff0c;可以通過指針修改 c中const會放到符號表中 c語言中const默認是外部連接&#xff0c;c中const默認是內部鏈接 #include<iostream> using namespace std;const int m_a 10; //在全局區域里&#xff0c;受到保護&…

Linux下crontab命令的用法

任務調度的crond常駐命令 crond 是linux用來定期執行程序的命令。當安裝完成操作系統之后&#xff0c;默認便會啟動此任務調度命令。crond命令每分鍾會定期檢查是否有要執行的工作&#xff0c;如果有要執行的工作便會自動執行該工作。而linux任務調度的工作主要分為以下兩類&am…

c++中引用的作用

引用的基本語法 用途起別名 Type &別名原名 引用必須初始化 一旦初始化后&#xff0c;不能修改 對數組建立引用 #include<iostream>using namespace std;//1.引用基本語法 Type &別名原名void test01(){int a 10;int &b a;cout << "a"…

LVM (Logic Volume Management,邏輯卷管理)

是傳統商業Unix就帶有的一項高級磁盤管理工具&#xff0c;異常強大。后來LVM移植到了Linux操作系統上&#xff0c;盡管不像原來Unix版本那么強大&#xff0c;但瘦死的駱駝比馬大&#xff0c;Linux的LVM仍然非常強大&#xff0c;可以在生產運行系統上面直接在線擴展硬盤分區&…

cpu中的MMU的作用

虛擬內存與物理內存之間的映射 用戶空間映射到物理內存是獨立的&#xff0c;提高安全性修改內存訪問級別 &#xff08;0是最高級&#xff09;

Linux命令行與Shell腳本編程大全讀書筆記

Linux內核4大主要功能&#xff1a; 內存管理 進程管理 設備管理 文件系統管理 Linux系統啟動的進程和腳本管理 1./etc/inittab 管理系統開機時會自動啟動的進程 2./etc/init.d 管理開機時啟動或停止某個應用的腳本放在這個目錄下&#xff0c;/etc/rcX.d目錄在啟動時&…

拷貝構造函數的總結

構造函數的分類及調用 按照參數分類 1.無參構造&#xff08;默認構造&#xff09; 2.有參構造按照類型分類 1.普通構造函數2.拷貝構造函數無參構造寫法和調用 Person p1; 注意不能寫Person (),因為編譯器認為這個是函數聲明有參構造函數寫法 和調用 Person p2(10) 或者Per…

技術與技巧札記

Linux常用命令及技巧&#xff1a; &#xff08;1&#xff09;cat /proc/version 查看當前內核的版本 (2) 掛載nfs文件夾&#xff1a;需要先確認在&#xff0f;etc&#xff0f;exports文件&#xff0c;可以用于開發板掛載的文件夾 mount -o nolock 10.0.22.30:/root/sharednfs …

c++中new的總結(動態管理,malloc存在的問題,malloc與new的區別)

c中使用malloc出現的問題 程序員必須確定對象的長度malloc 返回一個&#xff08;void *&#xff09;指針 &#xff0c;c不允許將&#xff08;void*) 賦值給其它指針&#xff0c;必須強轉malloc可能申請內存失敗&#xff0c;所以必須判斷返回值來保存內存分配成功用戶在使用對象…

Linux中變量#,@,0,1,2,*,$$,$?的含義

$# 是傳給腳本的參數個數 $0 是腳本本身的名字 $1 是傳遞給該shell腳本的第一個參數 $2 是傳遞給該shell腳本的第二個參數 $ 是傳給腳本的所有參數的列表 $* 是以一個單字符串顯示所有向腳本傳遞的參數&#xff0c;與位置變量不同&#xff0c;參數可超過9個 $$ 是腳本運行的當前…

Volatile的陷阱

最近寫的關于在嵌入式開發中常遇到的關于volatile關鍵字使用的短文&#xff0c;都是些通用的技術&#xff0c;貼上來share。 對于volatile關鍵字&#xff0c;大部分的C語言教材都是一筆帶過&#xff0c;并沒有做太過深入的分析&#xff0c;所以這里簡單整理了一些關于volatile的…

c++中靜態成員變量和靜態成員函數

靜態成員變量 在一個類中&#xff0c;若將一個成員變量聲明為static,這種成員成為靜態成員變量&#xff0c;與一般的數據成員不同&#xff0c;無論建立了多少個對象&#xff0c;都只想有一個靜態數據的拷貝&#xff0c;靜態成員變量&#xff0c;屬于某個類&#xff0c;所有對象…

單列模式(餓漢)

單例模式案例 目的&#xff1a;為了讓類中只有一個實例&#xff0c;實例不需要自己釋放將 默認構造 和 拷貝構造 私有化內部維護一個 對象的指針私有化唯一指針對外提供getinstance方法來訪問這個指針保證類中只能實例化唯一 一個對象 主席案例 #include<iostream>usin…

Makefile札記

Makefile中: ? 的區別 在Makefile中我們經常看到 : ? 這幾個賦值運算符&#xff0c;那么他們有什么區別呢&#xff1f;我們來做個簡單的實驗 新建一個Makefile&#xff0c;內容為&#xff1a; ifdef DEFINE_VRE VRE “Hello World!” else endif ifeq ($(OPT),define) VRE…

c++中this指針基本概念和使用

class Person { public:int m_A;//非靜態成員變量&#xff0c;屬于對象上void func(/*Person * this*/){}; //非靜態成員函數 不屬于對象身上static int m_B;//靜態成員函數&#xff0c;不屬于對象上static void fun2(){};//靜態成員函數 &#xff0c;不屬于對象身上//double …