Prolog 序言:不断得到错误的结果
我正在尝试创建一个程序,该程序可以在一个n*n国际象棋上放置骑士的最大值,而不会有任何骑士吃掉另一个。 我设法找到了如何做到这一点,但是我不断得到错误的结果,而不是显示解决方案所在的列表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).
:- 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列表中删除一名骑士,然后重试相同的过程。不要将您的答案更改回原始状态!