#prolog #puzzle #clpfd
#пролог #Головоломка #clpfd
Вопрос:
У меня есть головоломка, представляющая собой сетку 3 * 3 с номерами 1-8 в них, с пустым местом (0), которое я могу перемещать. Это конечное состояние головоломки:
1 2 3
8 0 4
7 6 5
Все это «состояние» представлено состоянием (1,2,3,8,0,4,7,6,5) путем чтения по горизонтали. Мне нужна функция для проверки того, какие части находятся в правильных местах.
У меня есть:
h(state(A,B,C,D,E,F,G,H,I),Z) :-
Теперь Z будет количеством частей в правильном месте.
A = 1
B = 2
C = 3
D = 8
E = 0
F = 4
G = 7
H = 6
I = 5
Есть ли какой-нибудь простой способ выдать вывод для Z? Любая помощь будет оценена. Спасибо.
Ответ №1:
Вы уверены, что не можете хранить свою информацию в списках? Это своего рода то, как на традиционном языке вы используете массивы вместо просто набора переменных, если вам нужен способ перебора по ним.
Ответ №2:
Есть короткий способ выразить это в прологе, но для этого требуется CLP (FD).
:- use_module(library(clpfd)).
h(State, Z) :-
State =.. [state | Pos],
maplist(equal, Pos, [0,1,2,3,8,0,4,7,6,5], Eq),
sum(Eq, #=, Z).
equal(X, Y, E) :-
E #<==> (X #= Y).
Ответ №3:
это кажется довольно простым в выполнении…
h(state(A,B,C,D,E,F,G,H,I),Z) :-
count_matching([A,B,C,D,E,F,G,H,I], [1,2,3,8,0,4,7,6,5], 0, Z).
count_matching([], [], N, N).
count_matching([A|As], [B|Bs], N, M) :-
( A == B
-> T is N 1
; T is N
),
count_matching(As, Bs, T, M).
SWI-Prolog aggregate library предлагает еще один простой способ решить вашу проблему:
:- [library(aggregate)].
h(state(A,B,C,D,E,F,G,H,I),Z) :-
aggregate_all(count,
(nth1(Index, [1,2,3,8,0,4,7,6,5], Cell),
nth1(Index, [A,B,C,D,E,F,G,H,I], Cell)), Z).
Использование aggregate_all является излишним: здесь более простая программа, использующая ту же схему (недетерминированный доступ к элементам через nth / 3):
h(state(A,B,C,D,E,F,G,H,I),Z) :-
findall(_,
(nth1(Index, [1,2,3,8,0,4,7,6,5], Cell),
nth1(Index, [A,B,C,D,E,F,G,H,I], Cell)), L),
length(L, Z).