solitaire.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // This program solves the (English) peg
  2. // solitaire board game.
  3. // http://en.wikipedia.org/wiki/Peg_solitaire
  4. package main
  5. import "fmt"
  6. const N = 11 + 1 // length of a row (+1 for \n)
  7. // The board must be surrounded by 2 illegal
  8. // fields in each direction so that move()
  9. // doesn't need to check the board boundaries.
  10. // Periods represent illegal fields,
  11. // ● are pegs, and ○ are holes.
  12. var board = []rune(
  13. `...........
  14. ...........
  15. ....●●●....
  16. ....●●●....
  17. ..●●●●●●●..
  18. ..●●●○●●●..
  19. ..●●●●●●●..
  20. ....●●●....
  21. ....●●●....
  22. ...........
  23. ...........
  24. `)
  25. // center is the position of the center hole if
  26. // there is a single one; otherwise it is -1.
  27. var center int
  28. func init() {
  29. n := 0
  30. for pos, field := range board {
  31. if field == '○' {
  32. center = pos
  33. n++
  34. }
  35. }
  36. if n != 1 {
  37. center = -1 // no single hole
  38. }
  39. }
  40. var moves int // number of times move is called
  41. // move tests if there is a peg at position pos that
  42. // can jump over another peg in direction dir. If the
  43. // move is valid, it is executed and move returns true.
  44. // Otherwise, move returns false.
  45. func move(pos, dir int) bool {
  46. moves++
  47. if board[pos] == '●' && board[pos+dir] == '●' && board[pos+2*dir] == '○' {
  48. board[pos] = '○'
  49. board[pos+dir] = '○'
  50. board[pos+2*dir] = '●'
  51. return true
  52. }
  53. return false
  54. }
  55. // unmove reverts a previously executed valid move.
  56. func unmove(pos, dir int) {
  57. board[pos] = '●'
  58. board[pos+dir] = '●'
  59. board[pos+2*dir] = '○'
  60. }
  61. // solve tries to find a sequence of moves such that
  62. // there is only one peg left at the end; if center is
  63. // >= 0, that last peg must be in the center position.
  64. // If a solution is found, solve prints the board after
  65. // each move in a backward fashion (i.e., the last
  66. // board position is printed first, all the way back to
  67. // the starting board position).
  68. func solve() bool {
  69. var last, n int
  70. for pos, field := range board {
  71. // try each board position
  72. if field == '●' {
  73. // found a peg
  74. for _, dir := range [...]int{-1, -N, +1, +N} {
  75. // try each direction
  76. if move(pos, dir) {
  77. // a valid move was found and executed,
  78. // see if this new board has a solution
  79. if solve() {
  80. unmove(pos, dir)
  81. fmt.Println(string(board))
  82. return true
  83. }
  84. unmove(pos, dir)
  85. }
  86. }
  87. last = pos
  88. n++
  89. }
  90. }
  91. // tried each possible move
  92. if n == 1 && (center < 0 || last == center) {
  93. // there's only one peg left
  94. fmt.Println(string(board))
  95. return true
  96. }
  97. // no solution found for this board
  98. return false
  99. }
  100. func main() {
  101. if !solve() {
  102. fmt.Println("no solution found")
  103. }
  104. fmt.Println(moves, "moves tried")
  105. }