xref: /inferno-os/appl/math/crackerbarrel.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsythimplement CBPuzzle;
2*37da2899SCharles.Forsyth
3*37da2899SCharles.Forsyth# Cracker Barrel Puzzle
4*37da2899SCharles.Forsyth#
5*37da2899SCharles.Forsyth# Holes are drilled in a triangular arrangement into which all but one
6*37da2899SCharles.Forsyth# are seated pegs. A 6th order puzzle appears in the diagram below.
7*37da2899SCharles.Forsyth# Note, the hole in the lower left corner of the triangle is empty.
8*37da2899SCharles.Forsyth#
9*37da2899SCharles.Forsyth#                 V
10*37da2899SCharles.Forsyth#               V   V
11*37da2899SCharles.Forsyth#             V   V   V
12*37da2899SCharles.Forsyth#           V   V   V   V
13*37da2899SCharles.Forsyth#         V   V   V   V   V
14*37da2899SCharles.Forsyth#       O   V   V   V   V   V
15*37da2899SCharles.Forsyth#
16*37da2899SCharles.Forsyth# Pegs are moved by jumping over a neighboring peg thereby removing the
17*37da2899SCharles.Forsyth# jumped peg. A peg can only be moved if a neighboring hole contains a
18*37da2899SCharles.Forsyth# peg and the hole on the other side of the neighbor is empty. The last
19*37da2899SCharles.Forsyth# peg cannot be removed.
20*37da2899SCharles.Forsyth#
21*37da2899SCharles.Forsyth# The object is to remove as many pegs as possible.
22*37da2899SCharles.Forsyth
23*37da2899SCharles.Forsythinclude "sys.m";
24*37da2899SCharles.Forsyth   sys: Sys;
25*37da2899SCharles.Forsythinclude "draw.m";
26*37da2899SCharles.Forsyth
27*37da2899SCharles.ForsythCBPuzzle: module {
28*37da2899SCharles.Forsyth   init: fn(nil: ref Draw->Context, args: list of string);
29*37da2899SCharles.Forsyth};
30*37da2899SCharles.Forsyth
31*37da2899SCharles.ForsythORDER: con 6;
32*37da2899SCharles.Forsyth
33*37da2899SCharles.ForsythMove: adt {
34*37da2899SCharles.Forsyth   x, y: int;
35*37da2899SCharles.Forsyth};
36*37da2899SCharles.Forsyth
37*37da2899SCharles.Forsythvalid:= array[] of {Move (1,0), (0,1), (-1,1), (-1,0), (0,-1), (1,-1)};
38*37da2899SCharles.Forsyth
39*37da2899SCharles.Forsythboard:= array[ORDER*ORDER] of int;
40*37da2899SCharles.Forsythpegs, minpegs: int;
41*37da2899SCharles.Forsyth
42*37da2899SCharles.Forsythpuzzle(): int
43*37da2899SCharles.Forsyth{
44*37da2899SCharles.Forsyth   if (pegs < minpegs)
45*37da2899SCharles.Forsyth      minpegs = pegs;
46*37da2899SCharles.Forsyth
47*37da2899SCharles.Forsyth   if (pegs == 1)
48*37da2899SCharles.Forsyth      return 1;
49*37da2899SCharles.Forsyth
50*37da2899SCharles.Forsyth   # Check each row of puzzle
51*37da2899SCharles.Forsyth   for (r := 0; r < ORDER; r += 1)
52*37da2899SCharles.Forsyth      # Check each column
53*37da2899SCharles.Forsyth      for (c := 0; c < ORDER-r; c += 1) {
54*37da2899SCharles.Forsyth         fromx := r*ORDER + c;
55*37da2899SCharles.Forsyth         # Is a peg in this hole?
56*37da2899SCharles.Forsyth         if (board[fromx])
57*37da2899SCharles.Forsyth            # Check valid moves from this hole
58*37da2899SCharles.Forsyth            for (m := 0; m < len valid; m += 1) {
59*37da2899SCharles.Forsyth               tor := r + 2*valid[m].y;
60*37da2899SCharles.Forsyth               toc := c + 2*valid[m].x;
61*37da2899SCharles.Forsyth
62*37da2899SCharles.Forsyth               # Is new location still on the board?
63*37da2899SCharles.Forsyth               if (tor + toc < ORDER && tor >= 0 && toc >= 0) {
64*37da2899SCharles.Forsyth                  jumpr := r + valid[m].y;
65*37da2899SCharles.Forsyth                  jumpc := c + valid[m].x;
66*37da2899SCharles.Forsyth                  jumpx := jumpr*ORDER + jumpc;
67*37da2899SCharles.Forsyth
68*37da2899SCharles.Forsyth                  # Is neighboring hole occupied?
69*37da2899SCharles.Forsyth                  if (board[jumpx]) {
70*37da2899SCharles.Forsyth                     # Is new location empty?
71*37da2899SCharles.Forsyth                     tox := tor*ORDER + toc;
72*37da2899SCharles.Forsyth
73*37da2899SCharles.Forsyth                     if (! board[tox]) {
74*37da2899SCharles.Forsyth                        # Jump neighboring hole
75*37da2899SCharles.Forsyth                        board[fromx] = 0;
76*37da2899SCharles.Forsyth                        board[jumpx] = 0;
77*37da2899SCharles.Forsyth                        board[tox] = 1;
78*37da2899SCharles.Forsyth                        pegs -= 1;
79*37da2899SCharles.Forsyth
80*37da2899SCharles.Forsyth                        # Try solving puzzle from here
81*37da2899SCharles.Forsyth                        if (puzzle()) {
82*37da2899SCharles.Forsyth                           #sys->print("(%d,%d) - (%d,%d)\n", r, c, tor, toc);
83*37da2899SCharles.Forsyth                           return 1;
84*37da2899SCharles.Forsyth                        }
85*37da2899SCharles.Forsyth                        # Dead end, put pegs back and try another move
86*37da2899SCharles.Forsyth                        board[fromx] = 1;
87*37da2899SCharles.Forsyth                        board[jumpx] = 1;
88*37da2899SCharles.Forsyth                        board[tox] = 0;
89*37da2899SCharles.Forsyth                        pegs += 1;
90*37da2899SCharles.Forsyth                     } # empty location
91*37da2899SCharles.Forsyth                  } # occupied neighbor
92*37da2899SCharles.Forsyth               } # still on board
93*37da2899SCharles.Forsyth            } # valid moves
94*37da2899SCharles.Forsyth      }
95*37da2899SCharles.Forsyth   return 0;
96*37da2899SCharles.Forsyth}
97*37da2899SCharles.Forsyth
98*37da2899SCharles.Forsythsolve(): int
99*37da2899SCharles.Forsyth{
100*37da2899SCharles.Forsyth   minpegs = pegs = (ORDER+1)*ORDER/2 - 1;
101*37da2899SCharles.Forsyth
102*37da2899SCharles.Forsyth   # Put pegs on board
103*37da2899SCharles.Forsyth   for (r := 0; r < ORDER; r += 1)
104*37da2899SCharles.Forsyth      for (c := 0; c < ORDER - r; c += 1)
105*37da2899SCharles.Forsyth         board[r*ORDER + c] = 1;
106*37da2899SCharles.Forsyth
107*37da2899SCharles.Forsyth   # Remove one peg
108*37da2899SCharles.Forsyth   board[0] = 0;
109*37da2899SCharles.Forsyth
110*37da2899SCharles.Forsyth   return puzzle();
111*37da2899SCharles.Forsyth}
112*37da2899SCharles.Forsyth
113*37da2899SCharles.Forsythinit(nil: ref Draw->Context, args: list of string)
114*37da2899SCharles.Forsyth{
115*37da2899SCharles.Forsyth   sys = load Sys Sys->PATH;
116*37da2899SCharles.Forsyth
117*37da2899SCharles.Forsyth   TRIALS: int;
118*37da2899SCharles.Forsyth   if (len args < 2)
119*37da2899SCharles.Forsyth      TRIALS = 1;
120*37da2899SCharles.Forsyth   else
121*37da2899SCharles.Forsyth      TRIALS = int hd tl args;
122*37da2899SCharles.Forsyth
123*37da2899SCharles.Forsyth   start := sys->millisec();
124*37da2899SCharles.Forsyth   for (trials := 0; trials < TRIALS; trials += 1)
125*37da2899SCharles.Forsyth      solved := solve();
126*37da2899SCharles.Forsyth   end := sys->millisec();
127*37da2899SCharles.Forsyth
128*37da2899SCharles.Forsyth   sys->print("%d ms\n", end - start);
129*37da2899SCharles.Forsyth
130*37da2899SCharles.Forsyth   if (! solved)
131*37da2899SCharles.Forsyth      sys->print("No solution\n");
132*37da2899SCharles.Forsyth   sys->print("Minimum pegs: %d\n", minpegs);
133*37da2899SCharles.Forsyth}
134