Feat: update stats
This commit is contained in:
		| @@ -71,6 +71,7 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) { | |||||||
| 		abortWithError(w, err.Error()) | 		abortWithError(w, err.Error()) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | 	updateStatsOnCardReveal(r.Context(), fi.State, color) | ||||||
| 	fi.Room.UpdateCounter() | 	fi.Room.UpdateCounter() | ||||||
| 	action := models.Action{ | 	action := models.Action{ | ||||||
| 		Actor:      fi.State.Username, | 		Actor:      fi.State.Username, | ||||||
| @@ -121,6 +122,7 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) { | |||||||
| 		fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) | 		fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) | ||||||
| 		clearMarks = true | 		clearMarks = true | ||||||
| 		StopTurnTimer(fi.Room.ID) | 		StopTurnTimer(fi.Room.ID) | ||||||
|  | 		updateStatsOnGameOver(r.Context(), fi.Room) | ||||||
| 	case string(models.WordColorWhite), string(oppositeColor): | 	case string(models.WordColorWhite), string(oppositeColor): | ||||||
| 		log.Debug("opened white or opposite color word", "word", word, "opposite-color", oppositeColor) | 		log.Debug("opened white or opposite color word", "word", word, "opposite-color", oppositeColor) | ||||||
| 		// end turn | 		// end turn | ||||||
| @@ -144,6 +146,7 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) { | |||||||
| 				Action:     models.ActionTypeGameOver, | 				Action:     models.ActionTypeGameOver, | ||||||
| 			} | 			} | ||||||
| 			fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) | 			fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) | ||||||
|  | 			updateStatsOnGameOver(r.Context(), fi.Room) | ||||||
| 		} | 		} | ||||||
| 		if fi.Room.RedCounter == 0 { | 		if fi.Room.RedCounter == 0 { | ||||||
| 			// red won | 			// red won | ||||||
| @@ -158,6 +161,7 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) { | |||||||
| 				Action:     models.ActionTypeGameOver, | 				Action:     models.ActionTypeGameOver, | ||||||
| 			} | 			} | ||||||
| 			fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) | 			fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) | ||||||
|  | 			updateStatsOnGameOver(r.Context(), fi.Room) | ||||||
| 		} | 		} | ||||||
| 	default: // same color as the team | 	default: // same color as the team | ||||||
| 		// check if game over | 		// check if game over | ||||||
| @@ -173,6 +177,7 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) { | |||||||
| 				Action:     models.ActionTypeGameOver, | 				Action:     models.ActionTypeGameOver, | ||||||
| 			} | 			} | ||||||
| 			fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) | 			fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) | ||||||
|  | 			updateStatsOnGameOver(r.Context(), fi.Room) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if clearMarks { | 	if clearMarks { | ||||||
|   | |||||||
							
								
								
									
										80
									
								
								handlers/stats.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								handlers/stats.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -47,7 +47,13 @@ func (p *RepoProvider) PlayerAdd(ctx context.Context, player *models.Player) err | |||||||
| 	db := getDB(ctx, p.DB) | 	db := getDB(ctx, p.DB) | ||||||
| 	_, err := db.ExecContext(ctx, "INSERT INTO players (room_id, username, team, role, is_bot, password) VALUES (?, ?, ?, ?, ?, ?)", | 	_, 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) | 		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 { | func (p *RepoProvider) PlayerUpdate(ctx context.Context, player *models.Player) error { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Grail Finder
					Grail Finder