Prolog八数码求解器开发:矩阵中0的相邻移动实现困惑
八数码求解器:实现0的相邻位置移动(Prolog)
核心思路
要实现0的移动,关键是定位0的坐标,然后根据边界规则生成合法的相邻位置,最后交换0和相邻元素得到新状态。结合你熟悉的nth0、append等谓词,我们可以分模块实现:
1. 定位0的位置
先找到0所在的行索引RowIdx,再在该行中找到0的列索引ColIdx:
% 找到0在矩阵中的位置(行索引RowIdx,列索引ColIdx) find_zero(Matrix, RowIdx, ColIdx) :- nth0(RowIdx, Matrix, Row), % 取第RowIdx行 nth0(ColIdx, Row, 0). % 在该行中找0的列索引
2. 生成合法的移动方向
0只能向上下左右移动,需要判断是否越界(行/列索引在0-2之间):
% 生成所有合法的移动方向(新行NewRow,新列NewCol) valid_move(RowIdx, ColIdx, NewRow, NewCol) :- % 向上移动:行索引减1,列不变 NewRow is RowIdx - 1, NewRow >= 0, NewCol = ColIdx. valid_move(RowIdx, ColIdx, NewRow, NewCol) :- % 向下移动:行索引加1,列不变 NewRow is RowIdx + 1, NewRow < 3, NewCol = ColIdx. valid_move(RowIdx, ColIdx, NewRow, NewCol) :- % 向左移动:列索引减1,行不变 NewCol is ColIdx - 1, NewCol >= 0, NewRow = RowIdx. valid_move(RowIdx, ColIdx, NewRow, NewCol) :- % 向右移动:列索引加1,行不变 NewCol is ColIdx + 1, NewCol < 3, NewRow = RowIdx.
3. 交换0和相邻元素,生成新状态
通过拆分矩阵的行,交换对应位置的元素,再重新组合成新矩阵:
% 交换矩阵中(Row1, Col1)和(Row2, Col2)的元素,得到新矩阵NewMatrix swap_elements(Matrix, Row1, Col1, Row2, Col2, NewMatrix) :- % 取第Row1行和第Row2行 nth0(Row1, Matrix, Row1List), nth0(Row2, Matrix, Row2List), % 交换Row1List中Col1位置的元素和Row2List中Col2位置的元素 swap_in_row(Row1List, Col1, Row2List, Col2, NewRow1, NewRow2), % 替换原矩阵中的两行,得到新矩阵 replace_row(Matrix, Row1, NewRow1, TempMatrix), replace_row(TempMatrix, Row2, NewRow2, NewMatrix). % 交换两个行中的指定位置元素 swap_in_row(RowA, IdxA, RowB, IdxB, NewRowA, NewRowB) :- nth0(IdxA, RowA, ValA), nth0(IdxB, RowB, ValB), replace_in_row(RowA, IdxA, ValB, NewRowA), replace_in_row(RowB, IdxB, ValA, NewRowB). % 替换行中指定位置的元素 replace_in_row(Row, Idx, NewVal, NewRow) :- append(Left, [_|Right], Row), length(Left, Idx), append(Left, [NewVal|Right], NewRow). % 替换矩阵中指定索引的行 replace_row(Matrix, RowIdx, NewRow, NewMatrix) :- append(Top, [_|Bottom], Matrix), length(Top, RowIdx), append(Top, [NewRow|Bottom], NewMatrix).
4. 整合移动功能
把上面的谓词整合,实现从当前状态生成所有可能的下一个状态:
% 从当前状态CurrentState生成所有合法的下一个状态NextState move(CurrentState, NextState) :- find_zero(CurrentState, Row, Col), valid_move(Row, Col, NewRow, NewCol), swap_elements(CurrentState, Row, Col, NewRow, NewCol, NextState).
关于你现有代码的说明
你提供的line_matching、list_count、wrong_position属于启发式计算代码,用来统计每行与目标状态的错位元素数量。如果后续实现A*等启发式搜索算法,这些代码可以用来计算启发值(作为评估函数的一部分),但和当前的移动功能无直接关联,后续搜索阶段可复用。
测试示例
输入初始状态[[2,8,3],[1,6,4],[7,0,5]],查询move([[2,8,3],[1,6,4],[7,0,5]], Next),会得到所有合法的下一个状态:
% 向上移动0到(1,2) Next = [[2,8,3],[1,0,4],[7,6,5]] ; % 向左移动0到(2,1) Next = [[2,8,3],[1,6,4],[0,7,5]] ; % 向右移动0到(2,2) Next = [[2,8,3],[1,6,4],[7,5,0]] ; false.
内容的提问来源于stack exchange,提问作者Enzogi
相关产品推荐
相关产品推荐

