Skip to content

Commit 02176f2

Browse files
authored
Merge pull request #28 from daithihearn/spectator
feat: spectator support on game state
2 parents 74058c9 + c9543f3 commit 02176f2

5 files changed

Lines changed: 124 additions & 147 deletions

File tree

pkg/game/game-handler.go

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -261,11 +261,7 @@ func (h *Handler) Call(c *gin.Context) {
261261
c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()})
262262
return
263263
}
264-
state, err := game.GetState(id)
265-
if err != nil {
266-
c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()})
267-
return
268-
}
264+
state := game.GetState(id)
269265
c.IndentedJSON(http.StatusOK, state)
270266
}
271267

@@ -313,11 +309,7 @@ func (h *Handler) SelectSuit(c *gin.Context) {
313309
c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()})
314310
return
315311
}
316-
state, err := game.GetState(id)
317-
if err != nil {
318-
c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()})
319-
return
320-
}
312+
state := game.GetState(id)
321313
c.IndentedJSON(http.StatusOK, state)
322314
}
323315

@@ -364,11 +356,7 @@ func (h *Handler) Buy(c *gin.Context) {
364356
c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()})
365357
return
366358
}
367-
state, err := game.GetState(id)
368-
if err != nil {
369-
c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()})
370-
return
371-
}
359+
state := game.GetState(id)
372360
c.IndentedJSON(http.StatusOK, state)
373361
}
374362

@@ -417,10 +405,6 @@ func (h *Handler) Play(c *gin.Context) {
417405
c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()})
418406
return
419407
}
420-
state, err := game.GetState(id)
421-
if err != nil {
422-
c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()})
423-
return
424-
}
408+
state := game.GetState(id)
425409
c.IndentedJSON(http.StatusOK, state)
426410
}

pkg/game/game-methods.go

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,45 @@ func (g *Game) Me(playerID string) (Player, error) {
1515
return Player{}, fmt.Errorf("player not found in game")
1616
}
1717

