zoukankan      html  css  js  c++  java
  • [Swift]LeetCode529. 扫雷游戏 | Minesweeper

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
    ➤微信公众号:山青咏芝(shanqingyongzhi)
    ➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/
    ➤GitHub地址:https://github.com/strengthen/LeetCode
    ➤原文地址:https://www.cnblogs.com/strengthen/p/10408473.html 
    ➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
    ➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

    Let's play the minesweeper game (Wikipediaonline game)!

    You are given a 2D char matrix representing the game board. 'M' represents an unrevealed mine, 'E' represents an unrevealed empty square, 'B' represents a revealed blank square that has no adjacent (above, below, left, right, and all 4 diagonals) mines, digit ('1' to '8') represents how many mines are adjacent to this revealed square, and finally 'X' represents a revealed mine.

    Now given the next click position (row and column indices) among all the unrevealedsquares ('M' or 'E'), return the board after revealing this position according to the following rules:

    1. If a mine ('M') is revealed, then the game is over - change it to 'X'.
    2. If an empty square ('E') with no adjacent mines is revealed, then change it to revealed blank ('B') and all of its adjacent unrevealed squares should be revealed recursively.
    3. If an empty square ('E') with at least one adjacent mine is revealed, then change it to a digit ('1' to '8') representing the number of adjacent mines.
    4. Return the board when no more squares will be revealed. 

    Example 1:

    Input: 
    
    [['E', 'E', 'E', 'E', 'E'],
     ['E', 'E', 'M', 'E', 'E'],
     ['E', 'E', 'E', 'E', 'E'],
     ['E', 'E', 'E', 'E', 'E']]
    
    Click : [3,0]
    
    Output: 
    
    [['B', '1', 'E', '1', 'B'],
     ['B', '1', 'M', '1', 'B'],
     ['B', '1', '1', '1', 'B'],
     ['B', 'B', 'B', 'B', 'B']]
    
    Explanation:
    

    Example 2:

    Input: 
    
    [['B', '1', 'E', '1', 'B'],
     ['B', '1', 'M', '1', 'B'],
     ['B', '1', '1', '1', 'B'],
     ['B', 'B', 'B', 'B', 'B']]
    
    Click : [1,2]
    
    Output: 
    
    [['B', '1', 'E', '1', 'B'],
     ['B', '1', 'X', '1', 'B'],
     ['B', '1', '1', '1', 'B'],
     ['B', 'B', 'B', 'B', 'B']]
    
    Explanation:
    

    Note:

    1. The range of the input matrix's height and width is [1,50].
    2. The click position will only be an unrevealed square ('M' or 'E'), which also means the input board contains at least one clickable square.
    3. The input board won't be a stage when game is over (some mines have been revealed).
    4. For simplicity, not mentioned rules should be ignored in this problem. For example, you don't need to reveal all the unrevealed mines when the game is over, consider any cases that you will win the game or flag any squares.

    让我们一起来玩扫雷游戏!

    给定一个代表游戏板的二维字符矩阵。 'M' 代表一个未挖出的地雷,'E' 代表一个未挖出的空方块,'B' 代表没有相邻(上,下,左,右,和所有4个对角线)地雷的已挖出的空白方块,数字('1' 到 '8')表示有多少地雷与这块已挖出的方块相邻,'X' 则表示一个已挖出的地雷。

    现在给出在所有未挖出的方块中('M'或者'E')的下一个点击位置(行和列索引),根据以下规则,返回相应位置被点击后对应的面板:

    1. 如果一个地雷('M')被挖出,游戏就结束了- 把它改为 'X'。
    2. 如果一个没有相邻地雷的空方块('E')被挖出,修改它为('B'),并且所有和其相邻的方块都应该被递归地揭露。
    3. 如果一个至少与一个地雷相邻的空方块('E')被挖出,修改它为数字('1'到'8'),表示相邻地雷的数量。
    4. 如果在此次点击中,若无更多方块可被揭露,则返回面板。 

    示例 1:

    输入: 
    
    [['E', 'E', 'E', 'E', 'E'],
     ['E', 'E', 'M', 'E', 'E'],
     ['E', 'E', 'E', 'E', 'E'],
     ['E', 'E', 'E', 'E', 'E']]
    
    Click : [3,0]
    
    输出: 
    
    [['B', '1', 'E', '1', 'B'],
     ['B', '1', 'M', '1', 'B'],
     ['B', '1', '1', '1', 'B'],
     ['B', 'B', 'B', 'B', 'B']]
    
    解释:
    

    示例 2:

    输入: 
    
    [['B', '1', 'E', '1', 'B'],
     ['B', '1', 'M', '1', 'B'],
     ['B', '1', '1', '1', 'B'],
     ['B', 'B', 'B', 'B', 'B']]
    
    Click : [1,2]
    
    输出: 
    
    [['B', '1', 'E', '1', 'B'],
     ['B', '1', 'X', '1', 'B'],
     ['B', '1', '1', '1', 'B'],
     ['B', 'B', 'B', 'B', 'B']]
    
    解释:
    

    注意:

    1. 输入矩阵的宽和高的范围为 [1,50]。
    2. 点击的位置只能是未被挖出的方块 ('M' 或者 'E'),这也意味着面板至少包含一个可点击的方块。
    3. 输入面板不会是游戏结束的状态(即有地雷已被挖出)。
    4. 简单起见,未提及的规则在这个问题中可被忽略。例如,当游戏结束时你不需要挖出所有地雷,考虑所有你可能赢得游戏或标记方块的情况。

    388ms

     1 class Solution {
     2       func updateBoard(_ board: [[Character]], _ click: [Int]) -> [[Character]] {
     3           var board = board
     4           return coreUpdateBoard(&board, click)
     5       }
     6     func coreUpdateBoard(_ board: inout [[Character]], _ click: [Int]) -> [[Character]] {
     7         let m = board.count, n = board[0].count
     8         let row = click[0], col = click[1]
     9 
    10         if board[row][col] == "M" {
    11             board[row][col] = "X"
    12         }
    13         else { // Empty
    14             // Get number of mines first.
    15             var count = 0
    16             for i in -1..<2 {
    17                 for j in -1..<2 {
    18                     if i == 0 && j == 0 {
    19                         continue
    20                     }
    21                     let r = row + i, c = col+j
    22                     if r<0 || r>=m || c<0 || c>=n {
    23                         continue
    24                     }
    25 
    26                     if board[r][c] == "M" || board[r][c] == "X" {
    27                         count += 1
    28                     }
    29                 }
    30             }
    31 
    32             if count > 0 { 
    33                 // If it is not a 'B', stop further DFS.
    34                 board[row][col] = Character("(count)")
    35             }
    36             else {
    37                 // Continue DFS to adjacent cells.
    38                 board[row][col] = "B"
    39                 for i in -1..<2 {
    40                     for j in -1..<2 {
    41                         if i == 0 && j == 0 {
    42                             continue
    43                         }
    44                         let r = row+i, c = col + j
    45                         if r<0 || r>=m || c<0 || c>=n {
    46                             continue
    47                         }
    48                         if board[r][c] == "E" {
    49                             coreUpdateBoard(&board, [r,c])
    50                         }
    51                     }
    52                 }
    53             }
    54         }
    55         return board
    56     }
    57 }

    392ms

     1 class Solution {
     2     let dirs: [(Int, Int)] = [(0, 1), (0, -1), (1, 0), (-1, 0), (1, 1), (1, -1), (-1, 1), (-1, -1)]
     3     
     4     func updateBoard(_ board: [[Character]], _ click: [Int]) -> [[Character]] {
     5         var board: [[Character]] = board
     6         let x = click[0]
     7         let y = click[1]
     8         if board[x][y] == "M" {
     9             board[x][y] = "X"
    10             return board
    11         }
    12         dfs(&board, x, y)
    13         return board
    14     }
    15     
    16     func dfs(_ board: inout [[Character]], _ x: Int, _ y: Int) {
    17         if x < 0 || x >= board.count || y < 0 || y >= board[0].count || board[x][y] != "E" {
    18             return 
    19         }
    20         let mineCount = numberOfMines(&board, x, y)
    21         if mineCount == 0 {
    22             board[x][y] = "B"
    23             for d in dirs {
    24                 dfs(&board, x + d.0, y + d.1)
    25             }
    26         } else {
    27             board[x][y] = Character(String(mineCount))
    28         }
    29     }
    30     
    31     func numberOfMines(_ board: inout [[Character]], _ x: Int, _ y: Int) -> Int {
    32         var count = 0
    33         for d in dirs {
    34             let newX = x + d.0
    35             let newY = y + d.1
    36             if newX < 0 || newX >= board.count || newY < 0 || newY >= board[0].count {
    37                 continue
    38             }
    39             if board[newX][newY] == "M" || board[newX][newY] == "X" {
    40                 count += 1
    41             }
    42         }
    43         return count
    44     }
    45 }

    Runtime: 396 ms
    Memory Usage: 20.4 MB
     1 class Solution {
     2     func updateBoard(_ board: [[Character]], _ click: [Int]) -> [[Character]] {
     3         if board.isEmpty || board[0].isEmpty {return []}
     4         var board = board
     5         var m:Int = board.count
     6         var n:Int = board[0].count
     7         var q:[[Int]] = [[click[0], click[1]]]
     8         while(!q.isEmpty)
     9         {
    10             var row:Int = q.first![0]
    11             var col:Int = q.first![1]
    12             var cnt:Int = 0
    13             q.removeFirst()
    14             var neighbors:[[Int]] = [[Int]]()
    15             if board[row][col] == "M"
    16             {
    17                 board[row][col] = "X"
    18             }
    19             else
    20             {
    21                 for i in -1..<2
    22                 {
    23                     for j in -1..<2
    24                     {
    25                         var x:Int = row + i
    26                         var y:Int = col + j
    27                         if x < 0 || x >= m || y < 0 || y >= n
    28                         {
    29                             continue
    30                         }
    31                         if board[x][y] == "M"
    32                         {
    33                             cnt += 1
    34                         }
    35                         else if cnt == 0 && board[x][y] == "E"
    36                         {
    37                             neighbors.append([x, y])
    38                         }
    39                     }
    40                 }
    41             }
    42             if cnt > 0 
    43             {
    44                 board[row][col] = (cnt + 48).ASCII
    45             }
    46             else
    47             {
    48                 for a in neighbors
    49                 {
    50                     board[a[0]][a[1]] = "B"
    51                     q.append(a)
    52                 }
    53             }
    54         }
    55         return board
    56     }
    57 }
    58 
    59 extension Int
    60 {
    61     //属性:ASCII值(定义大写为字符值)
    62     var ASCII:Character 
    63     {
    64         get {return Character(UnicodeScalar(self)!)}
    65     }
    66 }

    412ms

     1 class Solution {
     2     func updateBoard(_ board: [[Character]], _ click: [Int]) -> [[Character]] {
     3       let rows = board.count, cols = board[0].count
     4       var currentTuple: (Int, Int) = (click[0], click[1])
     5       var board = board
     6     
     7       var queue = [currentTuple]
     8 
     9       while !queue.isEmpty {
    10         let (currX, currY) = queue.popLast()!
    11 
    12         if board[currX][currY] == "M" {
    13           board[currX][currY] = "X" // Game over!
    14         } else {
    15 
    16           // Get total number of mines surrounding the square
    17           var count = 0
    18 
    19           for (dx, dy) in [(1, 0), (0, 1), (-1, 0), (0, -1), (1, 1), (-1, -1), (1, -1), (-1, 1)] {
    20             let (nextX, nextY) = (dx + currX, dy + currY)
    21             if nextX >= 0 && nextX < rows && nextY >= 0 && nextY < cols {
    22               if ["M", "X"].contains(board[nextX][nextY]) {
    23                 count += 1
    24               }
    25             }
    26           }
    27 
    28           if count > 0 {
    29             // Terminate search
    30             board[currX][currY] = Character.init("(count)")
    31           } else {
    32             // Else, perform BFS search
    33             board[currX][currY] = "B"
    34 
    35             for (dx, dy) in [(1, 0), (0, 1), (-1, 0), (0, -1), (1, 1), (-1, -1), (1, -1), (-1, 1)] {
    36               let (nextX, nextY) = (dx + currX, dy + currY)
    37               if nextX >= 0 && nextX < rows && nextY >= 0 && nextY < cols {
    38                 if ["E"].contains(board[nextX][nextY]) {
    39                   queue.append((nextX, nextY))
    40                   board[nextX][nextY] = "B"
    41                 }
    42               }
    43             }
    44           } 
    45         } 
    46       }
    47       return board
    48    }
    49 }

    628ms

     1         reveal(board: &board, i:click[0], j:click[1])
     2         return board
     3         
     4     }
     5     
     6     func reveal(board: inout [[Character]], i:Int, j:Int) {
     7         switch (String(board[i][j])) {
     8             case "M":
     9                 board[i][j] = Character("X")
    10                 break
    11             case "E":
    12             if (adjacencies[i][j] == 0) {
    13                 board[i][j] = Character("B")
    14                 directions.forEach { dir in
    15             let (y, x) = dir
    16             if isValid(i:y + i, j: x + j)  {
    17                 reveal(board: &board, i: y + i, j:x + j)
    18             }
    19         }
    20                 break
    21             } else {
    22                 
    23                 board[i][j] = Character(String(adjacencies[i][j]))
    24             }
    25                 
    26             default:
    27             break
    28         }
    29     }
    30     
    31     func setAdjacency(_ board: [[Character]], i: Int, j: Int) {
    32         var adjacency = 0
    33         directions.forEach { dir in
    34             let (y, x) = dir
    35             if isValid(i:y + i, j: x + j) && board[y + i][x + j] == "M" {
    36                 adjacency += 1
    37             }
    38         }
    39         adjacencies[i][j] = adjacency
    40           
    41     }
    42     
    43     func isValid(i:Int, j:Int) -> Bool {
    44         return i < m && i >= 0 && j >= 0 && j < n 
    45     }
    46 }
  • 相关阅读:
    IO操作之BIO、NIO、AIO
    IO之Socket网络编程
    this.getClass()和super.getClass()得到的是同一个类
    经济增长的背后
    SVN分支创建与合并
    .net类库里ListView的一个BUG
    VS2010调试技巧
    用C#代码编写的SN快速输入工具
    请教如何改善C#中socket通信机客户端程序的健壮性
    利用WebClient实现对Http协议的Post和Get对网站进行模拟登陆和浏览
  • 原文地址:https://www.cnblogs.com/strengthen/p/10408473.html
Copyright © 2011-2022 走看看