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