Prolog 序言:不断得到错误的结果

Prolog 序言:不断得到错误的结果,prolog,Prolog,我正在尝试创建一个程序,该程序可以在一个n*n国际象棋上放置骑士的最大值,而不会有任何骑士吃掉另一个。 我设法找到了如何做到这一点,但是我不断得到错误的结果,而不是显示解决方案所在的列表 :- use_module(library(lists), [member/2]). :- use_module(contestlib, [for/3]). genere(0,[]). genere(N,[N|L]) :- N>0, N1 is N-1, genere(N1,L).

我正在尝试创建一个程序,该程序可以在一个n*n国际象棋上放置骑士的最大值,而不会有任何骑士吃掉另一个。 我设法找到了如何做到这一点,但是我不断得到错误的结果,而不是显示解决方案所在的列表

:- use_module(library(lists), [member/2]).
:- use_module(contestlib, [for/3]).

genere(0,[]).
genere(N,[N|L]) :-
   N>0,
   N1 is N-1,
   genere(N1,L).

generePos(N,[(Lig,Col)]) :-
   genere(N,L),
   member(Lig,L),
   member(Col,L).

genereEchiquier(N,PlacedKnights) :-
   findall((X,Y),(for(X,1,N),for(Y,1,N)),PlacedKnights).

knights(N) :-
    genereEchiquier(N,PlacedKnights),
    generePos(N,P1),
    knighta(P1,PlacedKnights).

knighta([(X,Y)|_],[]) :-
   write("No solution, next sol").
knighta([(X,Y)|_],[_|PlacedKnights]) :-
   (  is_attacked(X,Y,PlacedKnights)
   -> knights(P1,PlacedKnights)
   ;  write([(X,Y)|PlacedKnights)!
   ).

is_attacked(X,Y,PlacedKnights) :-
    ( NX is X - 1, NY is Y - 2
    ; NX is X - 1, NY is Y + 2
    ; NX is X + 1, NY is Y - 2
    ; NX is X + 1, NY is Y + 2
    ; NX is X - 2, NY is Y - 1
    ; NX is X - 2, NY is Y + 1
    ; NX is X + 2, NY is Y - 1
    ; NX is X + 2, NY is Y + 1
    ),
    member((NX,NY),PlacedKnights).
在调试模式下运行程序时,行
knighta(P1,placedknight)
。不将程序带到knighta/2:此处

knighta([(X,Y)|_],[_|PlacedKnights])

我不知道为什么。

首先,您的代码存在一些问题:

  • 首先,我建议您缩进代码
  • 您应该使用
    ]
    而不是
    
    
  • 你有时会在应该叫骑士的地方叫骑士;及
  • 在附加
    中的约束之前,应首先使用
    成员
也许你应该考虑重新设计。

首先,您可以使用以下内容作为
is\u attacked
谓词:

is_attacked(X,Y,PlacedKnights) :-
    member((NX,NY),PlacedKnights),
    is_attacked(X,Y,NX,NY).

is_attacked(XA,YA,XB,YB) :-
    DX is abs(XA-XB),
    DY is abs(YA-YB),
    is_attacked(DX,DY).

is_attacked(1,2).
is_attacked(2,1).
因此,您迭代所有已放置的骑士,并计算差值并检查其是否为
(2,1)
(1,2)
差值

接下来,您可以使用以下谓词生成所有可能的配置:

generateSolution(R,_,R).
generateSolution(Q,N,R) :-
    for(X,1,N),
    for(Y,1,N),
    \+ member((X,Y),Q),
    \+ is_attacked(X,Y,Q),
    generateSolution([(X,Y)|Q],N,R).
其中,
generateSolution(L,N,R)
是一个谓词,其中
L
是已经安置的骑士,
N
是棋盘的大小,
R
是已经给定的骑士的任何正确配置(注意,这不是骑士的最大数量所必需的)

但这并不是那么有效:你不执行对称性破坏,因此产生了大量的重复:

