include shell counts in game dto

This commit is contained in:
Branden J Brown 2024-01-29 21:20:17 -06:00
parent f858384ca0
commit e8a181a4f7
3 changed files with 62 additions and 67 deletions

View File

@ -226,6 +226,11 @@ func (g *Match) Concede(id player.ID) error {
// DTO returns the current match state as viewed by the given player. // DTO returns the current match state as viewed by the given player.
func (g *Match) DTO(id player.ID) serve.Game { func (g *Match) DTO(id player.ID) serve.Game {
var live, blank int
if g.turn == 1 {
live = len(g.shells) / 2
blank = len(g.shells) - live
}
return serve.Game{ return serve.Game{
Players: [2]serve.Player{ Players: [2]serve.Player{
g.players[0].DTO(), g.players[0].DTO(),
@ -235,22 +240,11 @@ func (g *Match) DTO(id player.ID) serve.Game {
Damage: g.damage, Damage: g.damage,
Shell: g.Peek(id), Shell: g.Peek(id),
Previous: g.prev, Previous: g.prev,
Live: live,
Blank: blank,
} }
} }
// ShellCounts returns the number of live and blank shells.
func (g *Match) ShellCounts() serve.ShellCounts {
var counts serve.ShellCounts
for _, s := range g.shells {
if s {
counts.Live++
} else {
counts.Blank++
}
}
return counts
}
var ( var (
ErrWrongTurn = errors.New("not your turn") ErrWrongTurn = errors.New("not your turn")
ErrGameEnded = errors.New("the shotgun is empty") ErrGameEnded = errors.New("the shotgun is empty")

View File

@ -79,7 +79,6 @@ func TestGameStartGroup(t *testing.T) {
t.Parallel() t.Parallel()
g := New(player.ID{1}, player.ID{2}) g := New(player.ID{1}, player.ID{2})
for i := uint(1); i < 10000; i++ { for i := uint(1); i < 10000; i++ {
counts := g.ShellCounts()
checks := []struct { checks := []struct {
failed bool failed bool
msg string msg string
@ -89,7 +88,6 @@ func TestGameStartGroup(t *testing.T) {
{g.players[1].items[0] == ItemNone, "challenger has no first item: %v", []any{g.players[1].items}}, {g.players[1].items[0] == ItemNone, "challenger has no first item: %v", []any{g.players[1].items}},
{len(g.shells) < 2 || len(g.shells) > 8, "bad shells count %d, want 2-8", []any{len(g.shells)}}, {len(g.shells) < 2 || len(g.shells) > 8, "bad shells count %d, want 2-8", []any{len(g.shells)}},
{&g.shells[0] != &g.shellArray[0], "shells[0] is %p, want %p", []any{&g.shells[0], &g.shellArray[0]}}, {&g.shells[0] != &g.shellArray[0], "shells[0] is %p, want %p", []any{&g.shells[0], &g.shellArray[0]}},
{counts.Live != counts.Blank && counts.Live+1 != counts.Blank, "imbalanced live/blank %d/%d", []any{counts.Live, counts.Blank}},
{g.round != 1, "round is %d, want 1", []any{g.round}}, {g.round != 1, "round is %d, want 1", []any{g.round}},
{g.turn != 1, "turn is %d, want 1", []any{g.turn}}, {g.turn != 1, "turn is %d, want 1", []any{g.turn}},
{g.damage != 1, "damage is %d, want 1", []any{g.damage}}, {g.damage != 1, "damage is %d, want 1", []any{g.damage}},
@ -436,53 +434,56 @@ func TestConcede(t *testing.T) {
} }
} }
func TestGameShellCounts(t *testing.T) { func TestGameDTO(t *testing.T) {
cases := []struct {
name string
shells []bool
want serve.ShellCounts
}{
{
name: "empty",
shells: nil,
want: serve.ShellCounts{Live: 0, Blank: 0},
},
{
name: "one-live",
shells: []bool{true},
want: serve.ShellCounts{Live: 1, Blank: 0},
},
{
name: "one-blank",
shells: []bool{false},
want: serve.ShellCounts{Live: 0, Blank: 1},
},
{
name: "two",
shells: []bool{true, false},
want: serve.ShellCounts{Live: 1, Blank: 1},
},
{
name: "three",
shells: []bool{true, false, true},
want: serve.ShellCounts{Live: 2, Blank: 1},
},
{
name: "four",
shells: []bool{true, false, true, false},
want: serve.ShellCounts{Live: 2, Blank: 2},
},
}
for _, c := range cases {
c := c
t.Run(c.name, func(t *testing.T) {
t.Parallel() t.Parallel()
g := New(player.ID{1}, player.ID{2}) dealer, chall := player.ID{1}, player.ID{2}
g.shells = c.shells g := New(dealer, chall)
if got := g.ShellCounts(); got != c.want { {
t.Errorf("wrong shell counts: got %#v, wanted %#v", got, c.want) want := serve.Game{
Players: [2]serve.Player{
g.players[0].DTO(),
g.players[1].DTO(),
},
Round: g.round,
Damage: g.damage,
Shell: nil,
Previous: nil,
Live: len(g.shells) / 2,
Blank: (len(g.shells) + 1) / 2,
}
if got := g.DTO(dealer); want != got {
t.Errorf("dealer sees the wrong thing:\nwant %+v\ngot %+v", want, got)
}
if got := g.DTO(chall); want != got {
t.Errorf("challenger sees the wrong thing:\nwant %+v\ngot %+v", want, got)
}
if got := g.DTO(player.ID{}); want != got {
t.Errorf("observer sees the wrong thing:\nwant %+v\ngot %+v", want, got)
}
}
g.Shoot(chall, false)
{
want := serve.Game{
Players: [2]serve.Player{
g.players[0].DTO(),
g.players[1].DTO(),
},
Round: g.round,
Damage: g.damage,
Shell: nil,
Previous: &g.shellArray[0],
Live: 0,
Blank: 0,
}
if got := g.DTO(dealer); want != got {
t.Errorf("dealer sees the wrong thing:\nwant %+v\ngot %+v", want, got)
}
if got := g.DTO(chall); want != got {
t.Errorf("challenger sees the wrong thing:\nwant %+v\ngot %+v", want, got)
}
if got := g.DTO(player.ID{}); want != got {
t.Errorf("observer sees the wrong thing:\nwant %+v\ngot %+v", want, got)
} }
})
} }
} }

View File

@ -17,6 +17,12 @@ type Game struct {
Shell *bool `json:"shell,omitempty"` Shell *bool `json:"shell,omitempty"`
// Previous gives whether the previously discharged shell was live. // Previous gives whether the previously discharged shell was live.
Previous *bool `json:"previous"` Previous *bool `json:"previous"`
// Live is the number of live shells this round, if it is the first turn
// of the round.
Live int `json:"live,omitempty"`
// Blank is the number of blank shells this round, if it is the first turn
// of the round.
Blank int `json:"blank,omitempty"`
} }
// Player is the JSON DTO for a player. // Player is the JSON DTO for a player.
@ -37,9 +43,3 @@ type GameStart struct {
ID GameID `json:"id"` ID GameID `json:"id"`
Dealer bool `json:"dealer"` Dealer bool `json:"dealer"`
} }
// ShellCounts is the JSON DTO for shell counts emitted at the start of a shell group.
type ShellCounts struct {
Live int `json:"live"`
Blank int `json:"blank"`
}