diff --git a/handlers/elements.go b/handlers/elements.go index c58261d..12f1c75 100644 --- a/handlers/elements.go +++ b/handlers/elements.go @@ -71,6 +71,7 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) { abortWithError(w, err.Error()) return } + updateStatsOnCardReveal(r.Context(), fi.State, color) fi.Room.UpdateCounter() action := models.Action{ Actor: fi.State.Username, @@ -121,6 +122,7 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) { fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) clearMarks = true StopTurnTimer(fi.Room.ID) + updateStatsOnGameOver(r.Context(), fi.Room) case string(models.WordColorWhite), string(oppositeColor): log.Debug("opened white or opposite color word", "word", word, "opposite-color", oppositeColor) // end turn @@ -144,6 +146,7 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) { Action: models.ActionTypeGameOver, } fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) + updateStatsOnGameOver(r.Context(), fi.Room) } if fi.Room.RedCounter == 0 { // red won @@ -158,6 +161,7 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) { Action: models.ActionTypeGameOver, } fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) + updateStatsOnGameOver(r.Context(), fi.Room) } default: // same color as the team // check if game over @@ -173,6 +177,7 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) { Action: models.ActionTypeGameOver, } fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) + updateStatsOnGameOver(r.Context(), fi.Room) } } if clearMarks { diff --git a/handlers/stats.go b/handlers/stats.go new file mode 100644 index 0000000..1946658 --- /dev/null +++ b/handlers/stats.go @@ -0,0 +1,80 @@ +package handlers + +import ( + "context" + "gralias/models" +) + +// updateStatsOnCardReveal updates player stats when a card is revealed. +func updateStatsOnCardReveal(ctx context.Context, player *models.Player, cardColor models.WordColor) { + if player.IsBot { + return + } + stats, err := repo.GetPlayerStats(ctx, player.Username) + if err != nil { + log.Error("failed to get player stats for card reveal update", "username", player.Username, "error", err) + return + } + playerTeamColorStr := string(player.Team) + switch cardColor { + case models.WordColorBlack: + stats.OpenedBlackWords++ + case models.WordColorWhite: + stats.OpenedWhiteWords++ + default: + if string(cardColor) != playerTeamColorStr { + stats.OpenedOppositeWords++ + } + } + if err := repo.UpdatePlayerStats(ctx, stats); err != nil { + log.Error("failed to update player stats on card reveal", "username", player.Username, "error", err) + } +} + +// updateStatsOnGameOver updates stats for all players in a room when a game ends. +func updateStatsOnGameOver(ctx context.Context, room *models.Room) { + // Get all players in the room + players, err := repo.PlayerListByRoom(ctx, room.ID) + if err != nil { + log.Error("failed to list players by room for stats update", "room_id", room.ID, "error", err) + return + } + for _, player := range players { + if player.IsBot { + continue + } + stats, err := repo.GetPlayerStats(ctx, player.Username) + if err != nil { + log.Error("failed to get player stats for game over update", "username", player.Username, "error", err) + continue + } + stats.GamesPlayed++ + if player.Team == room.TeamWon { + stats.GamesWon++ + } else { + stats.GamesLost++ + } + if player.Role == models.UserRoleMime { + stats.PlayedAsMime++ + if stats.PlayedAsMime > 0 { + gamesWonAsMime := stats.MimeWinrate * float64(stats.PlayedAsMime-1) + if player.Team == room.TeamWon { + gamesWonAsMime++ + } + stats.MimeWinrate = gamesWonAsMime / float64(stats.PlayedAsMime) + } + } else if player.Role == models.UserRoleGuesser { + stats.PlayedAsGuesser++ + if stats.PlayedAsGuesser > 0 { + gamesWonAsGuesser := stats.GuesserWinrate * float64(stats.PlayedAsGuesser-1) + if player.Team == room.TeamWon { + gamesWonAsGuesser++ + } + stats.GuesserWinrate = gamesWonAsGuesser / float64(stats.PlayedAsGuesser) + } + } + if err := repo.UpdatePlayerStats(ctx, stats); err != nil { + log.Error("failed to update player stats on game over", "username", player.Username, "error", err) + } + } +} diff --git a/repos/players.go b/repos/players.go index 0cc2b0f..330fe59 100644 --- a/repos/players.go +++ b/repos/players.go @@ -47,7 +47,13 @@ func (p *RepoProvider) PlayerAdd(ctx context.Context, player *models.Player) err db := getDB(ctx, p.DB) _, err := db.ExecContext(ctx, "INSERT INTO players (room_id, username, team, role, is_bot, password) VALUES (?, ?, ?, ?, ?, ?)", player.RoomID, player.Username, player.Team, player.Role, player.IsBot, player.Password) - return err + if err != nil { + return err + } + if !player.IsBot { + return p.CreatePlayerStats(ctx, player.Username) + } + return nil } func (p *RepoProvider) PlayerUpdate(ctx context.Context, player *models.Player) error {