Принудительно прологи выбирают уникальные значения переменных
Хорошо, я новичок в Прологе, так что извините, если это что-то тривиальное, но я не могу найти правильный элегантный ответ на это. Я пытаюсь выполнить упражнение здесь на веб-сайте learnprolognow.org, упражнение 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, V1a, V1bH1b, V1c, V1dH2b, V1e, V1fH3b, V1g),
word(V2, V2a, V2bH1d, V2c, V2dH2d, V2e, V2fH3d, V2g),
word(V3, V3a, V3bH1f, V3c, V3dH2f, V3e, V3fH3f, V3g),
word(H1, H1a, V1bH1b, H1c, V2bH1d, H1e, V3bH1f, H1g),
word(H2, H2a, V1dH2b, H2c, V2dH2d, H2e, V3dH2f, H2g),
word(H3, H3a, V1fH3b, H3c, V2fH3d, H3e, V3fH3f, H3g).
С V1a
в V1g
и т.д., являющиеся символами каждого слова, и V1bH1b
в V3fH3f
быть общими для слов в кроссворде.
Решение, кажется, работает, однако в результате получаются повторяющиеся значения, первый результат:
?- crossword(V1, V2, V3, H1, H2, H3).
V1 = astante,
V2 = baratto,
V3 = statale,
H1 = astante,
H2 = baratto,
H3 = statale .
Как я могу заставить Пролог иметь V1 \= V2 \= V3 \= H1 \= H2 \= H3
? Если я буду делать их по отдельности, мне понадобится 120 перестановок, поэтому должен быть более быстрый путь, и это упражнение для начинающих, поэтому я должен что-то упустить.
Я нашел этот похожий вопрос, но представленные ответы кажутся такими сложными, я надеюсь, что есть более простой способ. Я использую swi-пролог на Ubuntu, на всякий случай, если это имеет значение.
Благодарю.
3 ответа
Использование alldif/1
определяется так:
alldif([]).
alldif([E|Es]) :-
maplist(dif(E), Es),
alldif(Es).
Который может использоваться даже для самого общего запроса:
?- alldif(Es).
Es = [] ;
Es = [_G1924] ;
Es = [_G2061, _G2064],
dif(_G2061, _G2064) ;
Es = [_G2163, _G2166, _G2169],
dif(_G2163, _G2169),
dif(_G2163, _G2166),
dif(_G2166, _G2169) ;
Es = [_G2309, _G2312, _G2315, _G2318],
dif(_G2309, _G2318),
dif(_G2309, _G2315),
dif(_G2309, _G2312),
dif(_G2315, _G2318),
dif(_G2312, _G2315),
dif(_G2312, _G2318) ...
Смысл цели maplist(dif(E),Es)
лучше всего понять, глядя на ответы:
?- maplist(dif(E),Es).
Es = [] ;
Es = [_G1987],
dif(E, _G1987) ;
Es = [_G2040, _G2043],
dif(E, _G2043),
dif(E, _G2040) ;
Es = [_G2093, _G2096, _G2099],
dif(E, _G2099),
dif(E, _G2096),
dif(E, _G2093) ;
Es = [_G2146, _G2149, _G2152, _G2155],
dif(E, _G2155),
dif(E, _G2152),
dif(E, _G2149),
dif(E, _G2146) ...
То есть, Es
список элементов, которые отличаются от E
, Список целей (dif(E),[A,B,C]) объединяет первый элемент (в данном случае dif(E)
) с каждым элементом списка. таким образом dif(E,A), dif(E,B), dif(E,C)
,
length(List, N)
: N - длина спискаsort(List, SortedList)
: SortedList является отсортированной версией List (дублирующиеся элементы удаляются)
С другой стороны, может быть быстрее иметь список доступных слов и удалить его, когда он используется; не только вам не придется делать проверку в конце, но вы также избежите бессмысленных реализаций (A1 = foo, A2 = foo
остановится немедленно вместо того, чтобы быть отклоненным в конце). Другими словами, обрезка веток.
Либо то, что @false сказал вам в комментариях; или мне нравится использовать выбор домена:
selectM([A|As],S,Z):- select(A,S,S1),selectM(As,S1,Z).
selectM([],Z,Z).
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(Words) :- findall(W, word(_,W), WS),
Words = [[ _,A,_,B,_,C,_],
[ _,D,_,E,_,F,_],
[ _,G,_,H,_,I,_],
[ _,A,_,D,_,G,_],
[ _,B,_,E,_,H,_],
[ _,C,_,F,_,I,_]],
selectM( Words, WS, _).