2023-07-31 23:46:28 +00:00
|
|
|
package bgammon
|
|
|
|
|
2023-09-08 06:35:27 +00:00
|
|
|
import (
|
2024-01-07 20:37:01 +00:00
|
|
|
"log"
|
2023-09-08 06:35:27 +00:00
|
|
|
"sort"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
)
|
2023-07-31 23:46:28 +00:00
|
|
|
|
|
|
|
const (
|
2024-01-06 02:18:54 +00:00
|
|
|
SpaceHomePlayer int8 = 0 // Current player's home.
|
|
|
|
SpaceHomeOpponent int8 = 25 // Opponent player's home.
|
|
|
|
SpaceBarPlayer int8 = 26 // Current player's bar.
|
|
|
|
SpaceBarOpponent int8 = 27 // Opponent player's bar.
|
2023-07-31 23:46:28 +00:00
|
|
|
)
|
|
|
|
|
2023-09-08 01:16:15 +00:00
|
|
|
// BoardSpaces is the total number of spaces needed to represent a backgammon board.
|
2023-08-23 00:05:35 +00:00
|
|
|
const BoardSpaces = 28
|
2023-07-31 23:46:28 +00:00
|
|
|
|
2023-09-08 01:16:15 +00:00
|
|
|
// NewBoard returns a new backgammon board represented as integers. Positive
|
|
|
|
// integers represent player 1's checkers and negative integers represent
|
|
|
|
// player 2's checkers. The board's space numbering is always from the
|
|
|
|
// perspective of the current player (i.e. the 1 space will always be in the
|
|
|
|
// current player's home board).
|
2024-01-07 20:37:01 +00:00
|
|
|
func NewBoard(variant int8) []int8 {
|
2024-01-06 02:18:54 +00:00
|
|
|
space := make([]int8, BoardSpaces)
|
2024-01-07 20:37:01 +00:00
|
|
|
switch variant {
|
|
|
|
case VariantBackgammon:
|
2023-11-25 03:15:50 +00:00
|
|
|
space[24], space[1] = 2, -2
|
|
|
|
space[19], space[6] = -5, 5
|
|
|
|
space[17], space[8] = -3, 3
|
|
|
|
space[13], space[12] = 5, -5
|
2024-01-07 20:37:01 +00:00
|
|
|
case VariantAceyDeucey, VariantTabula:
|
|
|
|
space[SpaceHomePlayer], space[SpaceHomeOpponent] = 15, -15
|
|
|
|
default:
|
|
|
|
log.Panicf("failed to initialize board: unknown variant: %d", variant)
|
2023-11-25 03:15:50 +00:00
|
|
|
}
|
2023-08-23 00:05:35 +00:00
|
|
|
return space
|
2023-07-31 23:46:28 +00:00
|
|
|
}
|
|
|
|
|
2023-09-08 01:16:15 +00:00
|
|
|
// HomeRange returns the start and end space of the provided player's home board.
|
2024-01-08 05:25:49 +00:00
|
|
|
func HomeRange(player int8, variant int8) (from int8, to int8) {
|
|
|
|
if player == 2 || variant == VariantTabula {
|
2023-08-23 00:05:35 +00:00
|
|
|
return 24, 19
|
2023-07-31 23:46:28 +00:00
|
|
|
}
|
2023-08-23 00:05:35 +00:00
|
|
|
return 1, 6
|
2023-07-31 23:46:28 +00:00
|
|
|
}
|
2023-09-07 07:21:58 +00:00
|
|
|
|
2023-09-08 01:16:15 +00:00
|
|
|
// RollForMove returns the roll needed to move a checker from the provided spaces.
|
2024-01-07 20:37:01 +00:00
|
|
|
func RollForMove(from int8, to int8, player int8, variant int8) int8 {
|
2023-09-07 07:21:58 +00:00
|
|
|
if !ValidSpace(from) || !ValidSpace(to) {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle standard moves.
|
|
|
|
if from >= 1 && from <= 24 && to >= 1 && to <= 24 {
|
2024-01-07 20:37:01 +00:00
|
|
|
return SpaceDiff(from, to, variant)
|
2023-09-07 07:21:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
playerHome := SpaceHomePlayer
|
|
|
|
playerBar := SpaceBarPlayer
|
|
|
|
oppHome := SpaceHomeOpponent
|
|
|
|
oppBar := SpaceBarOpponent
|
|
|
|
if player == 2 {
|
|
|
|
playerHome, oppHome, playerBar, oppBar = oppHome, playerHome, oppBar, playerBar
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle moves with special 'to' space.
|
|
|
|
if to == playerBar || to == oppBar || to == oppHome {
|
|
|
|
return 0
|
|
|
|
} else if to == playerHome {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle moves with special 'from' space.
|
|
|
|
if from == SpaceBarPlayer {
|
2024-01-08 05:25:49 +00:00
|
|
|
if player == 2 && variant != VariantTabula {
|
2023-09-07 07:21:58 +00:00
|
|
|
return 25 - to
|
|
|
|
} else {
|
|
|
|
return to
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2024-01-06 02:18:54 +00:00
|
|
|
func ParseSpace(space string) int8 {
|
2023-09-08 06:35:27 +00:00
|
|
|
i, err := strconv.Atoi(space)
|
|
|
|
if err != nil {
|
|
|
|
switch strings.ToLower(space) {
|
|
|
|
case "bar", "b":
|
|
|
|
return SpaceBarPlayer
|
|
|
|
case "off", "o", "home", "h":
|
|
|
|
return SpaceHomePlayer
|
|
|
|
}
|
|
|
|
return -1
|
|
|
|
}
|
2024-01-06 02:18:54 +00:00
|
|
|
return int8(i)
|
2023-09-08 06:35:27 +00:00
|
|
|
}
|
|
|
|
|
2024-01-06 02:18:54 +00:00
|
|
|
func compareMoveFunc(moves [][]int8) func(i, j int) bool {
|
2023-09-08 01:16:15 +00:00
|
|
|
return func(i, j int) bool {
|
|
|
|
if moves[j][0] == moves[i][0] {
|
|
|
|
return moves[j][1] < moves[i][1]
|
|
|
|
}
|
|
|
|
return moves[j][0] < moves[i][0]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SortMoves sorts moves from highest to lowest.
|
2024-01-06 02:18:54 +00:00
|
|
|
func SortMoves(moves [][]int8) {
|
2023-09-08 01:16:15 +00:00
|
|
|
sort.Slice(moves, compareMoveFunc(moves))
|
|
|
|
}
|