Add doubling cube
This commit is contained in:
parent
f96a4fdb1a
commit
8da2829b6a
6 changed files with 169 additions and 14 deletions
|
@ -45,6 +45,13 @@ formatted responses are more easily parsed by computers.
|
|||
- Join match by match ID or by player.
|
||||
- Aliases: `j`
|
||||
|
||||
- `double`
|
||||
- Offer double to opponent.
|
||||
- Aliases: `d`
|
||||
|
||||
- `resign`
|
||||
- Decline double offer and resign game.
|
||||
|
||||
- `roll`
|
||||
- Roll dice.
|
||||
- Aliases: `r`
|
||||
|
@ -58,7 +65,7 @@ formatted responses are more easily parsed by computers.
|
|||
- Aliases: `r`
|
||||
|
||||
- `ok`
|
||||
- Confirm checker movement and pass turn to next player.
|
||||
- Accept double offer or confirm checker movement and pass turn to next player.
|
||||
- Aliases: `k`
|
||||
|
||||
- `rematch`
|
||||
|
|
|
@ -617,6 +617,88 @@ COMMANDS:
|
|||
}
|
||||
|
||||
clientGame.removeClient(cmd.client)
|
||||
case bgammon.CommandDouble, "d":
|
||||
if clientGame == nil {
|
||||
cmd.client.sendNotice("You are not currently in a match.")
|
||||
continue
|
||||
}
|
||||
|
||||
if clientGame.Turn != cmd.client.playerNumber {
|
||||
cmd.client.sendNotice("It is not your turn.")
|
||||
continue
|
||||
}
|
||||
|
||||
gameState := &bgammon.GameState{
|
||||
Game: clientGame.Game,
|
||||
PlayerNumber: cmd.client.playerNumber,
|
||||
Available: clientGame.LegalMoves(),
|
||||
}
|
||||
if !gameState.MayDouble() {
|
||||
cmd.client.sendNotice("You may not double at this time.")
|
||||
continue
|
||||
}
|
||||
|
||||
clientGame.DoubleOffered = true
|
||||
|
||||
cmd.client.sendNotice(fmt.Sprintf("Double offered to opponent (%d points).", clientGame.Points*2))
|
||||
clientGame.opponent(cmd.client).sendNotice(fmt.Sprintf("%s offers a double (%d points).", cmd.client.name, clientGame.Points*2))
|
||||
|
||||
clientGame.eachClient(func(client *serverClient) {
|
||||
if client.json {
|
||||
clientGame.sendBoard(client)
|
||||
}
|
||||
})
|
||||
case bgammon.CommandResign:
|
||||
if clientGame == nil {
|
||||
cmd.client.sendNotice("You are not currently in a match.")
|
||||
continue
|
||||
}
|
||||
|
||||
gameState := &bgammon.GameState{
|
||||
Game: clientGame.Game,
|
||||
PlayerNumber: cmd.client.playerNumber,
|
||||
Available: clientGame.LegalMoves(),
|
||||
}
|
||||
if !gameState.MayResign() {
|
||||
cmd.client.sendNotice("You may not resign at this time.")
|
||||
continue
|
||||
}
|
||||
|
||||
cmd.client.sendNotice("Declined double offer")
|
||||
clientGame.opponent(cmd.client).sendNotice(fmt.Sprintf("%s declined double offer.", cmd.client.name))
|
||||
|
||||
log.Println("RESIGN VALUE: ", clientGame.DoubleValue) // TODO
|
||||
if cmd.client.playerNumber == 1 {
|
||||
clientGame.Player2.Points += clientGame.DoubleValue
|
||||
if clientGame.Player2.Points >= clientGame.Points {
|
||||
clientGame.Winner = 2
|
||||
} else {
|
||||
clientGame.Reset()
|
||||
}
|
||||
} else {
|
||||
clientGame.Player1.Points += clientGame.DoubleValue
|
||||
if clientGame.Player1.Points >= clientGame.Points {
|
||||
clientGame.Winner = 1
|
||||
} else {
|
||||
clientGame.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
var winEvent *bgammon.EventWin
|
||||
if clientGame.Winner != 0 {
|
||||
winEvent = &bgammon.EventWin{}
|
||||
if clientGame.Winner == 1 {
|
||||
winEvent.Player = clientGame.Player1.Name
|
||||
} else {
|
||||
winEvent.Player = clientGame.Player2.Name
|
||||
}
|
||||
}
|
||||
clientGame.eachClient(func(client *serverClient) {
|
||||
clientGame.sendBoard(client)
|
||||
if winEvent != nil {
|
||||
client.sendEvent(winEvent)
|
||||
}
|
||||
})
|
||||
case bgammon.CommandRoll, "r":
|
||||
if clientGame == nil {
|
||||
cmd.client.sendEvent(&bgammon.EventFailedRoll{
|
||||
|
@ -783,6 +865,21 @@ COMMANDS:
|
|||
continue
|
||||
}
|
||||
|
||||
if clientGame.DoubleOffered && clientGame.Turn != cmd.client.playerNumber {
|
||||
opponent := clientGame.opponent(cmd.client)
|
||||
if opponent == nil {
|
||||
cmd.client.sendNotice("You may not accept the double until your opponent rejoins the match.")
|
||||
continue
|
||||
}
|
||||
|
||||
clientGame.DoubleOffered = false
|
||||
clientGame.DoubleValue *= 2
|
||||
clientGame.DoublePlayer = opponent.playerNumber
|
||||
cmd.client.sendNotice("Accepted double.")
|
||||
opponent.sendNotice(fmt.Sprintf("%s accepted double.", cmd.client.name))
|
||||
continue
|
||||
}
|
||||
|
||||
legalMoves := clientGame.LegalMoves()
|
||||
if len(legalMoves) != 0 {
|
||||
available := bgammon.FlipMoves(legalMoves, cmd.client.playerNumber)
|
||||
|
|
|
@ -14,6 +14,8 @@ const (
|
|||
CommandCreate = "create" // Create match.
|
||||
CommandJoin = "join" // Join match.
|
||||
CommandLeave = "leave" // Leave match.
|
||||
CommandDouble = "double" // Offer double to opponent.
|
||||
CommandResign = "resign" // Decline double offer and resign game.
|
||||
CommandRoll = "roll" // Roll dice.
|
||||
CommandMove = "move" // Move checkers.
|
||||
CommandReset = "reset" // Reset checker movement.
|
||||
|
|
47
game.go
47
game.go
|
@ -22,30 +22,39 @@ type Game struct {
|
|||
Roll1 int
|
||||
Roll2 int
|
||||
Moves [][]int // Pending moves.
|
||||
Points int
|
||||
|
||||
Points int // Points required to win the match.
|
||||
DoubleValue int // Doubling cube value.
|
||||
DoublePlayer int // Player that currently posesses the doubling cube.
|
||||
DoubleOffered bool // Whether the current player is offering a double.
|
||||
|
||||
boardStates [][]int // One board state for each move to allow undoing a move.
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
return &Game{
|
||||
Board: NewBoard(),
|
||||
Player1: NewPlayer(1),
|
||||
Player2: NewPlayer(2),
|
||||
Board: NewBoard(),
|
||||
Player1: NewPlayer(1),
|
||||
Player2: NewPlayer(2),
|
||||
Points: 1,
|
||||
DoubleValue: 1,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Game) Copy() *Game {
|
||||
newGame := &Game{
|
||||
Board: make([]int, len(g.Board)),
|
||||
Player1: g.Player1,
|
||||
Player2: g.Player2,
|
||||
Turn: g.Turn,
|
||||
Winner: g.Winner,
|
||||
Roll1: g.Roll1,
|
||||
Roll2: g.Roll2,
|
||||
Moves: make([][]int, len(g.Moves)),
|
||||
boardStates: make([][]int, len(g.boardStates)),
|
||||
Board: make([]int, len(g.Board)),
|
||||
Player1: g.Player1,
|
||||
Player2: g.Player2,
|
||||
Turn: g.Turn,
|
||||
Winner: g.Winner,
|
||||
Roll1: g.Roll1,
|
||||
Roll2: g.Roll2,
|
||||
Moves: make([][]int, len(g.Moves)),
|
||||
Points: g.Points,
|
||||
DoubleValue: g.DoubleValue,
|
||||
DoublePlayer: g.DoublePlayer,
|
||||
boardStates: make([][]int, len(g.boardStates)),
|
||||
}
|
||||
copy(newGame.Board, g.Board)
|
||||
copy(newGame.Moves, g.Moves)
|
||||
|
@ -68,6 +77,18 @@ func (g *Game) NextTurn() {
|
|||
g.boardStates = g.boardStates[:0]
|
||||
}
|
||||
|
||||
func (g *Game) Reset() {
|
||||
g.Board = NewBoard()
|
||||
g.Turn = 0
|
||||
g.Roll1 = 0
|
||||
g.Roll2 = 0
|
||||
g.Moves = nil
|
||||
g.DoubleValue = 1
|
||||
g.DoublePlayer = 0
|
||||
g.DoubleOffered = false
|
||||
g.boardStates = nil
|
||||
}
|
||||
|
||||
func (g *Game) turnPlayer() Player {
|
||||
switch g.Turn {
|
||||
case 2:
|
||||
|
|
27
gamestate.go
27
gamestate.go
|
@ -56,8 +56,19 @@ func (g *GameState) SpaceAt(x int, y int) int {
|
|||
return space
|
||||
}
|
||||
|
||||
// MayDouble returns whether the player may send the 'double' command.
|
||||
func (g *GameState) MayDouble() bool {
|
||||
if g.Winner != 0 {
|
||||
return false
|
||||
}
|
||||
return 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.Winner != 0 || g.DoubleOffered {
|
||||
return false
|
||||
}
|
||||
switch g.Turn {
|
||||
case 0:
|
||||
if g.PlayerNumber == 1 {
|
||||
|
@ -78,10 +89,26 @@ func (g *GameState) MayRoll() bool {
|
|||
|
||||
// MayOK returns whether the player may send the 'ok' command.
|
||||
func (g *GameState) MayOK() bool {
|
||||
if g.Winner != 0 {
|
||||
return false
|
||||
} else if g.Turn != 0 && g.Turn != g.PlayerNumber && g.DoubleOffered {
|
||||
return true
|
||||
}
|
||||
return g.Turn != 0 && g.Turn == g.PlayerNumber && g.Roll1 != 0 && len(g.Available) == 0
|
||||
}
|
||||
|
||||
// MayResign returns whether the player may send the 'resign' command.
|
||||
func (g *GameState) MayResign() bool {
|
||||
if g.Winner != 0 {
|
||||
return false
|
||||
}
|
||||
return g.Turn != 0 && g.Turn != g.PlayerNumber && g.DoubleOffered
|
||||
}
|
||||
|
||||
// MayReset returns whether the player may send the 'reset' command.
|
||||
func (g *GameState) MayReset() bool {
|
||||
if g.Winner != 0 {
|
||||
return false
|
||||
}
|
||||
return g.Turn != 0 && g.Turn == g.PlayerNumber && len(g.Moves) > 0
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package bgammon
|
|||
type Player struct {
|
||||
Number int // 1 black, 2 white
|
||||
Name string
|
||||
Points int
|
||||
}
|
||||
|
||||
func NewPlayer(number int) Player {
|
||||
|
|
Loading…
Reference in a new issue