Validate moves

This commit is contained in:
Trevor Slocum 2023-09-04 22:52:28 -07:00
parent 2e11332392
commit 71a50ce22b
4 changed files with 52 additions and 11 deletions

View file

@ -3,7 +3,7 @@
[![Donate via LiberaPay](https://img.shields.io/liberapay/receives/rocket9labs.com.svg?logo=liberapay)](https://liberapay.com/rocket9labs.com)
[![Donate via Patreon](https://img.shields.io/badge/dynamic/json?color=%23e85b46&label=Patreon&query=data.attributes.patron_count&suffix=%20patrons&url=https%3A%2F%2Fwww.patreon.com%2Fapi%2Fcampaigns%2F5252223)](https://www.patreon.com/rocketnine)
**Note:** This is unfinished, alpha-quality software. Here be dragons.
**Note:** This is unfinished alpha-quality software. Here be dragons.
## Play
@ -28,3 +28,5 @@ See [bgammon-cli](https://code.rocket9labs.com/tslocum/bgammon-cli)
Please share issues and suggestions [here](https://code.rocket9labs.com/tslocum/bgammon/issues).
The bgammon protocol is specified in [PROTOCOL.md](https://code.rocket9labs.com/tslocum/bgammon/src/branch/main/PROTOCOL.md).
For information on how to play backgammon visit https://bkgm.com/rules.html

View file

@ -106,7 +106,7 @@ func (c *serverClient) sendEvent(e interface{}) {
case *bgammon.EventFailedRoll:
c.Write([]byte(fmt.Sprintf("failedroll %s", ev.Reason)))
case *bgammon.EventMoved:
c.Write([]byte(fmt.Sprintf("moved %s %s", ev.Player, bgammon.FormatMoves(ev.Moves, c.playerNumber))))
c.Write([]byte(fmt.Sprintf("moved %s %s", ev.Player, bgammon.FormatAndFlipMoves(ev.Moves, c.playerNumber))))
case *bgammon.EventFailedMove:
c.Write([]byte(fmt.Sprintf("failedmove %d/%d %s", ev.From, ev.To, ev.Reason)))
case *bgammon.EventFailedOk:

View file

@ -346,6 +346,16 @@ COMMANDS:
continue
}
// Set default game name.
if len(bytes.TrimSpace(gameName)) == 0 {
abbr := "'s"
lastLetter := cmd.client.name[len(cmd.client.name)-1]
if lastLetter == 's' || lastLetter == 'S' {
abbr = "'"
}
gameName = []byte(fmt.Sprintf("%s%s game", cmd.client.name, abbr))
}
g := newServerGame(<-s.newGameIDs)
g.name = gameName
g.password = gamePassword
@ -480,6 +490,14 @@ COMMANDS:
continue COMMANDS
}
if !bgammon.ValidSpace(from) || !bgammon.ValidSpace(to) {
cmd.client.sendEvent(&bgammon.EventFailedMove{
From: from,
To: to,
Reason: "Illegal move.",
})
}
originalFrom, originalTo := from, to
from, to = bgammon.FlipSpace(from, cmd.client.playerNumber), bgammon.FlipSpace(to, cmd.client.playerNumber)
log.Printf("translated player %d %d-%d as %d-%d", cmd.client.playerNumber, originalFrom, originalTo, from, to)
@ -496,9 +514,12 @@ COMMANDS:
continue
}
clientGame.eachClient(func(client *serverClient) {
client.sendEvent(&bgammon.EventMoved{
ev := &bgammon.EventMoved{
Moves: bgammon.FlipMoves(moves, client.playerNumber),
})
}
ev.Player = string(cmd.client.name)
client.sendEvent(ev)
clientGame.sendBoard(client)
})
case bgammon.CommandReset:
@ -525,9 +546,12 @@ COMMANDS:
cmd.client.sendNotice("Failed to undo move: invalid move.")
} else {
clientGame.eachClient(func(client *serverClient) {
client.sendEvent(&bgammon.EventMoved{
ev := &bgammon.EventMoved{
Moves: bgammon.FlipMoves(undoMoves, client.playerNumber),
})
}
ev.Player = string(cmd.client.name)
client.sendEvent(ev)
clientGame.sendBoard(client)
})
}
@ -544,7 +568,7 @@ COMMANDS:
playerNumber = 2
}
cmd.client.sendEvent(&bgammon.EventFailedOk{
Reason: fmt.Sprintf("The following legal moves are available: %s", bgammon.FormatMoves(legalMoves, playerNumber)),
Reason: fmt.Sprintf("The following legal moves are available: %s", bgammon.FormatAndFlipMoves(legalMoves, playerNumber)),
})
continue
}

23
game.go
View file

@ -592,7 +592,7 @@ func FlipSpace(space int, player int) int {
case SpaceBarOpponent:
return SpaceBarPlayer
default:
log.Panicf("unknown space %d", space)
return -1
}
}
return 24 - space + 1
@ -606,18 +606,33 @@ func FlipMoves(moves [][]int, player int) [][]int {
return m
}
func FormatMoves(moves [][]int, player int) []byte {
func FormatMoves(moves [][]int) []byte {
var out bytes.Buffer
for i := range moves {
if i != 0 {
out.WriteByte(' ')
}
// TODO
out.Write([]byte(fmt.Sprintf("{{%d/%d}}", FlipSpace(moves[i][0], player), FlipSpace(moves[i][1], player))))
out.Write([]byte(fmt.Sprintf("%d/%d", moves[i][0], moves[i][1])))
}
return out.Bytes()
}
func FormatAndFlipMoves(moves [][]int, player int) []byte {
return FormatMoves(FlipMoves(moves, player))
}
func ValidSpace(space int) bool {
if space < 1 || space > 24 {
return false
}
switch space {
case SpaceHomePlayer, SpaceHomeOpponent, SpaceBarPlayer, SpaceBarOpponent:
return true
default:
return false
}
}
const (
VerticalBar rune = '\u2502' // │
)