Try   HackMD

2023 交大電機營 程式遊戲實作 踩地雷


聽完前面兩個講師的課,相信大家也都變超強的啦~
現在就來挑戰自己,完成下面的踩地雷小遊戲吧!

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →


被挖空的程式碼

將下面程式碼的 11題空格填入正確的答案

#include <assert.h> #include <string.h> #include <conio.h> #include <unistd.h> #include <iostream> #include <cstdlib> #include <ctime> #include <queue> #include <iomanip> using namespace std; void CleanScreen(); //清空螢幕 void output(int graph[8][8], int vis[8][8], int, int, int, int); //輸出 int check_position(int graph[8][8], int, int); //檢查該區塊情形 int bomb_around(int graph[8][8], int, int); //數九宮格內地雷個數 // 不用看懂這個函數 // Clean up the Screen void CleanScreen() { #ifdef _WIN32 system("cls"); #else system("clear"); #endif } //輸出踩地雷地圖 (每個區塊有 地雷 / 旗標 / 已經點開 三種情形) void output(int graph[8][8], int vis[8][8], int mined_cnt, int flag_cnt, int cursor_row, int cursor_col) { cout << "\033[1;32;45m "; for (int j = 0; j < 8; j++) cout << setw(3) << j; //輸出直行編號 cout << "\033[0m\n"; for (int i = 0; i < 8; i++) { //i 標註 row 編號 cout << "\033[1;32;45m" << setw(3) << i << "\033[0m";//輸出橫列編號 for (int j = 0; j < 8; j++) { //j 標註 col 編號 if (___1___) //判斷是否為游標所在區塊 cout << "\033[5;44m"; //文字閃爍 if (vis[i][j] == 0) cout << " - " << "\033[0m"; //未知區塊 else if (vis[i][j] == 1) { //已點開的區塊(可顯示實際值) if (___2___) cout << "\033[1;31m" << " * " << "\033[0m"; //是地雷 else cout << ' ' << graph[i][j] << ' ' << "\033[0m"; //不是地雷(數字代表周遭九宮格內地雷數 } else if (vis[i][j] == 2) cout << "\033[1;36m" << " $ " << "\033[0m"; //旗幟標示 cout << "\033[0m"; //恢復為cout預設型態 } cout << '\n'; } //輸出目前 點開的區塊數量 / 旗幟標示的數量 cout << "\033[1;33m\n" << "mined places: " << mined_cnt << " /" << 8 * 8 - 10 << '\t' << "flagged bombs: " << flag_cnt << " /" << 10 << "\033[0m\n"; return; } //檢查graph[row][col] int check_position(int graph[8][8], int row, int col) { if (___3___) //不合法的情形 return 0; //不做事 >> 直接回傳0 if (graph[row][col] == -1) return 1; //地雷 >> 回傳1 if (graph[row][col] == 0) return 2; //周圍都沒地雷 >> 回傳2 return 3; //其他 (自己不是地雷,九宮格內有地雷) >> 回傳3 } //計算九宮格內有幾顆地雷(自己不是) int bomb_around(int graph[8][8], int row, int col) { int bomb_num = 0; for (___4.1___) { //檢查上下及自己三個row for (___4.2___) { //檢查左右及自己三個col if (i == 0 && j == 0) continue; if (___5___) bomb_num++; //是地雷 >> bomb_num+1 } } return bomb_num; } int main() { /* * 變數簡介 * graph[][]: 踩地雷地圖 * vis[][]: 紀錄區塊造訪/標示情形 * mined_cnt: 已經點開的合法區塊數 * flag_cnt: 旗幟標示的區塊數 * cursor_row:游標所在列 * cursor_col:游標所在行 */ int graph[8][8] = {0}, vis[8][8] = {0}; int mined_cnt = 0, flag_cnt = 0; int cursor_row = 0, cursor_col = 0; srand(time(NULL)); CleanScreen(); output(graph, vis, mined_cnt, flag_cnt, cursor_row, cursor_col); //開始踩地雷 bool fail = false; while (___6___) { //當 點開區塊數 = 總區塊數-地雷數 >> 成功; char ch = '\0'; //CleanScreen(); //output(graph, vis, mined_cnt, flag_cnt, cursor_row, cursor_col); while (ch == '\0') ch = getch(); if ((ch == 'w' || ch == 72) && check_position(graph, cursor_row - 1, cursor_col)) ___7.1___; // 上 else if ((ch == 's' || ch == 80) && check_position(graph, cursor_row + 1, cursor_col)) ___7.2___; // 下 else if ((ch == 'a' || ch == 75) && check_position(graph, cursor_row, cursor_col - 1)) ___7.3___; // 左 else if ((ch == 'd' || ch == 77) && check_position(graph, cursor_row, cursor_col + 1)) ___7.4___; // 右 else if (ch == 'j') { //點開區塊 if (mined_cnt == 0) { //第一次點開區塊,建立踩地雷地圖 for (int i = 0; i < 10; i++) {//填地雷 int pos = ___8___; //產生一個 0 ~ 63 的隨機變數 bool clr_cursor = (pos/8-cursor_row <= 1 && pos/8-cursor_row >= -1); clr_cursor &= (pos%8-cursor_col <= 1) && (pos%8-cursor_col >= -1); while (graph[pos/8][pos%8] == -1 || clr_cursor) { pos = ___8___; //產生一個 0 ~ 63 的隨機變數 clr_cursor = (pos/8-cursor_row <= 1 && pos/8-cursor_row >= -1); clr_cursor &= (pos%8-cursor_col <= 1) && (pos%8-cursor_col >= -1); } graph[pos/8][pos%8] = -1; } //計算每個區塊的數字 for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { if (graph[i][j] == 0) graph[i][j] = ___9___; //計算周遭地雷數 } } //踩地雷建圖完成 } if (vis[cursor_row][cursor_col]) continue; //已經點開/ 標示旗幟之區塊 else if (graph[cursor_row][cursor_col] == -1) { //踩到地雷 for (int t = 0; t < 8 * 8; t++) vis[t/8][t%8] = 1; //標記整張圖都被點開 fail = true; //標記已經踩到地雷 } else if (graph[cursor_row][cursor_col] > 0) { //周圍九宮格內有地雷 >> 只挖開一格 vis[cursor_row][cursor_col] = 1; ___10___; //更新挖開區塊數 } else { //點開區塊周圍九宮格沒有地雷 // BFS (不用懂這裡) queue<int> save; save.push(cursor_row * 8 + cursor_col); while (save.size()) { int cur = save.front(); int cur_row = cur / 8, cur_col = cur % 8; save.pop(); if (vis[cur_row][cur_col]) continue; cursor_row = cur_row; cursor_col = cur_col; vis[cur_row][cur_col] = 1; mined_cnt++; if (check_position(graph, cur_row, cur_col) == 2) { for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (i == 0 && j == 0) continue; if (check_position(graph, cur_row+i, cur_col+j) > 1 && !vis[cur_row+i][cur_col+j]) save.push((cur_row+i) * 8 + (cur_col + j)); } } } } // end BFS } } else if (ch == 'k') { //標示旗幟 if (vis[cursor_row][cursor_col] == 0) { //原本沒被標示旗幟 vis[cursor_row][cursor_col] = 2, flag_cnt++; } else if (vis[cursor_row][cursor_col] == 2) { //原本有標示旗幟 vis[cursor_row][cursor_col] = 0, flag_cnt--; } } CleanScreen(); output(graph, vis, mined_cnt, flag_cnt, cursor_row, cursor_col); if (fail) { //踩到地雷 cout << "\033[1;5;31m\n\t\t" << "Stepped on bomb!!" << "\033[0m\n"; break; } } //成功結束 >> 輸出 "\\ You Win ! //" if (!fail) cout << "\033[1;5;32m\n\t\t" << ___11___ << "\033[0m\n"; cout << "\033[0m" << "\n\nPress 'c' to leave\n"; char get_end; while (get_end = getch()) { if (get_end == 'c') break; } return 0; }

