JavaScript开发4x4摩天大楼谜题时place函数数组填充异常求助
问题排查结果
问题1:place函数向tab数组插入0值的原因
从提供的place函数代码可直接定位到以下问题点:
- 冗余的0赋值逻辑:
- 当
colnline_has_no_double校验不通过时,会直接执行tab[x][y] = 0 - for循环全部执行完成后,无论校验结果如何,又执行了一遍
tab[x][y] = 0,递归回溯时会直接把之前填入的有效值覆盖为0
- 当
- 递归无返回终止:所有调用
place(tab, consign, pos + 1)的位置都没有加return,递归到下一层返回后,会继续执行当前层的后续逻辑,最终触发上述0赋值语句 - for循环计数错误:for循环头部已经定义了index自动自增,循环体末尾又额外加了
index++,相当于每次循环index加2,只会遍历1、3两个值,2、4的取值逻辑完全没覆盖,大部分场景都会触发校验失败走0赋值分支 - 赋值逻辑错误:for循环里给
tab[x][y]赋值写死了9,根本没用到遍历的index值,后续校验逻辑拿到的都是错误值,大概率触发校验失败赋值0
问题2:手动填值时x变量相关报错的原因
- 缺少递归边界判断:没有对入参pos做越界校验,4x4的格子索引是0~15,当pos不断自增到16及以上时,
x = Math.floor(pos /4)就会等于4,而tab数组只有4个元素(索引0~3),tab[x]就会变成undefined,此时访问tab[x][y]、给tab[x][y]赋值都会抛出和x相关的异常 - var声明的变量作用域问题:用var声明x、y、index这些变量,递归调用时变量在函数作用域内共享,回溯时变量值会被后续递归修改,也可能导致x取值异常触发报错
核心代码修复参考
function place(tab, consign, pos) { // 新增边界判断,pos到16说明所有格子填完 if (pos === 16) { if (is_filled_good(tab, consign)) { set_data_in_input(tab); return true; // 用返回值标记是否找到解 } return false; } var x = Math.floor(pos / 4); var y = pos % 4; // 当前格子已填,直接走下一个 if (tab[x][y] != 0) { return place(tab, consign, pos + 1); } for (var index = 1; index <= 4; index++) { if (colnline_has_no_double(tab, x, y, index)) { tab[x][y] = index; let canGoNext = true; // 列填完做上下可见性校验 if (x === 3) { canGoNext = check_top_range(tab, consign, y) && check_bottom_range(tab, consign, y); } // 行填完做左右可见性校验 if (canGoNext && y === 3) { canGoNext = check_left_range(tab, consign, x) && check_right_range(tab, consign, x); } // 找到解直接返回,不再回溯 if (canGoNext && place(tab, consign, pos + 1)) { return true; } // 回溯恢复当前格子值 tab[x][y] = 0; } } return false; }
内容的提问来源于stack exchange,提问作者alexis wandor
相关产品推荐
相关产品推荐

