Support bearing off
This commit is contained in:
parent
71a50ce22b
commit
68f0cdcd7c
6 changed files with 264 additions and 92 deletions
59
board.go
59
board.go
|
@ -10,9 +10,9 @@ package bgammon
|
|||
// 1-24 for 24 spaces, 2 spaces for bar, 2 spaces for home
|
||||
const (
|
||||
SpaceHomePlayer = 0
|
||||
SpaceBarPlayer = 25
|
||||
SpaceBarOpponent = 26
|
||||
SpaceHomeOpponent = 27
|
||||
SpaceHomeOpponent = 25
|
||||
SpaceBarPlayer = 26
|
||||
SpaceBarOpponent = 27
|
||||
)
|
||||
|
||||
const BoardSpaces = 28
|
||||
|
@ -32,3 +32,56 @@ func HomeRange(player int) (from int, to int) {
|
|||
}
|
||||
return 1, 6
|
||||
}
|
||||
|
||||
func RollForMove(from int, to int, player int) int {
|
||||
if !ValidSpace(from) || !ValidSpace(to) {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Handle standard moves.
|
||||
if from >= 1 && from <= 24 && to >= 1 && to <= 24 {
|
||||
return SpaceDiff(from, to)
|
||||
}
|
||||
|
||||
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 {
|
||||
if player == 2 {
|
||||
return 25 - to
|
||||
} else {
|
||||
return to
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func CanBearOff(board []int, player int) bool {
|
||||
homeStart, homeEnd := HomeRange(player)
|
||||
homeStart, homeEnd = minInt(homeStart, homeEnd), maxInt(homeStart, homeEnd)
|
||||
|
||||
ok := true
|
||||
for i := 1; i < 24; i++ {
|
||||
if (i < homeStart || i > homeEnd) && PlayerCheckers(board[i], player) > 0 {
|
||||
ok = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if ok && (PlayerCheckers(board[SpaceBarPlayer], player) > 0 || PlayerCheckers(board[SpaceBarOpponent], player) > 0) {
|
||||
ok = false
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
|
|
@ -70,9 +70,13 @@ func (g *serverGame) sendBoard(client *serverClient) {
|
|||
log.Println(g.Game.Board)
|
||||
|
||||
ev.GameState.Game = ev.GameState.Copy()
|
||||
|
||||
// Flip board.
|
||||
for space := 1; space <= 24; space++ {
|
||||
ev.Board[space] = g.Game.Board[bgammon.FlipSpace(space, client.playerNumber)]
|
||||
}
|
||||
ev.Board[bgammon.SpaceHomePlayer], ev.Board[bgammon.SpaceHomeOpponent] = ev.Board[bgammon.SpaceHomeOpponent], ev.Board[bgammon.SpaceHomePlayer]
|
||||
ev.Board[bgammon.SpaceBarPlayer], ev.Board[bgammon.SpaceBarOpponent] = ev.Board[bgammon.SpaceBarOpponent], ev.Board[bgammon.SpaceBarPlayer]
|
||||
|
||||
ev.Moves = bgammon.FlipMoves(g.Game.Moves, client.playerNumber)
|
||||
|
||||
|
@ -80,9 +84,6 @@ func (g *serverGame) sendBoard(client *serverClient) {
|
|||
for i := range ev.GameState.Available {
|
||||
ev.GameState.Available[i][0], ev.GameState.Available[i][1] = bgammon.FlipSpace(legalMoves[i][0], client.playerNumber), bgammon.FlipSpace(legalMoves[i][1], client.playerNumber)
|
||||
}
|
||||
|
||||
log.Println(g.Game.Board)
|
||||
log.Println("AFTER")
|
||||
}
|
||||
|
||||
client.sendEvent(ev)
|
||||
|
@ -226,3 +227,7 @@ func (g *serverGame) opponent(client *serverClient) *serverClient {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *serverGame) terminated() bool {
|
||||
return g.client1 == nil && g.client2 == nil
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ type server struct {
|
|||
newClientIDs chan int
|
||||
commands chan serverCommand
|
||||
|
||||
gamesLock sync.RWMutex
|
||||
clientsLock sync.RWMutex // TODO need RW?
|
||||
}
|
||||
|
||||
|
@ -42,6 +43,7 @@ func newServer() *server {
|
|||
go s.handleNewGameIDs()
|
||||
go s.handleNewClientIDs()
|
||||
go s.handleCommands()
|
||||
go s.handleTerminatedGames()
|
||||
return s
|
||||
}
|
||||
|
||||
|
@ -92,6 +94,27 @@ func (s *server) removeClient(c *serverClient) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *server) handleTerminatedGames() {
|
||||
t := time.NewTicker(time.Minute)
|
||||
for range t.C {
|
||||
s.gamesLock.Lock()
|
||||
|
||||
i := 0
|
||||
for _, g := range s.games {
|
||||
if !g.terminated() {
|
||||
s.games[i] = g
|
||||
i++
|
||||
}
|
||||
}
|
||||
for j := i; j < len(s.games); j++ {
|
||||
s.games[j] = nil // Allow memory to be deallocated.
|
||||
}
|
||||
s.games = s.games[:i]
|
||||
|
||||
s.gamesLock.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) handleConnection(conn net.Conn) {
|
||||
log.Printf("new conn %+v", conn)
|
||||
|
||||
|
@ -185,6 +208,9 @@ func (s *server) sendWelcome(c *serverClient) {
|
|||
}
|
||||
|
||||
func (s *server) gameByClient(c *serverClient) *serverGame {
|
||||
s.gamesLock.RLock()
|
||||
defer s.gamesLock.RUnlock()
|
||||
|
||||
for _, g := range s.games {
|
||||
if g.client1 == c || g.client2 == c {
|
||||
return g
|
||||
|
@ -311,7 +337,12 @@ COMMANDS:
|
|||
opponent.sendEvent(ev)
|
||||
case bgammon.CommandList, "ls":
|
||||
ev := &bgammon.EventList{}
|
||||
|
||||
s.gamesLock.RLock()
|
||||
for _, g := range s.games {
|
||||
if g.terminated() {
|
||||
continue
|
||||
}
|
||||
ev.Games = append(ev.Games, bgammon.GameListing{
|
||||
ID: g.id,
|
||||
Password: len(g.password) != 0,
|
||||
|
@ -319,6 +350,8 @@ COMMANDS:
|
|||
Name: string(g.name),
|
||||
})
|
||||
}
|
||||
s.gamesLock.RUnlock()
|
||||
|
||||
cmd.client.sendEvent(ev)
|
||||
case bgammon.CommandCreate, "c":
|
||||
sendUsage := func() {
|
||||
|
@ -362,7 +395,10 @@ COMMANDS:
|
|||
if !g.addClient(cmd.client) {
|
||||
log.Panicf("failed to add client to newly created game %+v %+v", g, cmd.client)
|
||||
}
|
||||
s.games = append(s.games, g) // TODO lock
|
||||
|
||||
s.gamesLock.Lock()
|
||||
s.games = append(s.games, g)
|
||||
s.gamesLock.Unlock()
|
||||
case bgammon.CommandJoin, "j":
|
||||
if clientGame != nil {
|
||||
cmd.client.sendEvent(&bgammon.EventFailedJoin{
|
||||
|
@ -385,12 +421,17 @@ COMMANDS:
|
|||
continue
|
||||
}
|
||||
|
||||
s.gamesLock.Lock()
|
||||
for _, g := range s.games {
|
||||
if g.terminated() {
|
||||
continue
|
||||
}
|
||||
if g.id == gameID {
|
||||
if len(g.password) != 0 && (len(params) < 2 || !bytes.Equal(g.password, bytes.Join(params[2:], []byte(" ")))) {
|
||||
cmd.client.sendEvent(&bgammon.EventFailedJoin{
|
||||
Reason: "Invalid password.",
|
||||
})
|
||||
s.gamesLock.Unlock()
|
||||
continue COMMANDS
|
||||
}
|
||||
|
||||
|
@ -399,9 +440,11 @@ COMMANDS:
|
|||
Reason: "Game is full.",
|
||||
})
|
||||
}
|
||||
s.gamesLock.Unlock()
|
||||
continue COMMANDS
|
||||
}
|
||||
}
|
||||
s.gamesLock.Unlock()
|
||||
case bgammon.CommandLeave, "l":
|
||||
if clientGame == nil {
|
||||
cmd.client.sendEvent(&bgammon.EventFailedLeave{
|
||||
|
@ -496,6 +539,7 @@ COMMANDS:
|
|||
To: to,
|
||||
Reason: "Illegal move.",
|
||||
})
|
||||
continue COMMANDS
|
||||
}
|
||||
|
||||
originalFrom, originalTo := from, to
|
||||
|
@ -595,6 +639,19 @@ COMMANDS:
|
|||
cmd.client.Terminate("Client disconnected")
|
||||
case bgammon.CommandPong:
|
||||
// Do nothing.
|
||||
|
||||
// TODO remove
|
||||
case "endgame":
|
||||
if clientGame == nil {
|
||||
cmd.client.sendNotice("You are not currently in a game.")
|
||||
continue
|
||||
}
|
||||
|
||||
clientGame.Board = []int{0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0}
|
||||
|
||||
clientGame.eachClient(func(client *serverClient) {
|
||||
clientGame.sendBoard(client)
|
||||
})
|
||||
default:
|
||||
log.Printf("unknown command %s", keyword)
|
||||
}
|
||||
|
|
208
game.go
208
game.go
|
@ -35,16 +35,18 @@ func NewGame() *Game {
|
|||
|
||||
func (g *Game) Copy() *Game {
|
||||
newGame := &Game{
|
||||
Board: make([]int, len(g.Board)),
|
||||
Player1: g.Player1,
|
||||
Player2: g.Player2,
|
||||
Turn: g.Turn,
|
||||
Roll1: g.Roll1,
|
||||
Roll2: g.Roll2,
|
||||
Moves: make([][]int, len(g.Moves)),
|
||||
Board: make([]int, len(g.Board)),
|
||||
Player1: g.Player1,
|
||||
Player2: g.Player2,
|
||||
Turn: g.Turn,
|
||||
Roll1: g.Roll1,
|
||||
Roll2: g.Roll2,
|
||||
Moves: make([][]int, len(g.Moves)),
|
||||
boardStates: make([][]int, len(g.boardStates)),
|
||||
}
|
||||
copy(newGame.Board, g.Board)
|
||||
copy(newGame.Moves, g.Moves)
|
||||
copy(newGame.boardStates, g.boardStates)
|
||||
return newGame
|
||||
}
|
||||
|
||||
|
@ -67,7 +69,7 @@ func (g *Game) opponentPlayer() Player {
|
|||
}
|
||||
|
||||
func (g *Game) iterateSpaces(from int, to int, f func(space int, spaceCount int)) {
|
||||
if from == to {
|
||||
if from == to || from < 1 || from > 24 || to < 1 || to > 24 {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -97,26 +99,25 @@ func (g *Game) AddMoves(moves [][]int) bool {
|
|||
var addMoves [][]int
|
||||
var undoMoves [][]int
|
||||
|
||||
newBoard := make([]int, len(g.Board))
|
||||
var boardStates [][]int
|
||||
copy(newBoard, g.Board)
|
||||
gameCopy := g.Copy()
|
||||
|
||||
validateOffset := 0
|
||||
VALIDATEMOVES:
|
||||
for _, move := range moves {
|
||||
l := g.LegalMoves()
|
||||
l := gameCopy.LegalMoves()
|
||||
for _, lm := range l {
|
||||
if lm[0] == move[0] && lm[1] == move[1] {
|
||||
addMoves = append(addMoves, []int{move[0], move[1]})
|
||||
continue VALIDATEMOVES
|
||||
}
|
||||
}
|
||||
if len(g.Moves) > 0 {
|
||||
i := len(g.Moves) - 1 - validateOffset
|
||||
if len(gameCopy.Moves) > 0 {
|
||||
i := len(gameCopy.Moves) - 1 - validateOffset
|
||||
if i < 0 {
|
||||
log.Printf("FAILED MOVE %d/%d", move[0], move[1])
|
||||
return false
|
||||
}
|
||||
gameMove := g.Moves[i]
|
||||
gameMove := gameCopy.Moves[i]
|
||||
if move[0] == gameMove[1] && move[1] == gameMove[0] {
|
||||
undoMoves = append(undoMoves, []int{gameMove[1], gameMove[0]})
|
||||
validateOffset++
|
||||
|
@ -133,51 +134,49 @@ VALIDATEMOVES:
|
|||
|
||||
ADDMOVES:
|
||||
for _, move := range addMoves {
|
||||
l := g.LegalMoves()
|
||||
l := gameCopy.LegalMoves()
|
||||
for _, lm := range l {
|
||||
if lm[0] == move[0] && lm[1] == move[1] {
|
||||
log.Printf("ADD MOV %d/%d", lm[0], lm[1])
|
||||
log.Printf("BOARD %+v", gameCopy.Board)
|
||||
log.Printf("LEGAL %+v", l)
|
||||
log.Printf("ROLL %+v %+v", gameCopy.Roll1, gameCopy.Roll2)
|
||||
|
||||
boardState := make([]int, len(newBoard))
|
||||
copy(boardState, newBoard)
|
||||
boardStates = append(boardStates, boardState)
|
||||
boardState := make([]int, len(gameCopy.Board))
|
||||
copy(boardState, gameCopy.Board)
|
||||
gameCopy.boardStates = append(gameCopy.boardStates, boardState)
|
||||
|
||||
newBoard[move[0]] -= delta
|
||||
opponentCheckers := OpponentCheckers(newBoard[lm[1]], g.Turn)
|
||||
gameCopy.Board[move[0]] -= delta
|
||||
opponentCheckers := OpponentCheckers(gameCopy.Board[lm[1]], gameCopy.Turn)
|
||||
if opponentCheckers == 1 {
|
||||
newBoard[move[1]] = delta
|
||||
gameCopy.Board[move[1]] = delta
|
||||
} else {
|
||||
newBoard[move[1]] += delta
|
||||
gameCopy.Board[move[1]] += delta
|
||||
}
|
||||
|
||||
gameCopy.Moves = append(gameCopy.Moves, []int{move[0], move[1]})
|
||||
log.Printf("NEW MOVES %+v", gameCopy.Moves)
|
||||
continue ADDMOVES
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(addMoves) != 0 {
|
||||
g.Moves = append(g.Moves, moves...)
|
||||
g.boardStates = append(g.boardStates, boardStates...)
|
||||
}
|
||||
|
||||
newMoves := make([][]int, len(g.Moves))
|
||||
copy(newMoves, g.Moves)
|
||||
newBoardStates := make([][]int, len(g.boardStates))
|
||||
copy(newBoardStates, g.boardStates)
|
||||
for _, move := range undoMoves {
|
||||
log.Printf("TRY UNDO MOV %d/%d %+v", move[0], move[1], newMoves)
|
||||
if len(g.Moves) > 0 {
|
||||
i := len(newMoves) - 1
|
||||
log.Printf("TRY UNDO MOV %d/%d %+v", move[0], move[1], gameCopy.Moves)
|
||||
if len(gameCopy.Moves) > 0 {
|
||||
i := len(gameCopy.Moves) - 1
|
||||
if i < 0 {
|
||||
log.Printf("FAILED UNDO MOVE %d/%d", move[0], move[1])
|
||||
return false
|
||||
}
|
||||
gameMove := newMoves[i]
|
||||
gameMove := gameCopy.Moves[i]
|
||||
if move[0] == gameMove[1] && move[1] == gameMove[0] {
|
||||
log.Printf("UNDO MOV %d/%d", gameMove[0], gameMove[1])
|
||||
|
||||
copy(newBoard, g.boardStates[i])
|
||||
newMoves = g.Moves[:i]
|
||||
newBoardStates = g.boardStates[:i]
|
||||
log.Printf("NEW MOVES %+v", newMoves)
|
||||
copy(gameCopy.Board, gameCopy.boardStates[i])
|
||||
gameCopy.boardStates = gameCopy.boardStates[:i]
|
||||
|
||||
gameCopy.Moves = gameCopy.Moves[:i]
|
||||
log.Printf("NEW MOVES %+v", gameCopy.Moves)
|
||||
continue
|
||||
}
|
||||
log.Printf("COMPARE MOV %d/%d %d/%d", gameMove[0], gameMove[1], move[0], move[1])
|
||||
|
@ -185,12 +184,10 @@ ADDMOVES:
|
|||
log.Printf("FAILED UNDO MOVE %d/%d", move[0], move[1])
|
||||
return false
|
||||
}
|
||||
if len(undoMoves) != 0 {
|
||||
g.Moves = newMoves
|
||||
g.boardStates = newBoardStates
|
||||
}
|
||||
|
||||
g.Board = newBoard
|
||||
g.Board = gameCopy.Board
|
||||
g.Moves = gameCopy.Moves
|
||||
g.boardStates = gameCopy.boardStates
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -207,42 +204,61 @@ func (g *Game) LegalMoves() [][]int {
|
|||
rolls = append(rolls, g.Roll1, g.Roll2)
|
||||
}
|
||||
|
||||
haveDiceRoll := func(from, to int) bool {
|
||||
haveDiceRoll := func(from, to int) int {
|
||||
// TODO diff needs to account for bar and home special spaces
|
||||
diff := to - from
|
||||
if diff < 0 {
|
||||
diff *= -1
|
||||
}
|
||||
diff := SpaceDiff(from, to)
|
||||
var c int
|
||||
for _, roll := range rolls {
|
||||
if roll == diff {
|
||||
return true
|
||||
c++
|
||||
}
|
||||
}
|
||||
return false
|
||||
return c
|
||||
}
|
||||
|
||||
haveBearOffDiceRoll := func(diff int) int {
|
||||
var c int
|
||||
for _, roll := range rolls {
|
||||
if roll >= diff {
|
||||
c++
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
useDiceRoll := func(from, to int) {
|
||||
// TODO diff needs to account for bar and home special spaces
|
||||
diff := to - from
|
||||
if diff < 0 {
|
||||
diff *= -1
|
||||
if to == SpaceHomePlayer || to == SpaceHomeOpponent {
|
||||
needRoll := from
|
||||
if to == SpaceHomeOpponent {
|
||||
needRoll = 25 - from
|
||||
}
|
||||
for i, roll := range rolls {
|
||||
if roll >= needRoll {
|
||||
rolls = append(rolls[:i], rolls[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Panicf("no dice roll to use for %d/%d", from, to)
|
||||
}
|
||||
|
||||
diff := SpaceDiff(from, to)
|
||||
for i, roll := range rolls {
|
||||
if roll == diff {
|
||||
rolls = append(rolls[:i], rolls[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Panicf("tried to use non-existent dice roll %d-%d, have %+v", from, to, rolls)
|
||||
}
|
||||
|
||||
for _, move := range g.Moves {
|
||||
useDiceRoll(move[0], move[1])
|
||||
}
|
||||
|
||||
canBearOff := CanBearOff(g.Board, g.Turn)
|
||||
|
||||
var moves [][]int
|
||||
for space := range g.Board {
|
||||
if space == SpaceHomePlayer || space == SpaceHomeOpponent {
|
||||
if space == SpaceHomePlayer || space == SpaceHomeOpponent { // No entering from home spaces (until acey-deucey is added).
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -256,7 +272,7 @@ func (g *Game) LegalMoves() [][]int {
|
|||
// Enter from bar.
|
||||
from, to := HomeRange(g.Turn)
|
||||
g.iterateSpaces(from, to, func(homeSpace int, spaceCount int) {
|
||||
if !haveDiceRoll(space, homeSpace) {
|
||||
if haveDiceRoll(space, homeSpace) == 0 {
|
||||
return
|
||||
}
|
||||
if spaceCount != g.Roll1 && spaceCount != g.Roll2 {
|
||||
|
@ -268,6 +284,24 @@ func (g *Game) LegalMoves() [][]int {
|
|||
}
|
||||
})
|
||||
} else {
|
||||
if canBearOff {
|
||||
homeSpace := SpaceHomePlayer
|
||||
if g.Turn == 2 {
|
||||
homeSpace = SpaceHomeOpponent
|
||||
}
|
||||
available := haveBearOffDiceRoll(SpaceDiff(space, homeSpace))
|
||||
//log.Printf("HAVE BEAR OFF DICE ROLL %d for %d/%d (diff %d)", available, space, homeSpace, SpaceDiff(space, homeSpace))
|
||||
if available > 0 {
|
||||
movable := playerCheckers
|
||||
if movable > available {
|
||||
movable = available
|
||||
}
|
||||
for i := 0; i < movable; i++ {
|
||||
moves = append(moves, []int{space, homeSpace})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Move normally.
|
||||
lastSpace := 1
|
||||
dir := -1
|
||||
|
@ -276,34 +310,24 @@ func (g *Game) LegalMoves() [][]int {
|
|||
dir = 1
|
||||
}
|
||||
|
||||
if space == lastSpace {
|
||||
continue // TODO check if all pieces in home
|
||||
}
|
||||
|
||||
g.iterateSpaces(space+dir, lastSpace, func(to int, spaceCount int) {
|
||||
if !haveDiceRoll(space, to) {
|
||||
available := haveDiceRoll(space, to)
|
||||
if available == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if to == SpaceHomePlayer || to == SpaceHomeOpponent {
|
||||
return // TODO
|
||||
}
|
||||
|
||||
opponentCheckers := OpponentCheckers(g.Board[to], g.Turn)
|
||||
if opponentCheckers <= 1 {
|
||||
movable := 1
|
||||
if g.Roll1 == g.Roll2 {
|
||||
movable = playerCheckers
|
||||
if movable > 4 {
|
||||
movable = 4
|
||||
}
|
||||
movable := playerCheckers
|
||||
if movable > available {
|
||||
movable = available
|
||||
}
|
||||
for i := 0; i < movable; i++ {
|
||||
moves = append(moves, []int{space, to})
|
||||
//log.Printf("ADD MOVE %d-%d", space, to)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
return moves
|
||||
|
@ -541,7 +565,29 @@ func (g *Game) BoardState(player int) []byte {
|
|||
return t.Bytes()
|
||||
}
|
||||
|
||||
func spaceDiff(from int, to int) int {
|
||||
func SpaceDiff(from int, to int) int {
|
||||
if from < 0 || from > 27 || to < 0 || to > 27 {
|
||||
return 0
|
||||
} else if from == SpaceHomePlayer || from == SpaceHomeOpponent || to == SpaceBarPlayer || to == SpaceBarOpponent {
|
||||
return 0
|
||||
}
|
||||
|
||||
if (from == SpaceBarPlayer || from == SpaceBarOpponent) && (to == SpaceBarPlayer || to == SpaceBarOpponent || to == SpaceHomePlayer || to == SpaceHomeOpponent) {
|
||||
return 0
|
||||
}
|
||||
|
||||
if from == SpaceBarPlayer {
|
||||
return 25 - to
|
||||
} else if from == SpaceBarOpponent {
|
||||
return to
|
||||
}
|
||||
|
||||
if to == SpaceHomePlayer {
|
||||
return from
|
||||
} else if to == SpaceHomeOpponent {
|
||||
return 25 - from
|
||||
}
|
||||
|
||||
diff := to - from
|
||||
if diff < 0 {
|
||||
return diff * -1
|
||||
|
@ -622,15 +668,7 @@ func FormatAndFlipMoves(moves [][]int, player int) []byte {
|
|||
}
|
||||
|
||||
func ValidSpace(space int) bool {
|
||||
if space < 1 || space > 24 {
|
||||
return false
|
||||
}
|
||||
switch space {
|
||||
case SpaceHomePlayer, SpaceHomeOpponent, SpaceBarPlayer, SpaceBarOpponent:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return space >= 0 && space <= 27
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
|
@ -74,3 +74,7 @@ func (g *GameState) NeedRoll() bool {
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameState) NeedOk() bool {
|
||||
return g.Turn != 0 && g.Turn == g.PlayerNumber && len(g.Available) == 0
|
||||
}
|
||||
|
|
15
util.go
Normal file
15
util.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package bgammon
|
||||
|
||||
func minInt(a int, b int) int {
|
||||
if b < a {
|
||||
return b
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func maxInt(a int, b int) int {
|
||||
if b > a {
|
||||
return b
|
||||
}
|
||||
return a
|
||||
}
|
Loading…
Reference in a new issue