Support hitting checkers and entering from the bar

This commit is contained in:
Trevor Slocum 2023-09-07 22:16:38 -07:00
parent fe68234adb
commit 042a9599b8
3 changed files with 59 additions and 77 deletions

View file

@ -3,33 +3,6 @@ package main
import "flag"
func main() {
/*
b := bgammon.NewBoard()
g := newServerGame(1)
g.Board[bgammon.SpaceBarPlayer] = 3
g.Board[bgammon.SpaceBarOpponent] = -2
g.Roll1 = 1
g.Roll2 = 3
g.Turn = 2
log.Println("initial legal moves")
log.Printf("%+v", g.LegalMoves())
//g.Moves = append(g.Moves, []int{6, 4})
log.Printf("Legal moves after %+v", g.Moves)
log.Printf("%+v", g.LegalMoves())
playerNumber := 2
go func() {
time.Sleep(100 * time.Millisecond)
scanner := bufio.NewScanner(bytes.NewReader(g.BoardState(playerNumber)))
for scanner.Scan() {
log.Printf("%s", append([]byte("notice "), scanner.Bytes()...))
}
}()
select {}
*/
var address string
flag.StringVar(&address, "tcp", "localhost:1337", "TCP listen address")
flag.Parse()

View file

@ -617,11 +617,7 @@ COMMANDS:
continue
}
nextTurn := 1
if clientGame.Turn == 1 {
nextTurn = 2
}
clientGame.Roll1, clientGame.Roll2, clientGame.Moves, clientGame.Turn = 0, 0, nil, nextTurn
clientGame.NextTurn()
clientGame.eachClient(func(client *serverClient) {
clientGame.sendBoard(client)
})

103
game.go
View file

@ -50,6 +50,17 @@ func (g *Game) Copy() *Game {
return newGame
}
func (g *Game) NextTurn() {
nextTurn := 1
if g.Turn == 1 {
nextTurn = 2
}
g.Roll1, g.Roll2 = 0, 0
g.Turn = nextTurn
g.Moves = g.Moves[:0]
g.boardStates = g.boardStates[:0]
}
func (g *Game) turnPlayer() Player {
switch g.Turn {
case 2:
@ -89,8 +100,6 @@ func (g *Game) iterateSpaces(from int, to int, f func(space int, spaceCount int)
// AddMoves adds moves to the game state. Adding a backwards move will remove the equivalent existing move.
func (g *Game) AddMoves(moves [][]int) bool {
log.Printf("ADD MOVES - %+v", moves)
delta := 1
if g.Turn == 2 {
delta = -1
@ -114,7 +123,6 @@ VALIDATEMOVES:
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 := gameCopy.Moves[i]
@ -124,7 +132,6 @@ VALIDATEMOVES:
continue VALIDATEMOVES
}
}
log.Printf("FAILED MOVE %d/%d", move[0], move[1])
return false
}
@ -137,51 +144,47 @@ ADDMOVES:
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(gameCopy.Board))
copy(boardState, gameCopy.Board)
gameCopy.boardStates = append(gameCopy.boardStates, boardState)
gameCopy.Board[move[0]] -= delta
opponentCheckers := OpponentCheckers(gameCopy.Board[lm[1]], gameCopy.Turn)
if opponentCheckers == 1 {
if opponentCheckers == 1 { // Hit checker.
gameCopy.Board[move[1]] = delta
// Move opponent checker to bar.
barSpace := SpaceBarOpponent
if g.Turn == 2 {
barSpace = SpaceBarPlayer
}
gameCopy.Board[barSpace] += delta * -1
} else if opponentCheckers != 0 {
return false
} else {
gameCopy.Board[move[1]] += delta
}
gameCopy.Moves = append(gameCopy.Moves, []int{move[0], move[1]})
log.Printf("NEW MOVES %+v", gameCopy.Moves)
continue ADDMOVES
}
}
}
for _, move := range undoMoves {
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 := gameCopy.Moves[i]
if move[0] == gameMove[1] && move[1] == gameMove[0] {
log.Printf("UNDO MOV %d/%d", gameMove[0], gameMove[1])
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])
}
log.Printf("FAILED UNDO MOVE %d/%d", move[0], move[1])
return false
}
@ -254,43 +257,53 @@ func (g *Game) LegalMoves() [][]int {
useDiceRoll(move[0], move[1])
}
canBearOff := CanBearOff(g.Board, g.Turn)
var moves [][]int
for space := range g.Board {
if space == SpaceHomePlayer || space == SpaceHomeOpponent { // No entering from home spaces (until acey-deucey is added).
continue
}
checkers := g.Board[space]
playerCheckers := PlayerCheckers(checkers, g.Turn)
if playerCheckers == 0 {
continue
}
barSpace := SpaceBarPlayer
if g.Turn == 2 {
barSpace = SpaceBarOpponent
}
mustEnter := g.Board[barSpace] != 0
if space == SpaceBarPlayer || space == SpaceBarOpponent {
// Enter from bar.
from, to := HomeRange(g.Turn)
g.iterateSpaces(from, to, func(homeSpace int, spaceCount int) {
if haveDiceRoll(space, homeSpace) == 0 {
return
if mustEnter { // Must enter from bar.
from, to := HomeRange(g.opponentPlayer().Number)
g.iterateSpaces(from, to, func(homeSpace int, spaceCount int) {
available := haveDiceRoll(barSpace, homeSpace)
if available == 0 {
return
}
opponentCheckers := OpponentCheckers(g.Board[homeSpace], g.Turn)
if opponentCheckers <= 1 {
movable := PlayerCheckers(g.Board[barSpace], g.Turn)
if movable > available {
movable = available
}
if spaceCount != g.Roll1 && spaceCount != g.Roll2 {
return
for i := 0; i < movable; i++ {
moves = append(moves, []int{barSpace, homeSpace})
}
opponentCheckers := OpponentCheckers(g.Board[homeSpace], g.Turn)
if opponentCheckers <= 1 {
moves = append(moves, []int{space, homeSpace})
}
})
} else {
}
})
} else {
canBearOff := CanBearOff(g.Board, g.Turn)
for space := range g.Board {
if space == SpaceBarPlayer || space == SpaceBarOpponent { // Handled above.
continue
} else if space == SpaceHomePlayer || space == SpaceHomeOpponent { // No entering from home spaces (until acey-deucey is added).
continue
}
checkers := g.Board[space]
playerCheckers := PlayerCheckers(checkers, g.Turn)
if playerCheckers == 0 {
continue
}
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 {
@ -327,9 +340,9 @@ func (g *Game) LegalMoves() [][]int {
}
}
})
}
}
return moves
}