0

我正在跟随Learn Prolog Now!并且正在查看练习 2.4

在这里找到的解决方案似乎可以解决,但并不完全:

word(astante,  a,s,t,a,n,t,e). 
word(astoria,  a,s,t,o,r,i,a). 
word(baratto,  b,a,r,a,t,t,o). 
word(cobalto,  c,o,b,a,l,t,o). 
word(pistola,  p,i,s,t,o,l,a). 
word(statale,  s,t,a,t,a,l,e).

crossword(V1,V2,V3,H1,H2,H3) :- 
  word(V1, _, V1H1, _, V1H2, _, V1H3, _),
  word(V2, _, V2H1, _, V2H2, _, V2H3, _),
  word(V3, _, V3H1, _, V3H2, _, V3H3, _),
  word(H1, _, V1H1, _, V2H1, _, V3H1, _),
  word(H2, _, V1H2, _, V2H2, _, V3H2, _),
  word(H3, _, V1H3, _, V2H3, _, V3H3, _).

这会产生以下结果:

H1 = astoria
H2 = baratto
H3 = statale
V1 = astante
V2 = cobalto
V3 = pistola ? ;

H1 = astante
H2 = cobalto
H3 = pistola
V1 = astoria
V2 = baratto
V3 = statale ? ;

H1 = astoria
H2 = cobalto
H3 = pistola
V1 = astoria
V2 = cobalto
V3 = pistola ? ;

H1 = baratto
H2 = baratto
H3 = statale
V1 = baratto
V2 = baratto
V3 = statale ? ;

H1 = cobalto
H2 = baratto
H3 = statale
V1 = cobalto
V2 = baratto
V3 = statale ? ;

H1 = astante
H2 = baratto
H3 = statale
V1 = astante
V2 = baratto
V3 = statale ? ;

其中,只有 2 个是实用的:

H1 = astoria
H2 = baratto
H3 = statale
V1 = astante
V2 = cobalto
V3 = pistola ? ;

H1 = astante
H2 = cobalto
H3 = pistola
V1 = astoria
V2 = baratto
V3 = statale ? ;

由于其他 3 个解决方案包含重复项,因此它们不是该问题的可行答案。

如何添加到填字游戏规则以使其仅返回 V1、V2、V3、H1、H2、H3 都是唯一的结果?

4

2 回答 2

1

您可以使用这样的过程来确保值都不同:

all_dif([]).
all_dif([A|Tail]):-
  all_dif(Tail, A),
  all_dif(Tail).

all_dif([], _).
all_dif([B|Tail], A):-
  dif(A,B),
  all_dif(Tail, A).

并调用它all_dif([V1,V2,V3,H1,H2,H3])

于 2013-06-18T18:43:51.793 回答
1

一种常用的技术是使用select/3,在回溯中获得独特的替代元素:

crossword(V1,V2,V3,H1,H2,H3) :-
    selects(
        [[V1, _, V1H1, _, V1H2, _, V1H3, _],
         [V2, _, V2H1, _, V2H2, _, V2H3, _],
         [V3, _, V3H1, _, V3H2, _, V3H3, _],
         [H1, _, V1H1, _, V2H1, _, V3H1, _],
         [H2, _, V1H2, _, V2H2, _, V3H2, _],
         [H3, _, V1H3, _, V2H3, _, V3H3, _]
        ],
        [[a,s,t,a,n,t,e],
         [a,s,t,o,r,i,a],
         [b,a,r,a,t,t,o],
         [c,o,b,a,l,t,o],
         [p,i,s,t,o,l,a],
         [s,t,a,t,a,l,e]
        ]).

selects([], []).
selects([[W|Cs]|Ws], L) :-
    select(Cs, L, R),
    selects(Ws, R),
    atom_chars(W, Cs).

这显然是您已经找到的非常简单的解决方案的替代方法。

select/3 也可用于检查列表中是否有重复项:

crossword(V1,V2,V3,H1,H2,H3) :-
  word(V1, _, V1H1, _, V1H2, _, V1H3, _),
  word(V2, _, V2H1, _, V2H2, _, V2H3, _),
  word(V3, _, V3H1, _, V3H2, _, V3H3, _),
  word(H1, _, V1H1, _, V2H1, _, V3H1, _),
  word(H2, _, V1H2, _, V2H2, _, V3H2, _),
  word(H3, _, V1H3, _, V2H3, _, V3H3, _),
  maplist(nodup([V1,V2,V3,H1,H2,H3]), [V1,V2,V3,H1,H2,H3]).

nodup(L, E) :- select(E, L, R), \+ memberchk(E, R).

最后,由于 sort/2 删除了重复项,最简单的检查可能是

crossword(V1,V2,V3,H1,H2,H3) :-
  word(V1, _, V1H1, _, V1H2, _, V1H3, _),
  word(V2, _, V2H1, _, V2H2, _, V2H3, _),
  word(V3, _, V3H1, _, V3H2, _, V3H3, _),
  word(H1, _, V1H1, _, V2H1, _, V3H1, _),
  word(H2, _, V1H2, _, V2H2, _, V3H2, _),
  word(H3, _, V1H3, _, V2H3, _, V3H3, _),
  sort([V1,V2,V3,H1,H2,H3], [_,_,_,_,_,_]).
于 2013-06-18T21:29:39.037 回答