題目 Part 1. 選填題

作答的過程中,記得把選了甚麼選項記下來唷 !
就算你超有自信,覺得自己選的一定是對的直接填進就沒問題也一樣,等等需要對答案 !


Problem 1. 判斷目前要輸出的區塊是不是游標所在的位置

for (int j = 0; j < 8; j++) cout << setw(3) << j; //輸出直行編號 cout << "\033[0m\n"; for (int i = 0; i < 8; i++) { //i 表示 row 編號 cout << "\033[1;32;45m " << setw(3) << i << "\033[0m"; //輸出橫列編號 for (int j = 0; j < 8; j++) { //j 表示 col 編號 if (__1__) //判斷是否為游標所在區塊 cout << "\033[5;44m"; //文字閃爍 ... } }

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
選項 >> 只有一個是對的喔!

A ) i == cursor_row && j == cursor_col
B ) j == cursor_row && i == cursor_col
C ) i == cursor_row || j == cursor_col
D ) j == cursor_row || i == cursor_col


Problem 2. 判斷是不是地雷
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

else if (vis[i][j] == 1) { //已經被點開的區塊 if ( _2_ ) cout << "\033[1;31m" << " * " << "\033[0m"; //是地雷 else cout << ' ' << graph[i][j] << ' ' << "\033[0m"; //不是地雷 }

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
選項 >> 一樣只有一個對的喔~

A ) graph[i][j] == 1
B ) graph[i][j] == 0
C ) graph[i][j] == -1
D ) vis[i][j] == -1