?- generateSolution([],4,R),length(R,4).
R = [ (1, 4), (1, 3), (1, 2), (1, 1)] ; <- duplicate of
R = [ (2, 2), (1, 3), (1, 2), (1, 1)] ;
R = [ (4, 1), (1, 3), (1, 2), (1, 1)] ;
R = [ (4, 2), (1, 3), (1, 2), (1, 1)] ;
R = [ (4, 3), (1, 3), (1, 2), (1, 1)] ;
R = [ (4, 4), (1, 3), (1, 2), (1, 1)] ;
R = [ (1, 3), (1, 4), (1, 2), (1, 1)] ; <- this one
R = [ (2, 1), (1, 4), (1, 2), (1, 1)] ;
R = [ (3, 4), (1, 4), (1, 2), (1, 1)] ;
R = [ (4, 1), (1, 4), (1, 2), (1, 1)] ;
R = [ (4, 2), (1, 4), (1, 2), (1, 1)] ;
R = [ (4, 3), (1, 4), (1, 2), (1, 1)] ;
R = [ (4, 4), (1, 4), (1, 2), (1, 1)] ;
R = [ (1, 4), (2, 1), (1, 2), (1, 1)] ;
R = [ (2, 2), (2, 1), (1, 2), (1, 1)] ;
R = [ (3, 4), (2, 1), (1, 2), (1, 1)] ;
?- generateSolution([],4,R),length(R,4).
R = [ (1, 4), (1, 3), (1, 2), (1, 1)] ;
R = [ (2, 1), (1, 3), (1, 2), (1, 1)] ;
R = [ (2, 2), (1, 3), (1, 2), (1, 1)] ;
R = [ (3, 4), (1, 3), (1, 2), (1, 1)] ;
R = [ (4, 1), (1, 3), (1, 2), (1, 1)] ;
R = [ (4, 2), (1, 3), (1, 2), (1, 1)] ;
R = [ (4, 3), (1, 3), (1, 2), (1, 1)] ;
R = [ (4, 4), (1, 3), (1, 2), (1, 1)] ;
R = [ (2, 1), (1, 4), (1, 2), (1, 1)] ;
R = [ (2, 2), (1, 4), (1, 2), (1, 1)] ;
R = [ (3, 4), (1, 4), (1, 2), (1, 1)] ;
R = [ (4, 1), (1, 4), (1, 2), (1, 1)] ;
R = [ (4, 2), (1, 4), (1, 2), (1, 1)] ;
R = [ (4, 3), (1, 4), (1, 2), (1, 1)] ;
R = [ (4, 4), (1, 4), (1, 2), (1, 1)] ;
R = [ (2, 2), (2, 1), (1, 2), (1, 1)] ;
R = [ (3, 4), (2, 1), (1, 2), (1, 1)] ;
R = [ (4, 1), (2, 1), (1, 2), (1, 1)] ;
R = [ (4, 2), (2, 1), (1, 2), (1, 1)] ;
R = [ (4, 3), (2, 1), (1, 2), (1, 1)] ;
R = [ (4, 4), (2, 1), (1, 2), (1, 1)] ;
R = [ (3, 4), (2, 2), (1, 2), (1, 1)] ;
R = [ (4, 1), (2, 2), (1, 2), (1, 1)] ;
此处,或
Y
必须大于先前的
Y
,或
X
必须大于。因此,查询不再考虑重复项:

