Allow players to resign games

Resolves #16.
This commit is contained in:
Trevor Slocum 2024-06-27 18:55:40 -07:00
parent 6313f6fca8
commit 28e2b6ccfd
5 changed files with 62 additions and 30 deletions

View file

@ -81,7 +81,7 @@ formatted responses are more easily parsed by computers.
- Aliases: `d`
- `resign`
- Decline double offer and resign game.
- Resign game. Resigning when a double is offered will decline the offer.
- `roll`
- Roll dice.

View file

@ -25,7 +25,13 @@ The index is always eight digits in length with leading zeroes.
The first line of the game is the metadata. The timestamp specifies when the game started.
`i <timestamp> <player1> <player2> <total> <score1> <score2> <winner> <points> <acey>`
`i <timestamp> <player1> <player2> <total> <score1> <score2> <winner> <points> <variant>`
The variant is specified as follows:
- **0** Backgammon
- **1** Acey-deucey
- **2** Tabula
#### Events
@ -55,6 +61,12 @@ When no moves are possible, only the roll is specified.
`1 r 4-4`
##### Terminate
When a player resigns voluntarily or abandons an unfinished game, the player terminating the game early is indicated.
`1 t`
## Example .match file
```

View file

@ -132,8 +132,9 @@ func (g *GameState) MayOK() bool {
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 {
// 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
}

View file

@ -10,6 +10,9 @@ msgstr ""
msgid "%s accepted double."
msgstr ""
msgid "%s resigned."
msgstr ""
msgid "%s declined double offer."
msgstr ""
@ -34,7 +37,7 @@ msgstr ""
msgid "Created match: %s"
msgstr ""
msgid "Declined double offer"
msgid "Declined double offer."
msgstr ""
msgid "Double offered to opponent (%d points)."
@ -115,6 +118,9 @@ msgstr ""
msgid "Rematch offer sent."
msgstr ""
msgid "Resigned."
msgstr ""
msgid "Server error"
msgstr ""
@ -160,7 +166,7 @@ msgstr ""
msgid "You may not move until your opponent rejoins the match."
msgstr ""
msgid "You may not resign at this time."
msgid "You may not resign until it is your turn."
msgstr ""
msgid "You may not resign until your opponent rejoins the match."

View file

@ -559,41 +559,45 @@ COMMANDS:
continue
}
gameState := &bgammon.GameState{
Game: clientGame.Game,
PlayerNumber: cmd.client.playerNumber,
Available: clientGame.LegalMoves(false),
}
if !gameState.MayResign() {
cmd.client.sendNotice(gotext.GetD(cmd.client.language, "You may not resign at this time."))
continue
}
opponent := clientGame.opponent(cmd.client)
if opponent == nil {
cmd.client.sendNotice(gotext.GetD(cmd.client.language, "You may not resign until your opponent rejoins the match."))
continue
}
clientGame.NextPartialTurn(opponent.playerNumber)
gameState := &bgammon.GameState{
Game: clientGame.Game,
PlayerNumber: cmd.client.playerNumber,
Available: clientGame.LegalMoves(false),
}
var winner int8
addReplayHeader := func() {
clientGame.replay = append([][]byte{[]byte(fmt.Sprintf("i %d %s %s %d %d %d %d %d %d", clientGame.Started.Unix(), clientGame.Player1.Name, clientGame.Player2.Name, clientGame.Points, clientGame.Player1.Points, clientGame.Player2.Points, winner, clientGame.DoubleValue, clientGame.Variant))}, clientGame.replay...)
}
if gameState.MayDecline() {
winner = opponent.playerNumber
clientGame.NextPartialTurn(opponent.playerNumber)
cmd.client.sendNotice(gotext.GetD(cmd.client.language, "Declined double offer"))
clientGame.opponent(cmd.client).sendNotice(fmt.Sprintf(gotext.GetD(clientGame.opponent(cmd.client).language, "%s declined double offer."), cmd.client.name))
cmd.client.sendNotice(gotext.GetD(cmd.client.language, "Declined double offer."))
clientGame.opponent(cmd.client).sendNotice(fmt.Sprintf(gotext.GetD(clientGame.opponent(cmd.client).language, "%s declined double offer."), cmd.client.name))
clientGame.replay = append([][]byte{[]byte(fmt.Sprintf("i %d %s %s %d %d %d %d %d %d", clientGame.Started.Unix(), clientGame.Player1.Name, clientGame.Player2.Name, clientGame.Points, clientGame.Player1.Points, clientGame.Player2.Points, clientGame.Winner, clientGame.DoubleValue, clientGame.Variant))}, clientGame.replay...)
addReplayHeader()
clientGame.replay = append(clientGame.replay, []byte(fmt.Sprintf("%d d %d 0", clientGame.Turn, clientGame.DoubleValue*2)))
} else if gameState.Turn == 0 || gameState.Turn != cmd.client.playerNumber {
cmd.client.sendNotice(gotext.GetD(cmd.client.language, "You may not resign until it is your turn."))
continue
} else {
winner = cmd.client.playerNumber
clientGame.NextPartialTurn(cmd.client.playerNumber)
clientGame.replay = append(clientGame.replay, []byte(fmt.Sprintf("%d d %d 0", clientGame.Turn, clientGame.DoubleValue*2)))
cmd.client.sendNotice(gotext.GetD(cmd.client.language, "Resigned."))
clientGame.opponent(cmd.client).sendNotice(fmt.Sprintf(gotext.GetD(clientGame.opponent(cmd.client).language, "%s resigned."), cmd.client.name))
clientGame.replay = append(clientGame.replay, []byte(fmt.Sprintf("%d t", cmd.client.playerNumber)))
}
var reset bool
if cmd.client.playerNumber == 1 {
clientGame.Player2.Points = clientGame.Player2.Points + clientGame.DoubleValue
if clientGame.Player2.Points >= clientGame.Points {
clientGame.Winner = 2
clientGame.Ended = time.Now()
} else {
reset = true
}
} else {
if winner == 1 {
clientGame.Player1.Points = clientGame.Player1.Points + clientGame.DoubleValue
if clientGame.Player1.Points >= clientGame.Points {
clientGame.Winner = 1
@ -601,7 +605,16 @@ COMMANDS:
} else {
reset = true
}
} else {
clientGame.Player2.Points = clientGame.Player2.Points + clientGame.DoubleValue
if clientGame.Player2.Points >= clientGame.Points {
clientGame.Winner = 2
clientGame.Ended = time.Now()
} else {
reset = true
}
}
addReplayHeader()
var winEvent *bgammon.EventWin
if clientGame.Winner != 0 {