Problem 3. 檢查位置的合法性

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Hint:[row][col] 代表的位置不可以超出地圖的範圍

int check_position (int graph[8][8], int row, int col) { if ( _3_ ) //不合法的情形 return 0; //不做事 >> 直接回傳0 ...

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
選項 >> 不用懷疑,還是只有一個對的
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

A ) (row < 0 && row >= 8) || (col < 0 && col >= 8)
B ) (row < 0 || row >= 8) && (col < 0 || col >= 8)
C ) row < 0 && row >= 8 && col < 0 && col >= 8
D ) row < 0 || row >= 8 || col < 0 || col >= 8


Problem 4. 計算自己周圍九宮格內的地雷數

for ( _4.1_ ) { //檢查上下及自己的三個 row for ( _4.2_ ) { //檢查左右及自己的三個 col if (i == 0 && j == 0) continue; if (...) bomb_num++; //檢查是地雷 >> bomb_num+1 } }
O O O
O C O
O O O

如上面表格的情形,自己是C位,要計算周遭標示O的區塊總共有幾個地雷

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
選項 >> 這題水一點,有兩個選項正確

​​​​ _4.1_ / _4.2_

A ) int i = -1; i <= 1; i++ / int j = -1; j <= 1; j++
B ) int i = 0; i <= 2; i++ / int j = 0; j <= 1; j++
C ) int i = 1; i >= -1; i-- / int j = 1; j >= -1; j--
D ) int i = 2; i >= 0; i-- / int j = 2; j >= 0; j--


Problem 5. 檢查是不是地雷

for (...) { for (...) { if (i == 0 && j == 0) continue; if ( _5_ ) bomb_num++; //如果檢查是炸彈 >> bomb_num+1 } }

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
選項 >> 這題送你,只有一個選項 (絕對不是因為課程組掰不出來)

A ) check_position (graph, row+i, col+j) == 1


Problem 6. while loop 中止條件(成功結束時)

bool fail = false; while ( _6_ ) { //當 點開區塊數 = 總區塊數-地雷數 >> 成功 char ch = '\0'; ...

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Hint: 當 點開區塊數 = 總區塊數 - 總炸彈數 >> 成功結束

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
選項 >> 只有一個是正確的喔

A ) 1
B ) 0
C ) mined_cnt < 8 * 8 - 10
D ) mined_cnt < 10


Problem 7. 上下左右鍵

