開啟章節選單

10189 Minesweeper

題目連結

題目敘述

你玩過「踩地雷(Minesweeper)」這款小遊戲嗎?這是一款出現在某個作業系統裡的小遊戲(我們一時想不起來是什麼作業系統)
遊戲的目標是在一個 M × N 的格子地圖中,找出所有地雷的位置。為了幫助你,遊戲會在安全格子中顯示一個數字,表示 這個格子周圍(最多 8 個相鄰格子)有多少顆地雷

舉例

假設你有下面這個 4 × 4 的地圖,其中 * 表示地雷, . 表示安全格子:

*........*......

那麼轉換後的地圖應該是這樣:

*100 2210 1 * 10 1110

如上所示,每個安全格子上的數字,就是它周圍八個格子裡地雷的數量(橫、直、斜都算)

輸入說明

輸入包含多個地圖,每張地圖格式如下:
第一行:
n m

  • n是地圖的行數, m 是地圖的列數(保證 0 < n, m ≤ 100
    接下來 n 行,每行剛好 m 個字元,只會包含:
  • * 表示地雷
  • . 表示安全格子
    當讀到 n = 0m = 0 時,表示輸入結束,這一行不需處理

輸出說明

對每張地圖,輸出格式如下:

Field #x : 地圖結果

其中:

  • x 是地圖的編號(從 1 開始編號)
  • 原本是 '.' 的格子,要換成周圍地雷數量(0~8)
  • 原本是 '*' 的格子維持不變
  • 每張地圖輸出後,要空一行,但最後一張輸出後不要再多印空行

解題思路

  1. 定義方向陣列
  2. 讀取地圖
  3. 讀取地圖並先把 . 換成 '0'
  4. 計算每個非地雷格子的周圍地雷數
  5. 輸出地圖

程式碼

#include <bits/stdc++.h>
#define f first
#define s second
using namespace std;
int dir[8][2] = {{1, 0}, {-1, 0}, {0, 1},  {0, -1},
                 {1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
int main() {
  int n, m, field = 0;
  while (cin >> n >> m && n && m) {
    if (field) cout << endl;
    vector<string> vc(n);
    for (int i = 0; i < n; i++) {
      cin >> vc[i];
      for (int j = 0; j < m; j++) {
        if (vc[i][j] == '.') vc[i][j] = '0';
      }
    }
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < m; j++) {
        pair<int, int> p = {i, j};  // 現在座標
        if (vc[p.f][p.s] == '0') {
          for (int k = 0; k < 8; k++) {
            pair<int, int> now = {p.f + dir[k][0],
                                  p.s + dir[k][1]};  // 周圍8個座標
            /*
            . . .
            . x .
            . . .
            */
            if (0 <= now.f && now.f < n && 0 <= now.s &&
                now.s < m) {  // 如果在界內
              if (vc[now.f][now.s] == '*') {
                vc[p.f][p.s] += 1;
              }
            }
          }
        }
      }
    }
    // 輸出
    cout << "Field #" << ++field << ":" << endl;
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < m; j++) {
        cout << vc[i][j];
      }
      cout << endl;
    }
    //
  }
  return 0;
}