问题描述:

I'm following along with Learn Prolog Now! and was looking at Exercise 2.4.

A solution I found here seems to solve, but not completely:

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, _).

This produces the following results:

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 ? ;

Of these, only 2 are practical:

H1 = astoria

H2 = baratto

H3 = statale

V1 = astante

V2 = cobalto

V3 = pistola ? ;

H1 = astante

H2 = cobalto

H3 = pistola

V1 = astoria

V2 = baratto

V3 = statale ? ;

Because the other 3 solutions contain duplicates, they are not viable answers for the problem.

How can I add to the crossword rule to have it only return results where V1,V2,V3,H1,H2,H3 are all unique?

网友答案:

You could use a procedure like this to ensure values are all different:

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).

and call it with all_dif([V1,V2,V3,H1,H2,H3])

网友答案:

a common technique make use of select/3, to get unique alternative elements on backtracking:

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).

This is clearly an alternative method to the very simple solution you already found.

select/3 can also be used to check that there are no duplicates in list:

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).

At last, since sort/2 removes duplicates, the easiest check could be

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], [_,_,_,_,_,_]).
相关阅读:
Top