| // This program solves the (English) peg |
| // solitaire board game. |
| // http://en.wikipedia.org/wiki/Peg_solitaire |
| |
| package main |
| |
| import "fmt" |
| |
| const N = 11 + 1 // length of a row (+1 for \n) |
| |
| // The board must be surrounded by 2 illegal |
| // fields in each direction so that move() |
| // doesn't need to check the board boundaries. |
| // Periods represent illegal fields, |
| // ● are pegs, and ○ are holes. |
| |
| var board = []rune( |
| `........... |
| ........... |
| ....●●●.... |
| ....●●●.... |
| ..●●●●●●●.. |
| ..●●●○●●●.. |
| ..●●●●●●●.. |
| ....●●●.... |
| ....●●●.... |
| ........... |
| ........... |
| `) |
| |
| // center is the position of the center hole if |
| // there is a single one; otherwise it is -1. |
| var center int |
| |
| func init() { |
| n := 0 |
| for pos, field := range board { |
| if field == '○' { |
| center = pos |
| n++ |
| } |
| } |
| if n != 1 { |
| center = -1 // no single hole |
| } |
| } |
| |
| var moves int // number of times move is called |
| |
| // move tests if there is a peg at position pos that |
| // can jump over another peg in direction dir. If the |
| // move is valid, it is executed and move returns true. |
| // Otherwise, move returns false. |
| func move(pos, dir int) bool { |
| moves++ |
| if board[pos] == '●' && board[pos+dir] == '●' && board[pos+2*dir] == '○' { |
| board[pos] = '○' |
| board[pos+dir] = '○' |
| board[pos+2*dir] = '●' |
| return true |
| } |
| return false |
| } |
| |
| // unmove reverts a previously executed valid move. |
| func unmove(pos, dir int) { |
| board[pos] = '●' |
| board[pos+dir] = '●' |
| board[pos+2*dir] = '○' |
| } |
| |
| // solve tries to find a sequence of moves such that |
| // there is only one peg left at the end; if center is |
| // >= 0, that last peg must be in the center position. |
| // If a solution is found, solve prints the board after |
| // each move in a backward fashion (i.e., the last |
| // board position is printed first, all the way back to |
| // the starting board position). |
| func solve() bool { |
| var last, n int |
| for pos, field := range board { |
| // try each board position |
| if field == '●' { |
| // found a peg |
| for _, dir := range [...]int{-1, -N, +1, +N} { |
| // try each direction |
| if move(pos, dir) { |
| // a valid move was found and executed, |
| // see if this new board has a solution |
| if solve() { |
| unmove(pos, dir) |
| fmt.Println(string(board)) |
| return true |
| } |
| unmove(pos, dir) |
| } |
| } |
| last = pos |
| n++ |
| } |
| } |
| // tried each possible move |
| if n == 1 && (center < 0 || last == center) { |
| // there's only one peg left |
| fmt.Println(string(board)) |
| return true |
| } |
| // no solution found for this board |
| return false |
| } |
| |
| func main() { |
| if !solve() { |
| fmt.Println("no solution found") |
| } |
| fmt.Println(moves, "moves tried") |
| } |