Add rematch command

This commit is contained in:
Trevor Slocum 2023-09-10 15:27:33 -07:00
parent d735899304
commit 2a1ae33131
4 changed files with 76 additions and 16 deletions

View file

@ -16,58 +16,62 @@ All commands and events are separated by newlines.
- Log in to bgammon. A random username is assigned when none is provided.
- This must be the first command sent when a client connects to bgammon.
- Usernames must contain at least one non-numeric character.
- *Aliases:* `l`
- Aliases: `l`
- `loginjson [username] [password]`
- Log in to bgammon and enable JSON formatted responses.
- All client applications should use the `loginjson` command to log in, as JSON
formatted responses are more easily parsed by computers.
- *Aliases:* `lj`
- Aliases: `lj`
- `json <on/off>`
- Turn JSON formatted messages on or off. JSON messages are not sent by default.
- `help [command]`
- Request help for all commands, or optionally a specific command.
- *Aliases:* `h`
- Aliases: `h`
- `list`
- List all games.
- *Aliases:* `ls`
- Aliases: `ls`
- `create <public/private> [password]`
- List all games.
- *Aliases:* `c`
- Aliases: `c`
- `join <id>/<username> [password]`
- Join game by game ID or by player.
- *Aliases:* `j`
- Aliases: `j`
- `roll`
- Roll dice.
- *Aliases:* `r`
- Aliases: `r`
- `move <from-to> [from-to]...`
- Move checkers.
- *Aliases:* `m`, `mv`
- Aliases: `m`, `mv`
- `reset`
- Reset pending checker movement.
- *Aliases:* `r`
- Aliases: `r`
- `ok`
- Confirm checker movement and pass turn to next player.
- *Aliases:* `k`
- Aliases: `k`
- `rematch`
- Request (or accept) a rematch after a match has been finished.
- Aliases: `rm`
- `say <message>`
- Send a chat message.
- This command can only be used after creating or joining a game.
- *Aliases:* `s`
- Aliases: `s`
- `board`
- Print current game state in human-readable form.
- This command is not normally used, as the game state is provided in JSON format.
- *Aliases:* `b`
- Aliases: `b`
- `pong <message>`
- Sent in response to server `ping` event to prevent the connection from timing out.

View file

@ -19,6 +19,7 @@ type serverGame struct {
client2 *serverClient
r *rand.Rand
allowedPlayers [][]byte // Only matching player names are allowed to join.
rematch int
*bgammon.Game
}

View file

@ -224,9 +224,6 @@ func (s *server) sendHello(c *serverClient) {
c.Write([]byte("hello Welcome to bgammon.org! Please log in by sending the 'login' command. You may specify a username, otherwise you will be assigned a random username. If you specify a username, you may also specify a password. Have fun!"))
}
func (s *server) sendWelcome(c *serverClient) {
}
func (s *server) gameByClient(c *serverClient) *serverGame {
s.gamesLock.RLock()
defer s.gamesLock.RUnlock()
@ -703,6 +700,60 @@ COMMANDS:
clientGame.eachClient(func(client *serverClient) {
clientGame.sendBoard(client)
})
case bgammon.CommandRematch, "rm":
if clientGame == nil {
cmd.client.sendNotice("You are not currently in a game.")
continue
} else if clientGame.Winner == 0 {
cmd.client.sendNotice("The game you are in is still in progress.")
continue
} else if clientGame.rematch == cmd.client.playerNumber {
cmd.client.sendNotice("You have already requested a rematch.")
continue
} else if clientGame.client1 == nil || clientGame.client2 == nil {
cmd.client.sendNotice("Your opponent left the game.")
continue
} else if clientGame.rematch != 0 && clientGame.rematch != cmd.client.playerNumber {
s.gamesLock.Lock()
newGame := newServerGame(<-s.newGameIDs)
newGame.name = clientGame.name
newGame.password = clientGame.password
newGame.client1 = clientGame.client1
newGame.client2 = clientGame.client2
newGame.Player1 = clientGame.Player1
newGame.Player2 = clientGame.Player2
s.games = append(s.games, newGame)
clientGame.client1 = nil
clientGame.client2 = nil
s.gamesLock.Unlock()
ev1 := &bgammon.EventJoined{
GameID: newGame.id,
PlayerNumber: 1,
}
ev1.Player = newGame.Player1.Name
ev2 := &bgammon.EventJoined{
GameID: newGame.id,
PlayerNumber: 2,
}
ev2.Player = newGame.Player2.Name
newGame.eachClient(func(client *serverClient) {
client.sendEvent(ev1)
client.sendEvent(ev2)
newGame.sendBoard(client)
})
} else {
clientGame.rematch = cmd.client.playerNumber
clientGame.opponent(cmd.client).sendNotice("Your opponent would like to play again. Type /rematch to accept.")
cmd.client.sendNotice("Rematch offer sent.")
continue
}
case bgammon.CommandBoard, "b":
if clientGame == nil {
cmd.client.sendNotice("You are not currently in a game.")
@ -725,7 +776,10 @@ COMMANDS:
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.Turn = 1
clientGame.Roll1 = 1
clientGame.Roll2 = 2
clientGame.Board = []int{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0}
clientGame.eachClient(func(client *serverClient) {
clientGame.sendBoard(client)

View file

@ -18,6 +18,7 @@ const (
CommandMove = "move" // Move checkers.
CommandReset = "reset" // Reset checker movement.
CommandOk = "ok" // Confirm checker movement and pass turn to next player.
CommandRematch = "rematch" // Confirm checker movement and pass turn to next player.
CommandBoard = "board" // Print current board state in human-readable form.
CommandPong = "pong" // Response to server ping.
CommandDisconnect = "disconnect" // Disconnect from server.