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