SwiftUI数独生成器运行报错:数组索引越界
数独游戏索引越界错误分析与修复
可能的错误原因
- 视图初始化时访问空数组:你的
EnigmaViewModel中grid初始值是空数组[],而SwiftUI视图会在generateSudoku调用前就开始渲染。如果视图中用了ForEach(0..<9)这类循环去访问grid[row][col],此时grid是空的,访问grid[row]会直接触发索引越界。 - 生成器方法中的索引逻辑错误:
SudokuGenerator的fillRemaining或removeKDigits方法可能存在索引超出0-8范围的情况:fillRemaining递归过程中,计算下一个填充位置时可能错误地让i或j超过8;removeKDigits随机选择单元格时,可能生成了0-8以外的索引(比如误用了1...9的范围)。
修复方法
1. 初始化视图模型的grid为合法的9x9数组
修改EnigmaViewModel的grid初始值,确保视图渲染时数组是合法的9x9结构:
class EnigmaViewModel: ObservableObject { // 初始化为9x9的空数独网格,而非空数组 @Published var grid: [[Int]] = Array(repeating: Array(repeating: 0, count: 9), count: 9) let difficulty = Difficulty.easy func generateSudoku() { let generator = SudokuGenerator() self.grid = generator.generateGrid(k: 20) } }
2. 检查并修正生成器中的索引逻辑
验证fillRemaining的边界处理
确保fillRemaining的递归终止条件和位置计算正确,示例参考:
func fillRemaining(i: Int, j: Int) -> Bool { var row = i var col = j // 移动到下一个位置的逻辑,确保row和col不超过8 if col >= 9 { row += 1 col = 0 if row >= 9 { return true // 填充完成 } } // 跳过对角线已填充的单元格 if (row < 3 && col < 3) || (row >=3 && row <6 && col >=3 && col <6) || (row >=6 && col >=6) { return fillRemaining(i: row, j: col + 1) } // 尝试填充1-9的数字 for num in 1...9 { if isSafe(row: row, col: col, num: num) { grid[row][col] = num if fillRemaining(i: row, j: col + 1) { return true } grid[row][col] = 0 // 回溯 } } return false }
核心是确保每次递归的row和col始终在0-8范围内。
修正removeKDigits的随机索引生成
确保随机选择的行和列是0到8的范围:
func removeKDigits(k: Int) { var count = k while count > 0 { let row = Int.random(in: 0..<9) let col = Int.random(in: 0..<9) // 避免重复移除同一个单元格 if grid[row][col] != 0 { grid[row][col] = 0 count -= 1 } } }
这里必须用0..<9而不是1...9,因为Swift数组索引从0开始。
3. 临时调试技巧
在访问grid的地方加安全判断,快速定位问题位置:
// 视图中访问grid时先检查边界 if row < grid.count && col < grid[row].count && grid[row][col] != 0 { // 执行逻辑 }
内容的提问来源于stack exchange,提问作者Richie
相关产品推荐
相关产品推荐

