This solitaire game consists of a board of the following shape
and initial configuration

        x
       x x
      x o x
     x x x x
    x x x x x

where x denotes a peg and o an empty hole.  A peg may jump over
an adjacent peg if the hole behind it is empty.  The goal is to
be left with one peg.  I fooled around with this for about 2
minutes and decided it was too hard by hand---a Lolli program
was called for.

The representation is simple: we address the holes with two
natural numbers between 0 and 5, tilting the shape

  00
  10 11
  20 21 22
  30 31 32 33
  40 41 42 43 44

and then introduce a predicate

  b X Y D

where D (either `peg' or `empty') describes the contents of hole XY.  We
initialize the board with a linear assumption fixing the beginning state.

LINEAR b z z peg.
LINEAR b (s z) z peg.
LINEAR b (s z) (s z) peg.
LINEAR b (s (s z)) z peg.
LINEAR b (s (s z)) (s z) empty.
LINEAR b (s (s z)) (s (s z)) peg.
LINEAR b (s (s (s z))) z peg.
LINEAR b (s (s (s z))) (s z) peg.
LINEAR b (s (s (s z))) (s (s z)) peg.
LINEAR b (s (s (s z))) (s (s (s z))) peg.
LINEAR b (s (s (s (s z)))) z peg.
LINEAR b (s (s (s (s z)))) (s z) peg.
LINEAR b (s (s (s (s z)))) (s (s z)) peg.
LINEAR b (s (s (s (s z)))) (s (s (s z))) peg.
LINEAR b (s (s (s (s z)))) (s (s (s (s z)))) peg.

Next we introduce a basic predicate

  jump N

which tests if we can make N consecutive jumps.  Because of the hexagonal
geometry, there are 6 possible directions for jumping (most of them impossible
from any given hole).  The following program allows those precisely those
jumps: it first checks (and thereby consumes) whether we have a configuration
in which a jump is legal, then performs it (by assuming the necessary
instances of the b predicate), and continues with the assignment to make one
fewer jump.  Furthermore, we succeed if there are no jumps to make.

jump (s N) :-
          b X Y peg , b (s X) Y peg , b (s (s X)) Y empty ,
          ((b X Y empty , b (s X) Y empty , b (s (s X)) Y peg)
	   -o jump N).
jump (s N) :-
          b X Y peg , b (s X) (s Y) peg , b (s (s X)) (s (s Y)) empty ,
          ((b X Y empty , b (s X) (s Y) empty , b (s (s X)) (s (s Y)) peg)
	   -o jump N).
jump (s N) :- b X Y peg , b X (s Y) peg , b X (s (s Y)) empty ,
          ((b X Y empty , b X (s Y) empty , b X (s (s Y)) peg)
	   -o jump N).
jump (s N) :-
          b (s (s X)) Y peg , b (s X) Y peg , b X Y empty ,
	  ((b (s (s X)) Y empty , b (s X) Y empty , b X Y peg)
	   -o jump N).
jump (s N) :-
          b (s (s X)) (s (s Y)) peg , b (s X) (s Y) peg , b X Y empty ,
	  ((b (s (s X)) (s (s Y)) empty , b (s X) (s Y) empty , b X Y peg)
	   -o jump N).
jump (s N) :-
          b X (s (s Y)) peg , b X (s Y) peg , b X Y empty ,
          ((b X (s (s Y)) empty , b X (s Y) empty , b X Y peg)
	   -o jump N).
jump z :- erase.

The query that demonstrates if the puzzle is solvable asks Lolli
to check if it is possible to make 13 consecutive jumps.  Since we
start with 14 pegs, this means only one will be left.

  ?- solitaire --o top.
  ?- jump (s (s (s (s (s (s (s (s (s (s (s (s (s z))))))))))))).
  solved

It succeeds after 25 minutes (wall-clock time) under version 94, indicating
there is a solution.  Since Lolli does not have proof terms, I instrumented
the predicate to explicitly maintain enough information so I can carry
out the solution on the board.  This instrumented version takes about
27 minutes to return the first solution.  (Times are on a Dec Alpha).

I challenge anyone to write a more concise program more quickly to solve this
puzzle (the instrumented version is below), but I will not extend a challenge
to write a more efficient version.  It will be interesting to see how
quickly this puzzle can be solved given reasonable interpreter technology
like destructive substitutions, etc.

  - Frank

P.S.: I let it run overnight and the program determined that there is no
solution where the one remaining peg ends up in the hole which is
initially empty.
----------------------------------------------------------------------
MODULE solitaire2.

LINEAR b z z peg.
LINEAR b (s z) z peg.
LINEAR b (s z) (s z) peg.
LINEAR b (s (s z)) z peg.
LINEAR b (s (s z)) (s z) empty.
LINEAR b (s (s z)) (s (s z)) peg.
LINEAR b (s (s (s z))) z peg.
LINEAR b (s (s (s z))) (s z) peg.
LINEAR b (s (s (s z))) (s (s z)) peg.
LINEAR b (s (s (s z))) (s (s (s z))) peg.
LINEAR b (s (s (s (s z)))) z peg.
LINEAR b (s (s (s (s z)))) (s z) peg.
LINEAR b (s (s (s (s z)))) (s (s z)) peg.
LINEAR b (s (s (s (s z)))) (s (s (s z))) peg.
LINEAR b (s (s (s (s z)))) (s (s (s (s z)))) peg.

% I am using sw, se, e, ne, nw, w for the six possible directions
% of a jump, the arguments indicate the origin of the jump.
jump (j (sw X Y) N) :-
          b X Y peg , b (s X) Y peg , b (s (s X)) Y empty ,
          ((b X Y empty , b (s X) Y empty , b (s (s X)) Y peg)
	   -o jump N).
jump (j (se X Y) N) :-
          b X Y peg , b (s X) (s Y) peg , b (s (s X)) (s (s Y)) empty ,
          ((b X Y empty , b (s X) (s Y) empty , b (s (s X)) (s (s Y)) peg)
	   -o jump N).
jump (j (e X Y) N) :- b X Y peg , b X (s Y) peg , b X (s (s Y)) empty ,
          ((b X Y empty , b X (s Y) empty , b X (s (s Y)) peg)
	   -o jump N).
jump (j (ne (s (s X)) Y) N) :-
          b (s (s X)) Y peg , b (s X) Y peg , b X Y empty ,
	  ((b (s (s X)) Y empty , b (s X) Y empty , b X Y peg)
	   -o jump N).
jump (j (nw (s (s X)) (s (s Y))) N) :-
          b (s (s X)) (s (s Y)) peg , b (s X) (s Y) peg , b X Y empty ,
	  ((b (s (s X)) (s (s Y)) empty , b (s X) (s Y) empty , b X Y peg)
	   -o jump N).
jump (j (w X (s (s Y))) N) :-
          b X (s (s Y)) peg , b X (s Y) peg , b X Y empty ,
          ((b X (s (s Y)) empty , b X (s Y) empty , b X Y peg)
	   -o jump N).
jump f :- erase.
----------------------------------------------------------------------
?- solitaire2 --o top.
?- jump (j J1 (j J2 (j J3 (j J4 (j J5 (j J6 (j J7 (j J8 (j J9 (j J10 (j J11 (j J12 (j J13 f))))))))))))).
J1_10319350 <- ne (s (s (s (s z)))) (s z) ,
J2_10319349 <- w (s (s (s z))) (s (s (s z))) ,
J3_10319348 <- se (s z) z ,
J4_10319347 <- se (s z) (s z) ,
J5_10319346 <- ne (s (s (s z))) z ,
J6_10319345 <- sw z z ,
J7_10319344 <- nw (s (s (s (s z)))) (s (s (s (s z)))) ,
J8_10319343 <- w (s (s (s (s z)))) (s (s (s z))) ,
J9_10319342 <- sw (s (s z)) (s (s z)) ,
J10_10319341 <- e (s (s (s (s z)))) (s z) ,
J11_10319340 <- se (s (s z)) z ,
J12_10319339 <- w (s (s (s (s z)))) (s (s (s z))) ,
J13_10319338 <- e (s (s (s (s z)))) z
