mirror of
https://github.com/golang/go
synced 2024-11-24 13:30:09 -07:00
e5cf760e8a
Solves the (English) peg solitaire game. The board is represented by a 1-dimensional array for easy representation of directions with a single integer. The board's contents are chosen such that it can be printed with a direct string() conversion. R=r CC=adg, golang-dev https://golang.org/cl/2066042
120 lines
2.8 KiB
Go
120 lines
2.8 KiB
Go
// $G $F.go && $L $F.$A # don't run it - produces too much output
|
|
|
|
// Copyright 2010 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// This program solves the (English) peg solitaire board game.
|
|
// See also: http://en.wikipedia.org/wiki/Peg_solitaire
|
|
|
|
package main
|
|
|
|
const N = 11 + 1 // length of a board row (+1 for newline)
|
|
|
|
// 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 = []int(
|
|
`...........
|
|
...........
|
|
....●●●....
|
|
....●●●....
|
|
..●●●●●●●..
|
|
..●●●○●●●..
|
|
..●●●●●●●..
|
|
....●●●....
|
|
....●●●....
|
|
...........
|
|
...........
|
|
`)
|
|
|
|
|
|
// 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)
|
|
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
|
|
println(string(board))
|
|
return true
|
|
}
|
|
// no solution found for this board
|
|
return false
|
|
}
|
|
|
|
|
|
func main() {
|
|
if !solve() {
|
|
println("no solution found")
|
|
}
|
|
println(moves, "moves tried")
|
|
}
|