我现在有另一个问题
communs(piece(C1, F1, T1, Co1),piece(C2, F2, T2, Co2)) :-
C1 = C2;
F1 = F2;
T1 = T2;
Co1 = Co2.
line((A,_),(A_,_)) :-
A_ = A.
row((_,A),(_,A_)) :-
A_ = A.
win_line([]).
win_line([(_,_),_]).
win_line([(A,P)|[(A_,P_)|Reste]]):-
line(A,A_),
communs(P,P_),
win_line(Reste).
我真的想做点什么,但我现在不怎么做: 我想得到一个只有同一行坐标的列表,例如(1,1),(1,2),(1,3),
我尝试了这个,但我不认为这是正确的:
selct_line([],[]).
select_line([(A,P)|[(A_,P_)|Reste]], _):-
line(A,A_),
select_line(Reste,[(A,P)|[(A_,P_)]).
答案 0 :(得分:0)
你已经找到了几乎所有的问题,干得好!但是还有很多事情需要注意:
首先,使用A
和A_
作为不同变量的名称是有效的,但非常异常且非常难以阅读。例如,使用A1
和A2
会更好。
其次,你对语法感到困惑。考虑:
?- List = [(A1,P1)|[(A2,P2)|Reste]].
List = [ (A1, P1), (A2, P2)|Reste].
您和您的读者都可以使用第二种更常用的语法。两者都描述了相同的术语,但第二个更清楚地表明您有一个列表,该列表以两对(A1, P1)
和(A2, P2)
开头,后跟一些列表Reste
。
第三,让我们看看Prolog为您的定义生成的解决方案:
?- win_line(Line), length(Line, Length).
Line = [],
Length = 0 ;
Line = [ (_G983, _G984), _G986],
Length = 2 ;
Line = [ ((_G992, _G993), piece(_G998, _G999, _G1000, _G1001)), ((_G992, _G996), piece(_G998, _G1004, _G1005, _G1006))],
Length = 2 ;
Line = [ ((_G992, _G993), piece(_G998, _G999, _G1000, _G1001)), ((_G992, _G996), piece(_G998, _G1004, _G1005, _G1006)), (_G1011, _G1012), _G1014],
Length = 4 ;
Line = [ ((_G992, _G993), piece(_G998, _G999, _G1000, _G1001)), ((_G992, _G996), piece(_G998, _G1004, _G1005, _G1006)), ((_G1020, _G1021), piece(_G1026, _G1027, _G1028, _G1029)), ((_G1020, _G1024), piece(_G1026, _G1032, _G1033, _G1034))],
Length = 4 ;
等。生成的所有列表都是均匀的!大概你也想接受长度为1,3,5等的列表?
win_line/1
的第二个条款特别奇怪且未明确:
win_line([(_,_),_]).
即使忽略这对坐标,这也可以让我们证明这样的事情:
?- win_line([_, hello_world]).
true .
这不应该是坐标对和piece
项的对吗?也就是说,你可能想要更像这样的东西:
win_line([((_,_),_)]).
其行为如下:
?- win_line([(0,1), hello_world]).
false.
?- win_line([((0,1), hello_world)]).
true .
但更好:
win_line([((_,_), piece(_,_,_,_))]).
给出:
?- win_line([((0,1), hello_world)]).
false.
?- win_line([((0,1), piece(a,b,c,d))]).
true .
有了这个,结果的列举更有意义:
?- win_line(Line), length(Line, Length).
Line = [],
Length = 0 ;
Line = [ ((_G986, _G987), piece(_G989, _G990, _G991, _G992))],
Length = 1 ;
Line = [ ((_G992, _G993), piece(_G998, _G999, _G1000, _G1001)), ((_G992, _G996), piece(_G998, _G1004, _G1005, _G1006))],
Length = 2 ;
Line = [ ((_G992, _G993), piece(_G998, _G999, _G1000, _G1001)), ((_G992, _G996), piece(_G998, _G1004, _G1005, _G1006)), ((_G1014, _G1015), piece(_G1017, _G1018, _G1019, _G1020))],
Length = 3 ;
Line = [ ((_G992, _G993), piece(_G998, _G999, _G1000, _G1001)), ((_G992, _G996), piece(_G998, _G1004, _G1005, _G1006)), ((_G1020, _G1021), piece(_G1026, _G1027, _G1028, _G1029)), ((_G1020, _G1024), piece(_G1026, _G1032, _G1033, _G1034))],
Length = 4 .
第四,现在的行为如下:
?- win_line([((0,0), piece(a,b,c,d)), ((0,1), piece(a,b,c,d)), ((1,1), piece(now, something, completely, different))]).
true .
您强制执行列表的前两个元素之间的关系,但不强制执行第二个和第三个元素之间的关系。这是因为对于此表单的列表,您在前两个元素上调用communs
,但在第二个和第三个元素上调用 not 。
检查Prolog中每对相邻元素的常用方法是遵循以下模式:
valid_list([]).
valid_list([_]).
valid_list([A, B | Rest]) :-
valid_pair(A, B),
valid_list([B | Rest]).
也就是说,元素B
被传递回递归调用。因此,如果您在表单[A, B, C]
的列表中调用此列表,则会同时调用valid(A, B)
和valid(B, C)
。您的代码只检查第一个而不是第二个,因此它接受无效列表。
最后,((0,1), piece(...))
形式的这些术语在所有括号中都难以阅读。最好使用像move(0, 1, piece(...))
这样的格式。这会让你更加困惑,因为你对win_line
的第二个句子感到困惑。