?- generateSolution([],4,R),length(R,4).
R = [ (1, 4), (1, 3), (1, 2), (1, 1)] ; <- duplicate of
R = [ (2, 2), (1, 3), (1, 2), (1, 1)] ;
R = [ (4, 1), (1, 3), (1, 2), (1, 1)] ;
R = [ (4, 2), (1, 3), (1, 2), (1, 1)] ;
R = [ (4, 3), (1, 3), (1, 2), (1, 1)] ;
R = [ (4, 4), (1, 3), (1, 2), (1, 1)] ;
R = [ (1, 3), (1, 4), (1, 2), (1, 1)] ; <- this one
R = [ (2, 1), (1, 4), (1, 2), (1, 1)] ;
R = [ (3, 4), (1, 4), (1, 2), (1, 1)] ;
R = [ (4, 1), (1, 4), (1, 2), (1, 1)] ;
R = [ (4, 2), (1, 4), (1, 2), (1, 1)] ;
R = [ (4, 3), (1, 4), (1, 2), (1, 1)] ;
R = [ (4, 4), (1, 4), (1, 2), (1, 1)] ;
R = [ (1, 4), (2, 1), (1, 2), (1, 1)] ;
R = [ (2, 2), (2, 1), (1, 2), (1, 1)] ;
R = [ (3, 4), (2, 1), (1, 2), (1, 1)] ;
?- generateSolution([],4,R),length(R,4).
R = [ (1, 4), (1, 3), (1, 2), (1, 1)] ;
R = [ (2, 1), (1, 3), (1, 2), (1, 1)] ;
R = [ (2, 2), (1, 3), (1, 2), (1, 1)] ;
R = [ (3, 4), (1, 3), (1, 2), (1, 1)] ;
R = [ (4, 1), (1, 3), (1, 2), (1, 1)] ;
R = [ (4, 2), (1, 3), (1, 2), (1, 1)] ;
R = [ (4, 3), (1, 3), (1, 2), (1, 1)] ;
R = [ (4, 4), (1, 3), (1, 2), (1, 1)] ;
R = [ (2, 1), (1, 4), (1, 2), (1, 1)] ;
R = [ (2, 2), (1, 4), (1, 2), (1, 1)] ;
R = [ (3, 4), (1, 4), (1, 2), (1, 1)] ;
R = [ (4, 1), (1, 4), (1, 2), (1, 1)] ;
R = [ (4, 2), (1, 4), (1, 2), (1, 1)] ;
R = [ (4, 3), (1, 4), (1, 2), (1, 1)] ;
R = [ (4, 4), (1, 4), (1, 2), (1, 1)] ;
R = [ (2, 2), (2, 1), (1, 2), (1, 1)] ;
R = [ (3, 4), (2, 1), (1, 2), (1, 1)] ;
R = [ (4, 1), (2, 1), (1, 2), (1, 1)] ;
R = [ (4, 2), (2, 1), (1, 2), (1, 1)] ;
R = [ (4, 3), (2, 1), (1, 2), (1, 1)] ;
R = [ (4, 4), (2, 1), (1, 2), (1, 1)] ;
R = [ (3, 4), (2, 2), (1, 2), (1, 1)] ;
R = [ (4, 1), (2, 2), (1, 2), (1, 1)] ;
现在,为了找到最大数量的骑士,您可以引导:

谓词的工作原理如下:作为第一个解决方案,您使用
[]
(总是成功的空列表)。接下来,您将开始搜索包含更多骑士的配置:

once((generateSolution([],N,R),length(R,K),K > I)),
一旦找到了骑士数量为
K
的解决方案
R
,您就可以将新的解决方案作为当前解决方案,设置骑士数量并开始搜索骑士数量更多的解决方案。如果最终失败,则返回最后一个当前解决方案

:- use_module(library(lists), [member/2]).
:- use_module(contestlib, [for/3]).

genere(0,[]).
genere(N,[N|L]) :-
   N>0,
   N1 is N-1,
   genere(N1,L).

generePos(N,[(Lig,Col)]) :-
   genere(N,L),
   member(Lig,L),
   member(Col,L).

genereEchiquier(N,PlacedKnights) :-
   findall((X,Y),(for(X,1,N),for(Y,1,N)),PlacedKnights).

knights(N) :-
    genereEchiquier(N,PlacedKnights),
    generePos(N,P1),
    knighta(P1,PlacedKnights).

knighta([(X,Y)|_],[]) :-
   write("No solution, next sol").
