% Peg Solitaire
% Strange version using unary integers
% Author: Frank Pfenning

test(I) :-
	g_assign(count, 0),
	solve(I),
	g_inc(count),				% not affected by backtracking
	fail.
test(I) :-
	g_read(count, K),
	format("At ~p, ~p solutions\n", [I,K]).

solve(I) :-
	init(State0),
	int_to_nat(I,N),
	moves(N, State0).

int_to_nat(0, z).
int_to_nat(I, s(N)) :-
	I > 0,
	I1 is I-1,
	int_to_nat(I1, N).

moves(z, _).
moves(s(N), State1) :-
	move1(State1, State2),
	moves(N, State2).

% right
move1(State1, [peg(s(s(X)),Y), hole(s(X),Y), hole(X,Y) | State2]) :-
  Situation = [hole(s(s(X)),Y), peg(s(X),Y), peg(X,Y)],
  members(Situation, State1),		% redundant
  deletes(Situation, State1, State2).
% left
move1(State1, [peg(X,Y), hole(s(X),Y), hole(s(s(X)),Y) | State2]) :-
  Situation = [hole(X,Y), peg(s(X),Y), peg(s(s(X)),Y)],
  members(Situation, State1),		% redundant
  deletes(Situation, State1, State2).
% up
move1(State1, [peg(X,s(s(Y))), hole(X,s(Y)), hole(X,Y) | State2]) :-
  Situation = [hole(X,s(s(Y))), peg(X,s(Y)), peg(X,Y)],
  members(Situation, State1),		% redundant
  deletes(Situation, State1, State2).
% down
move1(State1, [peg(X,Y), hole(X,s(Y)), hole(X,s(s(Y))) | State2]) :-
  Situation = [hole(X,Y), peg(X,s(Y)), peg(X,s(s(Y)))],
  members(Situation, State1),		% redundant
  deletes(Situation, State1, State2).

init(State) :-
	between(s(s(z)), s(s(s(s(s(z))))), z, [], State0),
	between(s(s(z)), s(s(s(s(s(z))))), s(z), State0, State1),
	between(z,       s(s(s(s(s(s(s(z))))))), s(s(z)), State1, State2),
	between(z,       s(s(s(z))), s(s(s(z))), State2, State3a),
	between(s(s(s(s(z)))), s(s(s(s(s(s(s(z))))))), s(s(s(z))), State3a, State3b),
        between(z,       s(s(s(s(s(s(s(z))))))), s(s(s(s(z)))), State3b, State4),
        between(s(s(z)), s(s(s(s(s(z))))), s(s(s(s(s(z))))), State4, State5),
        between(s(s(z)), s(s(s(s(s(z))))), s(s(s(s(s(s(z)))))), State5, State6),
	State = [hole(s(s(s(z))),s(s(s(z))))|State6].

between(X, X, _, State, State) :- !.
between(X1, X2, Y, State1, State2) :-
	between(s(X1), X2, Y, [peg(X1,Y)|State1], State2).


members([], _).
members([B|Bs], State) :-
	member(B, State),
	members(Bs, State).

deletes([], State, State).
deletes([B|Bs], State1, State3) :-
	select(B, State1, State2),
	deletes(Bs, State2, State3).

% :- initialization(test(7)).
