Rémy Oudompheng | fc3797a | 2012-02-22 00:19:59 +0100 | [diff] [blame] | 1 | // build |
| 2 | |
Robert Griesemer | e5cf760e | 2010-09-03 10:52:45 -0700 | [diff] [blame] | 3 | // Copyright 2010 The Go Authors. All rights reserved. |
| 4 | // Use of this source code is governed by a BSD-style |
| 5 | // license that can be found in the LICENSE file. |
| 6 | |
Rob Pike | 80a9783 | 2012-02-24 11:48:19 +1100 | [diff] [blame] | 7 | // Test general operation by solving a peg solitaire game. |
| 8 | // A version of this is in the Go playground. |
| 9 | // Don't run it - produces too much output. |
| 10 | |
Robert Griesemer | e5cf760e | 2010-09-03 10:52:45 -0700 | [diff] [blame] | 11 | // This program solves the (English) peg solitaire board game. |
| 12 | // See also: http://en.wikipedia.org/wiki/Peg_solitaire |
| 13 | |
| 14 | package main |
| 15 | |
| 16 | const N = 11 + 1 // length of a board row (+1 for newline) |
| 17 | |
| 18 | // The board must be surrounded by 2 illegal fields in each direction |
| 19 | // so that move() doesn't need to check the board boundaries. Periods |
| 20 | // represent illegal fields, ● are pegs, and ○ are holes. |
Russ Cox | db33959 | 2011-10-25 22:20:02 -0700 | [diff] [blame] | 21 | var board = []rune( |
Robert Griesemer | e5cf760e | 2010-09-03 10:52:45 -0700 | [diff] [blame] | 22 | `........... |
| 23 | ........... |
| 24 | ....●●●.... |
| 25 | ....●●●.... |
| 26 | ..●●●●●●●.. |
| 27 | ..●●●○●●●.. |
| 28 | ..●●●●●●●.. |
| 29 | ....●●●.... |
| 30 | ....●●●.... |
| 31 | ........... |
| 32 | ........... |
| 33 | `) |
| 34 | |
Robert Griesemer | e5cf760e | 2010-09-03 10:52:45 -0700 | [diff] [blame] | 35 | // center is the position of the center hole if there is a single one; |
| 36 | // otherwise it is -1. |
| 37 | var center int |
| 38 | |
| 39 | func init() { |
| 40 | n := 0 |
| 41 | for pos, field := range board { |
| 42 | if field == '○' { |
| 43 | center = pos |
| 44 | n++ |
| 45 | } |
| 46 | } |
| 47 | if n != 1 { |
| 48 | center = -1 // no single hole |
| 49 | } |
| 50 | } |
| 51 | |
Robert Griesemer | e5cf760e | 2010-09-03 10:52:45 -0700 | [diff] [blame] | 52 | var moves int // number of times move is called |
| 53 | |
| 54 | // move tests if there is a peg at position pos that can jump over another peg |
| 55 | // in direction dir. If the move is valid, it is executed and move returns true. |
| 56 | // Otherwise, move returns false. |
| 57 | func move(pos, dir int) bool { |
| 58 | moves++ |
| 59 | if board[pos] == '●' && board[pos+dir] == '●' && board[pos+2*dir] == '○' { |
| 60 | board[pos] = '○' |
| 61 | board[pos+dir] = '○' |
| 62 | board[pos+2*dir] = '●' |
| 63 | return true |
| 64 | } |
| 65 | return false |
| 66 | } |
| 67 | |
Robert Griesemer | e5cf760e | 2010-09-03 10:52:45 -0700 | [diff] [blame] | 68 | // unmove reverts a previously executed valid move. |
| 69 | func unmove(pos, dir int) { |
| 70 | board[pos] = '●' |
| 71 | board[pos+dir] = '●' |
| 72 | board[pos+2*dir] = '○' |
| 73 | } |
| 74 | |
Robert Griesemer | e5cf760e | 2010-09-03 10:52:45 -0700 | [diff] [blame] | 75 | // solve tries to find a sequence of moves such that there is only one peg left |
| 76 | // at the end; if center is >= 0, that last peg must be in the center position. |
| 77 | // If a solution is found, solve prints the board after each move in a backward |
| 78 | // fashion (i.e., the last board position is printed first, all the way back to |
| 79 | // the starting board position). |
| 80 | func solve() bool { |
| 81 | var last, n int |
| 82 | for pos, field := range board { |
| 83 | // try each board position |
| 84 | if field == '●' { |
| 85 | // found a peg |
| 86 | for _, dir := range [...]int{-1, -N, +1, +N} { |
| 87 | // try each direction |
| 88 | if move(pos, dir) { |
| 89 | // a valid move was found and executed, |
| 90 | // see if this new board has a solution |
| 91 | if solve() { |
| 92 | unmove(pos, dir) |
| 93 | println(string(board)) |
| 94 | return true |
| 95 | } |
| 96 | unmove(pos, dir) |
| 97 | } |
| 98 | } |
| 99 | last = pos |
| 100 | n++ |
| 101 | } |
| 102 | } |
| 103 | // tried each possible move |
| 104 | if n == 1 && (center < 0 || last == center) { |
| 105 | // there's only one peg left |
| 106 | println(string(board)) |
| 107 | return true |
| 108 | } |
| 109 | // no solution found for this board |
| 110 | return false |
| 111 | } |
| 112 | |
Robert Griesemer | e5cf760e | 2010-09-03 10:52:45 -0700 | [diff] [blame] | 113 | func main() { |
| 114 | if !solve() { |
| 115 | println("no solution found") |
| 116 | } |
| 117 | println(moves, "moves tried") |
| 118 | } |