knighta([(X,Y)|_],[_|PlacedKnights]) :-
   (  is_attacked(X,Y,PlacedKnights)
   -> knights(P1,PlacedKnights)
   ;  write([(X,Y)|PlacedKnights)!
   ).

is_attacked(X,Y,PlacedKnights) :-
    ( NX is X - 1, NY is Y - 2
    ; NX is X - 1, NY is Y + 2
    ; NX is X + 1, NY is Y - 2
    ; NX is X + 1, NY is Y + 2
    ; NX is X - 2, NY is Y - 1
    ; NX is X - 2, NY is Y + 1
    ; NX is X + 2, NY is Y - 1
    ; NX is X + 2, NY is Y + 1
    ),
    member((NX,NY),PlacedKnights).
示例

?- bootstrap(1,S),write(S).
[ (1,1)]
S = [ (1, 1)].

?- bootstrap(2,S),write(S).
[ (2,2), (2,1), (1,2), (1,1)]
S = [ (2, 2), (2, 1), (1, 2), (1, 1)].

?- bootstrap(3,S),write(S).
[ (3,3), (3,1), (2,2), (1,3), (1,1)]
S = [ (3, 3), (3, 1), (2, 2), (1, 3), (1, 1)].

?- bootstrap(4,S),write(S).
[ (4,4), (4,3), (4,2), (4,1), (1,4), (1,3), (1,2), (1,1)]
S = [ (4, 4), (4, 3), (4, 2), (4, 1), (1, 4), (1, 3), (1, 2), (1, 1)].

?- bootstrap(5,S),write(S).
[ (5,5), (5,3), (5,1), (4,4), (4,2), (3,5), (3,3), (3,1), (2,4), (2,2), (1,5), (1,3), (1,1)]
S = [ (5, 5), (5, 3), (5, 1), (4, 4), (4, 2), (3, 5), (3, 3), (3, 1), (..., ...)|...].

?- bootstrap(6,S),write(S).
完整代码:

bootstrap(N,Sol) :-
    once(bootstrap(N,[],0,Sol)).

bootstrap(N,_,I,S) :-
    once((generateSolution([],N,R),length(R,K),K > I)),
    !,
    bootstrap(N,R,K,S).
bootstrap(_,S,_,S).

generateSolution(R,_,R).
generateSolution([],N,R) :-
    for(X,1,N),
    for(Y,1,N),
    generateSolution([(X,Y)],N,R).
generateSolution([(XL,YL)|T],N,R) :-
    YL1 is YL+1,
    for(Y,YL1,N),
    \+ is_attacked(XL,Y,[(XL,YL)|T]),
    generateSolution([(XL,Y),(XL,YL)|T],N,R).
generateSolution([(XL,YL)|T],N,R) :-
    XL1 is XL+1,
    for(X,XL1,N),
    for(Y,1,N),
    \+ is_attacked(X,Y,[(XL,YL)|T]),
    generateSolution([(X,Y),(XL,YL)|T],N,R).

is_attacked(X,Y,PlacedKnights) :-
    member((NX,NY),PlacedKnights),
    is_attacked(X,Y,NX,NY).

is_attacked(XA,YA,XB,YB) :-
    DX is abs(XA-XB),
    DY is abs(YA-YB),
    is_attacked(DX,DY).

is_attacked(1,2).
is_attacked(2,1).
请注意,存在更聪明的技术,例如,验证骑士是否受到攻击会浪费很多时间,还有其他对称性破坏方法,以及防止返回具有
生成解决方案的骑士数量较少的解决方案的方法。这只是一张草图


非回溯最优解决方案

正如您所注意到的,几乎所有结果都遵循一种模式:

1:
+-+
|x|
+-+
2:
+-+-+
|x|x|
+-+-+
|x|x|
+-+-+
3:
+-+-+-+
|x| |x|
+-+-+-+
| |x| |
+-+-+-+
|x| |x|
+-+-+-+
4:
+-+-+-+-+
|x| |x| |
+-+-+-+-+
| |x| |x|
+-+-+-+-+
|x| |x| |
+-+-+-+-+
| |x| |x|
+-+-+-+-+
N
大于或等于
N
的那一刻起出现的模式是,您将骑士放置在
(0,0)
上,并且每个
(i,i+2*j)
都有
i
j
整数(
j
可以小于
0
)。这是保证的最大值

因此,您可以通过以下方式生成此文件:

solution(1,[(1,1)]).
solution(2,[(2,2),(2,1),(1,2),(1,1)]).
solution(N,L) :-
    N > 2,
    solution([],N,1,1,L).

solution(L,N,I,_,L) :-
    I > N,
    !.
solution(L,N,I,J,S) :-
    JN is J+2,
    JN =< N,
    !,
    solution([(I,J)|L],N,I,JN,S).
solution(L,N,I,J,S) :-
    IN is I+1,
    JN is (I mod 2)+1,
    IN =< N,
    !,
    solution([(I,J)|L],N,IN,JN,S).
solution(L,N,I,J,[(I,J)|L]).
或图形表示:

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |x| |x| |x| |x| |x| |x| |x| |x| |x| |x|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|x| |x| |x| |x| |x| |x| |x| |x| |x| |x| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |x| |x| |x| |x| |x| |x| |x| |x| |x| |x|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|x| |x| |x| |x| |x| |x| |x| |x| |x| |x| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |x| |x| |x| |x| |x| |x| |x| |x| |x| |x|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|x| |x| |x| |x| |x| |x| |x| |x| |x| |x| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |x| |x| |x| |x| |x| |x| |x| |x| |x| |x|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|x| |x| |x| |x| |x| |x| |x| |x| |x| |x| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |x| |x| |x| |x| |x| |x| |x| |x| |x| |x|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|x| |x| |x| |x| |x| |x| |x| |x| |x| |x| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |x| |x| |x| |x| |x| |x| |x| |x| |x| |x|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|x| |x| |x| |x| |x| |x| |x| |x| |x| |x| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |x| |x| |x| |x| |x| |x| |x| |x| |x| |x|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|x| |x| |x| |x| |x| |x| |x| |x| |x| |x| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |x| |x| |x| |x| |x| |x| |x| |x| |x| |x|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|x| |x| |x| |x| |x| |x| |x| |x| |x| |x| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |x| |x| |x| |x| |x| |x| |x| |x| |x| |x|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|x| |x| |x| |x| |x| |x| |x| |x| |x| |x| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |x| |x| |x| |x| |x| |x| |x| |x| |x| |x|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|x| |x| |x| |x| |x| |x| |x| |x| |x| |x| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

首先感谢您抽出时间回答我的问题。我尝试在代码中替换它,但它似乎没有改变任何东西,当我启动调试器时,问题似乎就在这里:knighta(P1,PlacedKnights)。当prolog到达这里时,他没有去knighta([(X,Y)| |,],| | PlacedKnights]),所以它给了我一个错误,这里有一个屏幕:@omar:我添加了很多其他问题。但我认为你最好先解释一下你的程序是如何工作的。每个谓词应该做什么。目前有点混乱…同样在Prolog中,
(,)/2
优先于
(;)/2
!参见示例:
?-write_canonical((a,b,c;d,e,f))。
,产生:
;(','(a','(b,c)),','(d','(e,f)))
。因此,这个特定的括号没有区别。不能在一个注释中发布所有内容,因此,k,我们开始,generePos(N[N | L])谓词生成棋盘的所有位置,从[(1,1)]到[(N,N)]。GenereChiquier(N,PlacedKnights)在单个列表中生成棋盘的所有位置[(1,1),…(N,N)]被攻击(X,Y,PlacedKnights)如果X,Y位置上的骑士可以被PlacedKnights列表中的一个骑士攻击(N),则为true其中N是棋盘的大小,解决这个问题,开始时,所有的地方都是夜晚(它们占据了所有的棋盘),如果骑士可以被其他骑士攻击,将军们会尝试每个位置。如果没有,那么我们已经解决了问题,所以我们会显示解决方案,否则我们会从PlacedKnight列表中删除一名骑士,然后重试相同的过程。不要将您的答案更改回原始状态!