一起刷LeetCode——扫雷游戏(DFS/BFS)

53 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第25天,点击查看活动详情

扫雷游戏

给你一个大小为 m x n 二维字符矩阵 board ,表示扫雷游戏的盘面,其中:

'M' 代表一个 未挖出的 地雷, 'E' 代表一个 未挖出的 空方块, 'B' 代表没有相邻(上,下,左,右,和所有4个对角线)地雷的 已挖出的 空白方块, 数字('1' 到 '8')表示有多少地雷与这块 已挖出的 方块相邻, 'X' 则表示一个 已挖出的 地雷。 给你一个整数数组 click ,其中 click = [clickr, clickc] 表示在所有 未挖出的 方块('M' 或者 'E')中的下一个点击位置(clickr 是行下标,clickc 是列下标)。

根据以下规则,返回相应位置被点击后对应的盘面:

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

来源:力扣(LeetCode) 链接:leetcode.cn/problems/mi…

分析

  • 经典的游戏,规则也都比较清楚
  • 点击一个方块,逐渐向外扩散,点击的方块是地雷就改为X,如果是空方块,统计数量然后修改数字,如果是0,那就改为B,然后递归的处理方块周围没有挖出的方块,注意一定是没有挖出来的方块
  • 递归的处理可以是DFS也可以是BFS
  • 当遍历点击方块周围的方块时,可以通过定义一组坐标来表示八个方向,在涉及到方向的时候经常使用这种表示方向的坐标数组来遍历某个元素周围的元素
let directions = [    [-1,0],
    [-1,1],
    [0,1],
    [1,1],
    [1,0],
    [1,-1],
    [0,-1],
    [-1,-1]
]

DFS

var updateBoard = function(board, click) {
    let directions = [        [-1,0],
        [-1,1],
        [0,1],
        [1,1],
        [1,0],
        [1,-1],
        [0,-1],
        [-1,-1]
    ]
    if(!board.length) return board;
    let row = click[0]
    let col = click[1]
    let currentSquareVal = board[row][col]
    if(currentSquareVal == 'M'){
        board[row][col] ='X'
        return board
    }
    
    function dfs(r,c){
        let current = board[r][c]
        if(current !== 'E'){
            return
        }
        
        let mines = getMines(r,c)
        if(mines>0){
            board[r][c] = mines.toString()
            return
        }else{
            board[r][c] = 'B'
        }
        
        for(let i =0;i<directions.length;i++){
            let newRow = directions[i][0] + r;
            let newCol = directions[i][1] + c;
            if(checkRange(newRow,newCol)){
                dfs(newRow,newCol)
            }
        }
    }
    
    
    var checkRange = function(newrow,newcol){
        return newrow>=0 && newrow<board.length && newcol>=0 && newcol<board[0].length
    } 
    
    var getMines = function(r,c){
        let mines = 0;
        for(let i =0;i<directions.length;i++){
            let newRow = directions[i][0] + r;
            let newCol = directions[i][1] + c;
            if(checkRange(newRow,newCol)){
                if(board[newRow][newCol] == "M") mines++
            }
            
        }
        return mines
    }
    dfs(row,col)
    return board
}

BFS

var updateBoard = function(board, click) {
let directions = [
    [-1,0],
    [-1,1],
    [0,1],
    [1,1],
    [1,0],
    [1,-1],
    [0,-1],
    [-1,-1]
]
    let row = click[0];
    let col = click[1]
    let currentSquare = board[row][col]
    if(currentSquare == 'M'){
        board[row][col] ='X'
        return board
    }else if(currentSquare == 'E'){
        let seenArray = new Array(board.length).fill(0)
        seenArray = seenArray.map(()=> new Array(board[0].length).fill(false));
        let queue =[click]
        while(queue.length){
            let currentSquare = queue.shift();
            let mineCount = 0;
            let tempQueue = []
            //looping in directions array
            for(let i =0;i<directions.length;i++){
                let newRow = directions[i][0] + currentSquare[0];
                let newCol = directions[i][1] + currentSquare[1];
                if(newRow>=0 && newRow<board.length && newCol>=0 && newCol<board[0].length  ){
                    let newSquare = board[newRow][newCol];
                    if(newSquare == 'M'){
                        mineCount++
                    }else if(newSquare == 'E'){
                        tempQueue.push([newRow,newCol])
                    }else{
                        continue
                    }
                }
            }

            //changing currentSquare's value
            if(mineCount>0){
                board[currentSquare[0]][[currentSquare[1]]] = mineCount.toString()
            }else{
                board[currentSquare[0]][[currentSquare[1]]] = 'B';
                tempQueue.forEach((each)=>{
                    if(!seenArray[each[0]][each[1]]){
                        queue.push(each)
                        seenArray[each[0]][each[1]] = each
                    }
                })
            }
        }
        
    }
    return board;
};

总结

  • 本题是经典的扫雷游戏的题目,难度等级为中等,因为玩过所以规则理解起来也相对简单,早期的游戏是算法相对直接的表现,现在的游戏可能一个交互涉及到一些通过基础算法封装的高级算法,比如很多大型游戏都会有的寻路算法,算法的不算升级也让游戏的交互有了一定的提升
  • 今天也是有收获的一天