if ((ch == 'w' || ch == 72) && ... ) _7.1_ ; //上 else if ((ch == 's' || ch == 80) && ... ) _7.2_ ; //下 else if ((ch == 'a' || ch == 75) && ... ) _7.3_ ; //左 else if ((ch == 'd' || ch == 77) && ... ) _7.4_ ; //右

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
選項 >> 四個子題共用下列的選項

​​​​作答形式: _7.1 / _7.2_ / _7.3_ / _7.4_ 

A ) cursor_col++
B ) cursor_row++
C ) cursor_col--
D ) cursor_row--


Problem 8. 隨機變數產生

for (int i = 0; i < 10; i++) {//填地雷 int pos = ___8___; //產生一個 0 ~ 63 的隨機變數 bool clr_cursor = (pos/8-cursor_row <= 1 && pos/8-cursor_row >= -1); clr_cursor &= (pos%8-cursor_col <= 1) && (pos%8-cursor_col >= -1); while (graph[pos/8][pos%8] == -1 || clr_cursor) { pos = ___8___; //產生一個 0 ~ 63 的隨機變數 clr_cursor = (pos/8-cursor_row <= 1 && pos/8-cursor_row >= -1); clr_cursor &= (pos%8-cursor_col <= 1) && (pos%8-cursor_col >= -1); } graph[pos/8][pos%8] = -1; }

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Hint: 隨機產生一個 0 ~ 63 的整數
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Hint: 常數 RAND_MAX 為函數 rand() 能產出的最大值

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
選項 >> 有兩個是對的喔 (程式裡面兩個標示 _ 8 _ 的地方是一樣的東西

A ) (int) ((double) rand()%RAND_MAX / 64)
B ) (int) ((double) rand()/RAND_MAX * 8 * 8)
C ) rand() % 64
D ) rand() / 64


Problem 9. 呼叫函式計算周遭的地雷數

//計算每個區塊的數字 for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { if (graph[i][j] == 0) graph[i][j] = ___9___; //計算周遭地雷數 } //踩地雷建圖完成 }

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
選項 >> 只有一個是正確的喔

A ) output (graph, vis, mined_cnt, flag_cnt, cursor_row, cursor_col)
B ) check_position (graph, cursor_row, cursor_col)
C ) bomb_around (graph, cursor_row, cursor_col)
D ) bomb_around (graph, i, j)


Problem 10. 紀錄挖開的區塊數

else if (graph[cursor_row][cursor_col] > 0){ //九宮格內有地雷 >> 只挖開一格 vis[cursor_row][cursor_col] = 1; _10_ ; //更新挖開區塊數 }

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
選項 >> 有兩個是正確的喔

A ) flag_cnt++
B ) mined_cnt++
C ) flag_cnt += 1
D ) mined_cnt = mined_cnt+1


Problem 11. 超難題

題目敘述:

恭喜玩家終於成功解開整張地圖都沒踩到地雷!
請在螢幕上輸出 "\\ You win ! //" 的字樣 (輸出在螢幕上時沒有雙引號)

_ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
注意: 輸出 \\ You win ! // 完不用自己加換行

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Hint: 可以自己開一個 cpp 檔案試著輸出上面的字串喔!

//成功結束 >> 輸出 "\\ You Win ! //" if (!fail) cout << "033[1;5;32m" << _11_ << "033[0m\n";

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
選項 >> 因為是超難題所以就沒有選項啦
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

直接寫出 __ 11 __ 內該寫入什麼程式碼喔


作答完成

寫完上面11題的答案之後,記得給學長姐們確認過答案,再把答案打入你的程式檔喔!


題目 Part 2. 程式改寫

能做到這真的已經超強了!

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

接下來試著把踩地雷程式做出以下改變:

  1. 8*8的地圖 變成 16*16的地圖
  2. 10顆地雷 變成 40顆地雷

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Hint: 附上一張貓貓給你能量

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

如果你真的卡住了的話,可以看一下下面巨有料的影片喔!!

  • 影片 1 -
    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

寫完之後就可以玩踩地雷遊戲囉!