You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin扫雷项目setMines()方法疑似无限循环致运行超时

扫雷项目15秒超时无限循环问题修复

报错信息

项目运行时触发测试超时:

In this test, the program is running for a long time, more than 15 seconds. Most likely, the program has gone into an infinite loop.

核心故障点

你推测的setMines()确实是死循环主要触发点,同时代码中存在多处配套逻辑错误共同导致异常:

  • 随机数范围错误:Random.nextInt(0, SIZE - 1)的上界是排他值,SIZE=9时上界传8,实际生成的坐标范围是0~7,永远取不到最后一行/列的坐标8,可放雷位置从81个缩减到64个。
  • 安全区判断逻辑错误:放雷时排除首次点击位置的条件写为x != notMine["x"] && y != notMine["y"],会排除所有和首次点击同x或同y的整行整列格子,可放雷位置进一步缩减,当用户输入雷数大于剩余可放位置数时,循环永远找不到符合条件的空位,minesToSet无法递减到0,直接触发死循环。
  • 集合引用错误:markedCells、unExploredCells直接赋值为mines,三个变量指向同一个Set对象,后续标记、探索操作会直接篡改地雷集合,导致胜负判断、放雷逻辑完全混乱。
  • 辅助逻辑错误:toggleMarking中多余的y坐标偏移、notHasMinesAround()返回值写反、空白格探索仅展开一层不递归,都会导致游戏逻辑异常,间接触发循环无法退出。

无死循环的地雷放置实现

替换原有随机重试的放雷逻辑,采用「合法位置预生成+洗牌取位」方案,从根源上避免随机重复选点导致的无限循环,时间复杂度更稳定:

private fun setMines() {
    // 预先生成所有允许放雷的坐标,仅排除首次点击的单个格子
    val availablePositions = mutableListOf<Pair<Int, Int>>()
    val safeX = notMine["x"]
    val safeY = notMine["y"]
    for (x in 0 until SIZE) {
        for (y in 0 until SIZE) {
            if (x != safeX || y != safeY) {
                availablePositions.add(x to y)
            }
        }
    }
    // 洗牌后直接取前N个位置放雷,不存在重复选点问题
    availablePositions.shuffle()
    val minePositions = availablePositions.take(numberOfMines)

    // 批量设置地雷与周围数字
    for ((x, y) in minePositions) {
        val cell = this[x][y]
        cell.makeMine()
        mines.add(cell)
        // 遍历3x3邻域更新数字
        for (row in x - 1..x + 1) {
            for (col in y - 1..y + 1) {
                if (row in 0 until SIZE && col in 0 until SIZE) {
                    this[row][col].add()
                }
            }
        }
    }
}

必须同步修复的配套问题

  • 修正集合初始化,三个集合独立创建,不要引用同一个对象:
    private val mines = mutableSetOf<Cell>()
    private val markedCells = mutableSetOf<Cell>()
    private val unExploredCells = mutableSetOf<Cell>()
    
  • 删除toggleMarking函数中多余的val y = y - 1行,传入坐标已提前做过偏移处理。
  • 修正Cell类中周围雷数判断逻辑:
    fun notHasMinesAround(): Boolean = number == 0
    
  • 修正空白格探索逻辑,改为递归展开所有连通的无雷空白格:
    fun explore(x: Int, y: Int) {
        val cell = this[x][y]
        if (cell.isExplored || cell.isMarked) return
        cell.explore()
        unExploredCells.remove(cell)
        // 仅当当前格周围无雷时,才递归展开邻域格子
        if (cell.isNotMine() && cell.notHasMinesAround()) {
            for (row in x - 1..x + 1) {
                for (col in y - 1..y + 1) {
                    if (row in 0 until SIZE && col in 0 until SIZE && (row != x || col != y)) {
                        explore(row, col)
                    }
                }
            }
        }
    }
    
  • 调整main函数流程,删除第一次输入前多余的println(Board(SIZE)),避免打印未初始化的空棋盘。

内容的提问来源于stack exchange,提问作者halotukozak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 19:01:17