18-
func (g *Game) GetState(playerID string) (State, error) {
19-
// Get player
20-
me, err := g.Me(playerID)
21-
if err != nil {
22-
return State{}, err
18+
func (g *Game) GetState(playerID string) State {
19+
// 1. Get Previous round if there is one
20+
var prevRound Round
21+
if len(g.Completed) > 0 {
22+
prevRound = g.Completed[len(g.Completed)-1]
2323
}
2424

25-
// 1. Get max call
25+
// 2. Get max call
2626
maxCall := Pass
2727
for _, p := range g.Players {
2828
if p.Call > maxCall {
2929
maxCall = p.Call
3030
}
3131
}
3232

33-
// 2. Add dummy if applicable
33+
// 3. Get player
34+
me, err := g.Me(playerID)
35+
36+
// If the player isn't in the game they are a spectator
37+
if err != nil {
38+
return State{
39+
ID: g.ID,
40+
Revision: g.Revision,
41+
IamSpectator: true,
42+
Status: g.Status,
43+
Round: g.CurrentRound,
44+
PrevRound: prevRound,
45+
MaxCall: maxCall,
46+
Players: g.Players,
47+
}
48+
}
49+
50+
// 4. Add dummy if applicable
3451
iamGoer := g.CurrentRound.GoerID == playerID
3552
if iamGoer && g.CurrentRound.Status == Called && g.Dummy != nil {
3653
me.Cards = append(me.Cards, g.Dummy...)
3754
}
3855

39-
// 3. Get Previous round if there is one
40-
var prevRound Round
41-
if len(g.Completed) > 0 {
42-
prevRound = g.Completed[len(g.Completed)-1]
43-
}
44-
45-
// 4. Return player's game state
56+
// 5. Return player's game state
4657
gameState := State{
4758
ID: g.ID,
4859
Revision: g.Revision,
@@ -60,7 +71,7 @@ func (g *Game) GetState(playerID string) (State, error) {
6071
Players: g.Players,
6172
}
6273

63-
return gameState, nil
74+
return gameState
6475
}
6576

6677
// MinKeep returns the minimum number of cards that must be kept by a player
@@ -280,10 +291,7 @@ func (g *Game) Call(playerID string, call Call) error {
280291
}
281292

282293
// If they are in the bunker (score < -30) they can only pass
283-
state, err := g.GetState(playerID)
284-
if err != nil {
285-
return err
286-
}
294+
state := g.GetState(playerID)
287295
if state.Me.Score < -30 && call != Pass {
288296
return fmt.Errorf("player in bunker")
289297
}
@@ -429,10 +437,7 @@ func (g *Game) SelectSuit(playerID string, suit Suit, cards []CardName) error {
429437
}
430438

431439
// Verify the cards are valid (must be either in the player's hand or the dummy's hand and must be unique
432-
state, errS := g.GetState(playerID)
433-
if errS != nil {
434-
return errS
435-
}
440+
state := g.GetState(playerID)
436441
if !containsAllUnique(state.Cards, cards) {
437442
return fmt.Errorf("invalid card selected")
438443
}
@@ -482,10 +487,7 @@ func (g *Game) Buy(playerID string, cards []CardName) error {
482487
}
483488

484489
// Verify the cards are valid (must be either in the player's hand or the dummy's hand and must be unique
485-
state, errS := g.GetState(playerID)
486-
if errS != nil {
487-
return errS
488-
}
490+
state := g.GetState(playerID)
489491
if !containsAllUnique(state.Cards, cards) {
490492
return fmt.Errorf("invalid card selected")
491493
}
@@ -543,10 +545,7 @@ func (g *Game) Play(id string, card CardName) error {
543545
}
544546

545547
// Verify the card is valid
546-
state, err := g.GetState(id)
547-
if err != nil {
548-
return err
549-
}
548+
state := g.GetState(id)
550549
if !contains(state.Cards, card) {
551550
return fmt.Errorf("invalid card selected")
552551
}
@@ -592,7 +591,7 @@ func (g *Game) Play(id string, card CardName) error {
592591
g.CurrentRound.CurrentHand.CurrentPlayerID = np.ID
593592
} else {
594593

595-
err = g.completeHand()
594+
err := g.completeHand()
596595
if err != nil {
597596
return err
598597
}

pkg/game/game-service.go

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,7 @@ func getCacheKey(gameId string, playerId string) string {
3434
func (s *Service) updateStateCache(game Game) error {
3535
// Update the state cache for all players in the game.
3636
for _, player := range game.Players {
37-
state, err := game.GetState(player.ID)
38-
if err != nil {
39-
return err
40-
}
37+
state := game.GetState(player.ID)
4138
errC := s.Cache.Set(getCacheKey(game.ID, player.ID), state, time.Minute)
4239
if errC != nil {
4340
return errC
@@ -92,10 +89,7 @@ func (s *Service) GetState(ctx context.Context, gameId string, playerID string)
9289
return State{}, has, errG
9390
}
9491

95-
state, err = game.GetState(playerID)
96-
if err != nil {
97-
return State{}, true, err
98-
}
92+
state = game.GetState(playerID)
9993

10094
// Update the state cache for all players in the game.
10195
errC := s.updateStateCache(game)

pkg/game/game-service_test.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ func TestGameService_GetState(t *testing.T) {
320320
expectingError: true,
321321
},
322322
{
323-
name: "player not in the game",
323+
name: "player not in the game should be a spectator",
324324
gameID: TwoPlayerGame().ID,
325325
playerID: "3",
326326
mockGetResult: &[]Game{
@@ -332,8 +332,17 @@ func TestGameService_GetState(t *testing.T) {
332332
mockGetCacheExists: &[]bool{false},
333333
mockGetCacheError: &[]error{nil},
334334
mockSetCacheError: &[]error{nil},
335-
expectedExists: false,
336-
expectingError: true,
335+
expectedResult: State{
336+
ID: TwoPlayerGame().ID,
337+
Revision: TwoPlayerGame().Revision,
338+
IamSpectator: true,
339+
Status: TwoPlayerGame().Status,
340+
Round: TwoPlayerGame().CurrentRound,
341+
MaxCall: TwoPlayerGame().Players[0].Call,
342+
Players: TwoPlayerGame().Players,
343+
},
344+
expectedExists: true,
345+
expectingError: false,
337346
},
338347
{
339348
name: "successful cache hit",

0 commit comments

Comments
 (0)