骑士在Prolog的巡回赛:超出筹码限制

时间:2019-08-04 15:39:54

标签: prolog swi-prolog knights-tour

在尝试使用Warnsdorff规则优化程序之后,编译器开始发出超出堆栈限制的信息。所有部分似乎都单独起作用,但是我不知道如何进行优化。我正在使用具有32位窗口的旧笔记本电脑上编写程序,因此无法手动增加堆栈的大小,因为它是在官方网站https://www.swi-prolog.org/FAQ/StackSizes.html上编写的。

knightpath(Board, [1 / 1 | Path]) :-
    Jumps is Board * Board,
    the_way(Jumps, [1 / 1 | Path]).
the_way(1, [X / Y]) : -
    between(1, 5, X),
    between(1, 5, Y).
the_way(Jumps, [X1 / Y1, X2 / Y2 | Path]) : -
    Jumps1 is Jumps - 1,
    the_way(Jumps1, [X2 / Y2 | Path]),
    warnsdorff(X2 / Y2, Path, X1 / Y1).
jump(X1 / Y1, X2 / Y2) : -
    ((X1 is X2 + 2;
      X1 is X2 - 2),
     (Y1 is Y2 + 1;
      Y1 is Y2 - 1);
     (X1 is X2 + 1;
      X1 is X2 - 1),
     (Y1 is Y2 + 2;
      Y1 is Y2 - 2)),
    between(1, 5, X1),
    between(1, 5, Y1).
warnsdorff(X1 / Y1, Path, X2 / Y2) :-
    find_posible(X1 / Y1, Path, Pos),
    find_best(_, [X1 / Y1 | Path], Pos, X2 / Y2).
find_best(N, Path, [X / Y], X / Y) : -
    find_posible(X / Y, Path, Pos),
    length(Pos, N).
find_best(N1, Path, [X / Y | List], X / Y) : -
    find_best(N2, Path, List, _),
    find_posible(X / Y, Path, Pos),
    length(Pos, N1),
    N1 < N2.
find_best(N2, Path, [X1 / Y1 | List], X2 / Y2) : -
    find_best(N2, Path, List, X2 / Y2),
    find_posible(X1 / Y1, Path, Pos),
    length(Pos, N1),
    N1 >= N2.
find_posible(X1 / Y1, Path, Pos) : -
    findall(X2 / Y2, jump(X2 / Y2, X1 / Y1), All_tog),
    filter_path(All_tog, Path, Pos).
filter_path([], _, []).
filter_path([X / Y | All_tog], Path, [X / Y | Pos]) : -
    not(member(X / Y, Path)),
    filter_path(All_tog, Path, Pos).
filter_path([X / Y | All_tog], Path, Pos) : -
    member(X / Y, Path),
    filter_path(All_tog, Path, Pos).

这就是编译器产生的结果

ERROR: Stack limit (0.5Gb) exceeded
ERROR:   Stack sizes: local: 0.1Gb, global: 42.7Mb, trail: 0Kb
ERROR:   Stack depth: 1,863,822, last-call: 0%, Choice points: 3
ERROR:   In:
ERROR:     [1,863,822] user:the_way(-1863788, [length:1|_22365890])
ERROR:     [1,863,821] user:the_way(-1863787, '<garbage_collected>')
ERROR:     [1,863,820] user:the_way(-1863786, '<garbage_collected>')
ERROR:     [1,863,819] user:the_way(-1863785, '<garbage_collected>')
ERROR:     [1,863,818] user:the_way(-1863784, '<garbage_collected>')

2 个答案:

答案 0 :(得分:1)

回溯已显示出什么问题:the_way的调用方式为:

[1,863,822] user:the_way(-1863788, [length:1|_22365890])

因此,这意味着Jumps变量为-1863788。您没有在递归中执行适当的检查,以免使路径长于阈值。您应该添加一个约束,例如:

the_way(1, [X / Y]) : -
    between(1, 5, X),
    between(1, 5, Y).
the_way(Jumps, [X1 / Y1, X2 / Y2 | Path]) : -
    Jumps > 1,
    Jumps1 is Jumps - 1,
    the_way(Jumps1, [X2 / Y2 | Path]),
    warnsdorff(X2 / Y2, Path, X1 / Y1).

答案 1 :(得分:1)

问题在于,Warnsdorff规则无法为第一个(按堆栈计算的最后一个)平方为1/1的情况提供解决方案。我必须写

knightpath(Answ) :-
    Jumps is Board * Board,
    the_way(Jumps, Path),
    reverse(Path, Answ).
...

the_way(1, [1/1]).

顺便说一句,如果我按照Willem Van Onsem https://stackoverflow.com/a/57348007/11779964的建议编写,那么可以避免错误,并且编译器将只输出'false'。