diff --git a/pkg/game/game-handler.go b/pkg/game/game-handler.go index ed786b9..b938d05 100644 --- a/pkg/game/game-handler.go +++ b/pkg/game/game-handler.go @@ -261,11 +261,7 @@ func (h *Handler) Call(c *gin.Context) { c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()}) return } - state, err := game.GetState(id) - if err != nil { - c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()}) - return - } + state := game.GetState(id) c.IndentedJSON(http.StatusOK, state) } @@ -313,11 +309,7 @@ func (h *Handler) SelectSuit(c *gin.Context) { c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()}) return } - state, err := game.GetState(id) - if err != nil { - c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()}) - return - } + state := game.GetState(id) c.IndentedJSON(http.StatusOK, state) } @@ -364,11 +356,7 @@ func (h *Handler) Buy(c *gin.Context) { c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()}) return } - state, err := game.GetState(id) - if err != nil { - c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()}) - return - } + state := game.GetState(id) c.IndentedJSON(http.StatusOK, state) } @@ -417,10 +405,6 @@ func (h *Handler) Play(c *gin.Context) { c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()}) return } - state, err := game.GetState(id) - if err != nil { - c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()}) - return - } + state := game.GetState(id) c.IndentedJSON(http.StatusOK, state) } diff --git a/pkg/game/game-methods.go b/pkg/game/game-methods.go index 1a0aba3..eb5c4fd 100644 --- a/pkg/game/game-methods.go +++ b/pkg/game/game-methods.go @@ -15,14 +15,14 @@ func (g *Game) Me(playerID string) (Player, error) { return Player{}, fmt.Errorf("player not found in game") } -func (g *Game) GetState(playerID string) (State, error) { - // Get player - me, err := g.Me(playerID) - if err != nil { - return State{}, err +func (g *Game) GetState(playerID string) State { + // 1. Get Previous round if there is one + var prevRound Round + if len(g.Completed) > 0 { + prevRound = g.Completed[len(g.Completed)-1] } - // 1. Get max call + // 2. Get max call maxCall := Pass for _, p := range g.Players { if p.Call > maxCall { @@ -30,19 +30,30 @@ func (g *Game) GetState(playerID string) (State, error) { } } - // 2. Add dummy if applicable + // 3. Get player + me, err := g.Me(playerID) + + // If the player isn't in the game they are a spectator + if err != nil { + return State{ + ID: g.ID, + Revision: g.Revision, + IamSpectator: true, + Status: g.Status, + Round: g.CurrentRound, + PrevRound: prevRound, + MaxCall: maxCall, + Players: g.Players, + } + } + + // 4. Add dummy if applicable iamGoer := g.CurrentRound.GoerID == playerID if iamGoer && g.CurrentRound.Status == Called && g.Dummy != nil { me.Cards = append(me.Cards, g.Dummy...) } - // 3. Get Previous round if there is one - var prevRound Round - if len(g.Completed) > 0 { - prevRound = g.Completed[len(g.Completed)-1] - } - - // 4. Return player's game state + // 5. Return player's game state gameState := State{ ID: g.ID, Revision: g.Revision, @@ -60,7 +71,7 @@ func (g *Game) GetState(playerID string) (State, error) { Players: g.Players, } - return gameState, nil + return gameState } // 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 { } // If they are in the bunker (score < -30) they can only pass - state, err := g.GetState(playerID) - if err != nil { - return err - } + state := g.GetState(playerID) if state.Me.Score < -30 && call != Pass { return fmt.Errorf("player in bunker") } @@ -429,10 +437,7 @@ func (g *Game) SelectSuit(playerID string, suit Suit, cards []CardName) error { } // Verify the cards are valid (must be either in the player's hand or the dummy's hand and must be unique - state, errS := g.GetState(playerID) - if errS != nil { - return errS - } + state := g.GetState(playerID) if !containsAllUnique(state.Cards, cards) { return fmt.Errorf("invalid card selected") } @@ -482,10 +487,7 @@ func (g *Game) Buy(playerID string, cards []CardName) error { } // Verify the cards are valid (must be either in the player's hand or the dummy's hand and must be unique - state, errS := g.GetState(playerID) - if errS != nil { - return errS - } + state := g.GetState(playerID) if !containsAllUnique(state.Cards, cards) { return fmt.Errorf("invalid card selected") } @@ -543,10 +545,7 @@ func (g *Game) Play(id string, card CardName) error { } // Verify the card is valid - state, err := g.GetState(id) - if err != nil { - return err - } + state := g.GetState(id) if !contains(state.Cards, card) { return fmt.Errorf("invalid card selected") } @@ -592,7 +591,7 @@ func (g *Game) Play(id string, card CardName) error { g.CurrentRound.CurrentHand.CurrentPlayerID = np.ID } else { - err = g.completeHand() + err := g.completeHand() if err != nil { return err } diff --git a/pkg/game/game-service.go b/pkg/game/game-service.go index 1f74deb..5a5fd4a 100644 --- a/pkg/game/game-service.go +++ b/pkg/game/game-service.go @@ -34,10 +34,7 @@ func getCacheKey(gameId string, playerId string) string { func (s *Service) updateStateCache(game Game) error { // Update the state cache for all players in the game. for _, player := range game.Players { - state, err := game.GetState(player.ID) - if err != nil { - return err - } + state := game.GetState(player.ID) errC := s.Cache.Set(getCacheKey(game.ID, player.ID), state, time.Minute) if errC != nil { return errC @@ -92,10 +89,7 @@ func (s *Service) GetState(ctx context.Context, gameId string, playerID string) return State{}, has, errG } - state, err = game.GetState(playerID) - if err != nil { - return State{}, true, err - } + state = game.GetState(playerID) // Update the state cache for all players in the game. errC := s.updateStateCache(game) diff --git a/pkg/game/game-service_test.go b/pkg/game/game-service_test.go index 2c9876f..d0b1a8f 100644 --- a/pkg/game/game-service_test.go +++ b/pkg/game/game-service_test.go @@ -320,7 +320,7 @@ func TestGameService_GetState(t *testing.T) { expectingError: true, }, { - name: "player not in the game", + name: "player not in the game should be a spectator", gameID: TwoPlayerGame().ID, playerID: "3", mockGetResult: &[]Game{ @@ -332,8 +332,17 @@ func TestGameService_GetState(t *testing.T) { mockGetCacheExists: &[]bool{false}, mockGetCacheError: &[]error{nil}, mockSetCacheError: &[]error{nil}, - expectedExists: false, - expectingError: true, + expectedResult: State{ + ID: TwoPlayerGame().ID, + Revision: TwoPlayerGame().Revision, + IamSpectator: true, + Status: TwoPlayerGame().Status, + Round: TwoPlayerGame().CurrentRound, + MaxCall: TwoPlayerGame().Players[0].Call, + Players: TwoPlayerGame().Players, + }, + expectedExists: true, + expectingError: false, }, { name: "successful cache hit", diff --git a/pkg/game/game_test.go b/pkg/game/game_test.go index 7d2e596..c56616b 100644 --- a/pkg/game/game_test.go +++ b/pkg/game/game_test.go @@ -66,11 +66,10 @@ func TestGame_Me(t *testing.T) { func TestGame_GetState(t *testing.T) { tests := []struct { - name string - game Game - playerID string - expectedState State - expectingError bool + name string + game Game + playerID string + expectedState State }{ { name: "Player exists", @@ -89,10 +88,18 @@ func TestGame_GetState(t *testing.T) { }, }, { - name: "Player does not exist", - game: TwoPlayerGame(), - playerID: "3", - expectingError: true, + name: "Player does not exist so is a spectator", + game: TwoPlayerGame(), + playerID: "3", + expectedState: State{ + ID: TwoPlayerGame().ID, + Revision: TwoPlayerGame().Revision, + IamSpectator: true, + Status: TwoPlayerGame().Status, + MaxCall: 0, + Players: TwoPlayerGame().Players, + Round: TwoPlayerGame().CurrentRound, + }, }, { name: "Game in Called state", @@ -175,70 +182,63 @@ func TestGame_GetState(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - state, err := test.game.GetState(test.playerID) - if test.expectingError { - if err == nil { - t.Errorf("expected an error, got nil") - } - } else { - if err != nil { - t.Errorf("expected no error, got %v", err) - } - if state.ID != test.expectedState.ID { - t.Errorf("expected game ID to be %s, got %s", test.expectedState.ID, state.ID) - } - if state.Revision != test.expectedState.Revision { - t.Errorf("expected game revision to be %d, got %d", test.expectedState.Revision, state.Revision) - } - if state.Status != test.expectedState.Status { - t.Errorf("expected game status to be %s, got %s", test.expectedState.Status, state.Status) - } - if state.Me.ID != test.expectedState.Me.ID { - t.Errorf("expected player ID to be %s, got %s", test.expectedState.Me.ID, state.Me.ID) - } - if state.Me.Seat != test.expectedState.Me.Seat { - t.Errorf("expected player seat to be %d, got %d", test.expectedState.Me.Seat, state.Me.Seat) - } - if !compare(state.Me.Cards, test.expectedState.Me.Cards) { - t.Errorf("expected player cards to be %v, got %v", test.expectedState.Me.Cards, state.Me.Cards) - } - if state.Me.Call != test.expectedState.Me.Call { - t.Errorf("expected player call to be %d, got %d", test.expectedState.Me.Call, state.Me.Call) - } - if state.Me.Score != test.expectedState.Me.Score { - t.Errorf("expected player score to be %d, got %d", test.expectedState.Me.Score, state.Me.Score) - } - if state.Me.Rings != test.expectedState.Me.Rings { - t.Errorf("expected player rings to be %d, got %d", test.expectedState.Me.Rings, state.Me.Rings) - } - if state.Me.TeamID != test.expectedState.Me.TeamID { - t.Errorf("expected player team ID to be %s, got %s", test.expectedState.Me.TeamID, state.Me.TeamID) - } - if state.Me.Winner != test.expectedState.Me.Winner { - t.Errorf("expected player winner to be %t, got %t", test.expectedState.Me.Winner, state.Me.Winner) - } - if state.IamDealer != test.expectedState.IamDealer { - t.Errorf("expected IamDealer to be %t, got %t", test.expectedState.IamDealer, state.IamDealer) - } - if state.IamGoer != test.expectedState.IamGoer { - t.Errorf("expected IamGoer to be %t, got %t", test.expectedState.IamGoer, state.IamGoer) - } - if state.IamSpectator != test.expectedState.IamSpectator { - t.Errorf("expected IamSpectator to be %t, got %t", test.expectedState.IamSpectator, state.IamSpectator) - } - if state.IsMyGo != test.expectedState.IsMyGo { - t.Errorf("expected IsMyGo to be %t, got %t", test.expectedState.IsMyGo, state.IsMyGo) - } - if state.MaxCall != test.expectedState.MaxCall { - t.Errorf("expected MaxCall to be %d, got %d", test.expectedState.MaxCall, state.MaxCall) - } - if state.Round.Number != test.expectedState.Round.Number { - t.Errorf("expected Round Number to be %d, got %d", test.expectedState.Round.Number, state.Round.Number) - } - if state.PrevRound.Number != test.expectedState.PrevRound.Number { - t.Errorf("expected PrevRound Number to be %d, got %d", test.expectedState.PrevRound.Number, state.PrevRound.Number) - } + state := test.game.GetState(test.playerID) + + if state.ID != test.expectedState.ID { + t.Errorf("expected game ID to be %s, got %s", test.expectedState.ID, state.ID) + } + if state.Revision != test.expectedState.Revision { + t.Errorf("expected game revision to be %d, got %d", test.expectedState.Revision, state.Revision) + } + if state.Status != test.expectedState.Status { + t.Errorf("expected game status to be %s, got %s", test.expectedState.Status, state.Status) + } + if state.Me.ID != test.expectedState.Me.ID { + t.Errorf("expected player ID to be %s, got %s", test.expectedState.Me.ID, state.Me.ID) + } + if state.Me.Seat != test.expectedState.Me.Seat { + t.Errorf("expected player seat to be %d, got %d", test.expectedState.Me.Seat, state.Me.Seat) + } + if !compare(state.Me.Cards, test.expectedState.Me.Cards) { + t.Errorf("expected player cards to be %v, got %v", test.expectedState.Me.Cards, state.Me.Cards) + } + if state.Me.Call != test.expectedState.Me.Call { + t.Errorf("expected player call to be %d, got %d", test.expectedState.Me.Call, state.Me.Call) + } + if state.Me.Score != test.expectedState.Me.Score { + t.Errorf("expected player score to be %d, got %d", test.expectedState.Me.Score, state.Me.Score) + } + if state.Me.Rings != test.expectedState.Me.Rings { + t.Errorf("expected player rings to be %d, got %d", test.expectedState.Me.Rings, state.Me.Rings) + } + if state.Me.TeamID != test.expectedState.Me.TeamID { + t.Errorf("expected player team ID to be %s, got %s", test.expectedState.Me.TeamID, state.Me.TeamID) + } + if state.Me.Winner != test.expectedState.Me.Winner { + t.Errorf("expected player winner to be %t, got %t", test.expectedState.Me.Winner, state.Me.Winner) + } + if state.IamDealer != test.expectedState.IamDealer { + t.Errorf("expected IamDealer to be %t, got %t", test.expectedState.IamDealer, state.IamDealer) } + if state.IamGoer != test.expectedState.IamGoer { + t.Errorf("expected IamGoer to be %t, got %t", test.expectedState.IamGoer, state.IamGoer) + } + if state.IamSpectator != test.expectedState.IamSpectator { + t.Errorf("expected IamSpectator to be %t, got %t", test.expectedState.IamSpectator, state.IamSpectator) + } + if state.IsMyGo != test.expectedState.IsMyGo { + t.Errorf("expected IsMyGo to be %t, got %t", test.expectedState.IsMyGo, state.IsMyGo) + } + if state.MaxCall != test.expectedState.MaxCall { + t.Errorf("expected MaxCall to be %d, got %d", test.expectedState.MaxCall, state.MaxCall) + } + if state.Round.Number != test.expectedState.Round.Number { + t.Errorf("expected Round Number to be %d, got %d", test.expectedState.Round.Number, state.Round.Number) + } + if state.PrevRound.Number != test.expectedState.PrevRound.Number { + t.Errorf("expected PrevRound Number to be %d, got %d", test.expectedState.PrevRound.Number, state.PrevRound.Number) + } + }) } } @@ -1086,10 +1086,7 @@ func TestGame_SelectSuit(t *testing.T) { t.Errorf("expected revision to be %d, got %d", test.expectedRevision, test.game.Revision) } // Check that he has all of retained the cards he selected - state, err := test.game.GetState(test.playerID) - if err != nil { - t.Errorf("expected no error, got %v", err) - } + state := test.game.GetState(test.playerID) if !compare(state.Cards, test.cards) { t.Errorf("expected player to have all of the selected cards %v, got %v", test.cards, state.Cards) } @@ -1210,10 +1207,7 @@ func TestGame_Buy(t *testing.T) { t.Errorf("expected round status to be %s, got %s", test.expectedStatus, test.game.CurrentRound.Status) } // Check that he has all of retained the cards he selected - state, err := test.game.GetState(test.playerID) - if err != nil { - t.Errorf("expected no error, got %v", err) - } + state := test.game.GetState(test.playerID) if len(state.Cards) != 5 { t.Errorf("expected player to have 5 cards, got %d", len(state.Cards)) } @@ -1311,10 +1305,7 @@ func TestGame_Play(t *testing.T) { t.Errorf("expected next player to be %s, got %s", test.expectedNextPlayer, test.game.CurrentRound.CurrentHand.CurrentPlayerID) } // Check that he has all of retained the cards he selected - state, err := test.game.GetState(test.playerID) - if err != nil { - t.Errorf("expected no error, got %v", err) - } + state := test.game.GetState(test.playerID) if contains(state.Cards, test.card) { t.Errorf("expected player to not have played card %s, got %v", test.card, state.Cards) }