bgammon/gamestate.go
2024-06-27 18:55:40 -07:00

151 lines
3.9 KiB
Go

package bgammon
import (
"log"
)
type GameState struct {
*Game
PlayerNumber int8
Available [][]int8 // Legal moves.
Forced bool // A forced move is being played automatically.
Spectating bool
}
func (g *GameState) OpponentPlayer() Player {
if g.PlayerNumber == 1 {
return g.Player2
}
return g.Player1
}
func (g *GameState) LocalPlayer() Player {
if g.PlayerNumber == 1 {
return g.Player1
}
return g.Player2
}
func (g *GameState) SpaceAt(x int8, y int8) int8 {
if (x < 0 || x > 12) || (y < 0 || y > 9) {
return -1
}
var space int8 = -1
if x <= 5 {
space = x + 1
} else if x == 6 {
if y <= 4 {
return SpaceBarOpponent
} else {
return SpaceBarPlayer
}
} else {
space = x
}
if g.PlayerNumber == 2 {
if y <= 4 {
space = 25 - space
}
} else {
if y <= 4 {
space += 12
} else {
space = 13 - space
}
}
return space
}
// Pips returns the pip count for the specified player.
func (g *GameState) Pips(player int8) int {
var pips int
var spaceValue int
if player == 1 {
pips += int(PlayerCheckers(g.Board[SpaceBarPlayer], player)) * 25
} else {
pips += int(PlayerCheckers(g.Board[SpaceBarOpponent], player)) * 25
}
if g.Variant != VariantBackgammon {
if player == 1 && !g.Player1.Entered {
pips += int(PlayerCheckers(g.Board[SpaceHomePlayer], player)) * 25
} else if player == 2 && !g.Player2.Entered {
pips += int(PlayerCheckers(g.Board[SpaceHomeOpponent], player)) * 25
}
}
for i := 1; i < 25; i++ {
if player == g.PlayerNumber && g.Variant != VariantTabula {
spaceValue = i
} else {
spaceValue = 25 - i
}
pips += int(PlayerCheckers(g.Board[i], player)) * spaceValue
}
return pips
}
// MayDouble returns whether the player may send the 'double' command.
func (g *GameState) MayDouble() bool {
if g.Spectating || g.Winner != 0 || g.Variant != VariantBackgammon {
return false
}
return g.Points != 1 && g.Turn != 0 && g.Turn == g.PlayerNumber && g.Roll1 == 0 && !g.DoubleOffered && (g.DoublePlayer == 0 || g.DoublePlayer == g.PlayerNumber)
}
// MayRoll returns whether the player may send the 'roll' command.
func (g *GameState) MayRoll() bool {
if g.Spectating || g.Winner != 0 || g.DoubleOffered {
return false
}
switch g.Turn {
case 0:
if g.PlayerNumber == 1 {
return g.Player2.Name != "" && (g.Roll1 == 0 || (g.Roll1 == g.Roll2))
} else if g.PlayerNumber == 2 {
return g.Player1.Name != "" && (g.Roll2 == 0 || (g.Roll1 == g.Roll2))
}
return false
case 1:
return g.PlayerNumber == g.Turn && g.Player2.Name != "" && g.Roll1 == 0
case 2:
return g.PlayerNumber == g.Turn && g.Player1.Name != "" && g.Roll1 == 0
default:
log.Panicf("unknown turn %d", g.Turn)
return false
}
}
// MayChooseRoll returns whether the player may send the 'ok' command, supplying
// the chosen roll. This command only applies to acey-deucey games.
func (g *GameState) MayChooseRoll() bool {
return g.Variant == VariantAceyDeucey && g.Turn != 0 && g.Turn == g.PlayerNumber && ((g.Roll1 == 1 && g.Roll2 == 2) || (g.Roll1 == 2 && g.Roll2 == 1)) && len(g.Moves) == 2
}
// MayOK returns whether the player may send the 'ok' command.
func (g *GameState) MayOK() bool {
if g.Spectating || g.Winner != 0 {
return false
} else if g.Turn != 0 && g.Turn != g.PlayerNumber && g.PlayerNumber != g.DoublePlayer && g.DoubleOffered {
return true
}
return g.Turn != 0 && g.Turn == g.PlayerNumber && g.Roll1 != 0 && len(g.Available) == 0
}
// MayDecline returns whether the player may send the 'resign' command to
// decline a double offer.
func (g *GameState) MayDecline() bool {
if g.Spectating || g.Winner != 0 {
return false
}
return g.Turn != 0 && g.Turn != g.PlayerNumber && g.PlayerNumber != g.DoublePlayer && g.DoubleOffered
}
// MayReset returns whether the player may send the 'reset' command.
func (g *GameState) MayReset() bool {
if g.Spectating || g.Winner != 0 {
return false
}
return g.Turn != 0 && g.Turn == g.PlayerNumber && len(g.Moves) > 0
}