如何创建将每个值作为唯一值返回的规则

时间:2013-06-18 18:03:00

标签: prolog crossword prolog-dif

我正在关注Learn Prolog Now!并正在关注Exercise 2.4

found here似乎解决了一个解决方案,但并非完全解决:

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都是唯一的结果?

2 个答案:

答案 0 :(得分: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])

进行调用

答案 1 :(得分: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], [_,_,_,_,_,_]).