solve([_], []).
solve(Pieces, [A-B|Moves]) :-
Pieces \= [_],
select(A, Pieces, Pieces1),
select(B, Pieces1, Pieces2),
takes(A, B, Pieces2), p(Pos,_) = B, p(_,Type) = A,
solve([p(Pos,Type)|Pieces2], Moves).
takes(p(F-R,pawn), p(F1-R1,_), _) :-
abs(F1 - F) =:= 1, R1 =:= R + 1.
takes(p(F-R,rook), p(F-R1,_), Pieces) :-
empty_v(F, R, R1, Pieces).
takes(p(F-R,rook), p(F1-R,_), Pieces) :-
empty_h(R, F, F1, Pieces).
takes(p(F-R,knight), p(F1-R1,_), _) :-
abs(F1 - F) =:= 2, abs(R1 - R) =:= 1.
takes(p(F-R,knight), p(F1-R1,_), _) :-
abs(F1 - F) =:= 1, abs(R1 - R) =:= 2.
takes(p(F-R,bishop), p(F1-R1,_), Pieces) :-
abs(F1 - F) =:= abs(R1 - R),
empty_d(F-R, F1-R1, Pieces).
takes(p(Pos,queen), Piece, Pieces) :-
takes(p(Pos,rook), Piece, Pieces).
takes(p(Pos,queen), Piece, Pieces) :-
takes(p(Pos,bishop), Piece, Pieces).
takes(p(F-R,king), p(F1-R1,_), _) :-
abs(F1 - F) =< 1, abs(R1 - R) =< 1.
empty_v(_, R, R, _) :- !.
empty_v(F, R, R1, Pieces) :- R > R1, empty_v(F, R1, R, Pieces).
empty_v(F, R, R1, Pieces) :-
R < R1, R2 is R + 1,
\+ member(p(F-R,_), Pieces),
empty_v(F, R2, R1, Pieces).
empty_h(_, F, F, _) :- !.
empty_h(R, F, F1, Pieces) :- F > F1, empty_h(R, F1, F, Pieces).
empty_h(R, F, F1, Pieces) :-
F < F1, F2 is F + 1,
\+ member(p(F-R,_), Pieces),
empty_h(R, F2, F1, Pieces).
empty_d(F-R, F-R, _) :- !.
empty_d(F-R, F1-R1, Pieces) :- F > F1, empty_d(F1-R1, F-R, Pieces).
empty_d(F-R, F1-R1, Pieces) :-
F < F1, F2 is F + 1,
\+ member(p(F-R,_), Pieces),
( R < R1 -> R2 is R + 1 ; R2 is R - 1 ),
empty_d(F2-R2, F1-R1, Pieces).
show_board(Pieces) :- show_board(1-4, Pieces).
show_board(5-R, Pieces) :- nl, R1 is R - 1, show_board(1-R1, Pieces).
show_board(1-0, _) :- !.
show_board(F-R, Pieces) :-
( member(p(F-R,Type), Pieces) -> abbrev(Type, C), write(C), write(' ')
; write('. ')
),
F1 is F + 1,
show_board(F1-R, Pieces), !.
abbrev(pawn, 'P').
abbrev(rook, 'R').
abbrev(knight, 'N').
abbrev(bishop, 'B').
abbrev(queen, 'Q').
abbrev(king, 'K').
show_moves([]).
show_moves([p(F-R,Type)-p(F1-R1,_)|Moves]) :-
abbrev(Type, C), write(C), write(' '),
file(F, FC), write(FC), write(R),
write(' x '),
file(F1, F1C), write(F1C), write(R1),
nl,
show_moves(Moves).
file(1, a).
file(2, b).
file(3, c).
file(4, d).
test(Pieces) :-
show_board(Pieces), nl,
solve(Pieces, Moves),
show_moves(Moves).
puzzle(N, K, Puzzle, Solution) :-
choose(N, [pawn,pawn,rook,rook,knight,knight,bishop,bishop,queen,king], Types),
place(Types, [], Puzzle),
member(p(1-_,_), Puzzle),
member(p(_-1,_), Puzzle),
forall(member(P, Puzzle),
( select(P, Puzzle, Puzzle1),
select(Q, Puzzle1, Puzzle2),
takes(P, Q, Puzzle2)
)),
findall(Moves, solve(Puzzle, Moves), [Solution]),
solve(Puzzle, Solution),
\+ member(_-p(_,king), Solution),
\+ ( solve(Puzzle, Solution1),
attackers(Solution1, Attackers),
sort(Attackers, Different),
length(Different, D),
D < K ).
choose(0, _, []).
choose(N, [X|Xs], [X|Ys]) :- N > 0, N1 is N - 1, choose(N1, Xs, Ys).
choose(N, [_|Xs], Ys) :- N > 0, choose(N, Xs, Ys).
place([], Board, Board).
place([Type|Types], Board, X) :-
between(1, 4, F), between(1, 4, R),
\+ member(p(F-R,_), Board),
place(Types, [p(F-R,Type)|Board], X).
attackers([], []).
attackers([p(_,T)-_|Xs], [T|Ys]) :- attackers(Xs, Ys).