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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 21:44:52