nextjs-rewrite (#5)
Reviewed-on: #5 Co-authored-by: David Gwilliam <dhgwilliam@gmail.com> Co-committed-by: David Gwilliam <dhgwilliam@gmail.com>
This commit was merged in pull request #5.
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* Elo Rating Utilities
|
||||
*
|
||||
* Provides functions for calculating Elo ratings and changes
|
||||
* Based on the standard Elo rating system
|
||||
*/
|
||||
|
||||
/**
|
||||
* Calculate the expected score for a player based on rating difference
|
||||
* @param ratingA Player A's rating
|
||||
* @param ratingB Player B's rating
|
||||
* @returns Expected score (0-1) for Player A
|
||||
*/
|
||||
export function calculateExpectedScore(ratingA: number, ratingB: number): number {
|
||||
const ratingDiff = ratingA - ratingB;
|
||||
return 1 / (1 + Math.pow(10, -ratingDiff / 400));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate Elo rating change for a single game
|
||||
* @param rating Player's current rating
|
||||
* @param opponentRating Opponent's rating
|
||||
* @param actualScore Actual score (1 = win, 0.5 = draw, 0 = loss)
|
||||
* @param kFactor K-factor (how much ratings change per game)
|
||||
* @returns Elo rating change (positive or negative)
|
||||
*/
|
||||
export function calculateEloChange(
|
||||
rating: number,
|
||||
opponentRating: number,
|
||||
actualScore: number,
|
||||
kFactor: number = 32
|
||||
): number {
|
||||
const expectedScore = calculateExpectedScore(rating, opponentRating);
|
||||
return kFactor * (actualScore - expectedScore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate team Elo rating as average of individual ratings
|
||||
* @param rating1 Rating of player 1
|
||||
* @param rating2 Rating of player 2
|
||||
* @returns Team rating
|
||||
*/
|
||||
export function calculateTeamElo(rating1: number, rating2: number): number {
|
||||
return (rating1 + rating2) / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update player statistics after a match
|
||||
* @param currentRating Current player rating
|
||||
* @param currentGamesPlayed Current games played count
|
||||
* @param currentWins Current wins count
|
||||
* @param eloChange Elo rating change
|
||||
* @param won Whether the player won
|
||||
* @returns Updated statistics
|
||||
*/
|
||||
export function updatePlayerStats(
|
||||
currentRating: number,
|
||||
currentGamesPlayed: number,
|
||||
currentWins: number,
|
||||
eloChange: number,
|
||||
won: boolean
|
||||
): {
|
||||
newRating: number;
|
||||
newGamesPlayed: number;
|
||||
newWins: number;
|
||||
newLosses: number;
|
||||
winRate: number;
|
||||
} {
|
||||
const newRating = currentRating + Math.round(eloChange);
|
||||
const newGamesPlayed = currentGamesPlayed + 1;
|
||||
const newWins = currentWins + (won ? 1 : 0);
|
||||
const newLosses = newGamesPlayed - newWins;
|
||||
const winRate = newGamesPlayed > 0 ? newWins / newGamesPlayed : 0;
|
||||
|
||||
return {
|
||||
newRating,
|
||||
newGamesPlayed,
|
||||
newWins,
|
||||
newLosses,
|
||||
winRate,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate new rating after a match
|
||||
* @param currentRating Current rating
|
||||
* @param opponentRating Opponent's rating
|
||||
* @param won Whether the player won
|
||||
* @param kFactor K-factor (default 32)
|
||||
* @returns New rating
|
||||
*/
|
||||
export function calculateNewRating(
|
||||
currentRating: number,
|
||||
opponentRating: number,
|
||||
won: boolean,
|
||||
kFactor: number = 32
|
||||
): number {
|
||||
const actualScore = won ? 1 : 0;
|
||||
const eloChange = calculateEloChange(currentRating, opponentRating, actualScore, kFactor);
|
||||
return Math.round(currentRating + eloChange);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate rating is within reasonable bounds
|
||||
* @param rating Rating to validate
|
||||
* @returns Whether the rating is valid
|
||||
*/
|
||||
export function isValidRating(rating: number): boolean {
|
||||
return rating >= 100 && rating <= 3000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rating tier name based on rating
|
||||
* @param rating Player rating
|
||||
* @returns Tier name
|
||||
*/
|
||||
export function getRatingTier(rating: number): string {
|
||||
if (rating < 1100) return 'Beginner';
|
||||
if (rating < 1300) return 'Novice';
|
||||
if (rating < 1500) return 'Intermediate';
|
||||
if (rating < 1700) return 'Advanced';
|
||||
if (rating < 1900) return 'Expert';
|
||||
if (rating < 2100) return 'Master';
|
||||
return 'Grandmaster';
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate expected score for a team match
|
||||
* @param team1Rating Average rating of team 1
|
||||
* @param team2Rating Average rating of team 2
|
||||
* @returns Expected score for team 1
|
||||
*/
|
||||
export function calculateExpectedTeamScore(team1Rating: number, team2Rating: number): number {
|
||||
return calculateExpectedScore(team1Rating, team2Rating);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate Elo change for team match
|
||||
* @param team1Rating Average rating of team 1
|
||||
* @param team2Rating Average rating of team 2
|
||||
* @param team1Score Actual score for team 1 (1 = win, 0.5 = draw, 0 = loss)
|
||||
* @param kFactor K-factor (default 32)
|
||||
* @returns Elo change for team 1
|
||||
*/
|
||||
export function calculateTeamEloChange(
|
||||
team1Rating: number,
|
||||
team2Rating: number,
|
||||
team1Score: number,
|
||||
kFactor: number = 32
|
||||
): number {
|
||||
return calculateEloChange(team1Rating, team2Rating, team1Score, kFactor);
|
||||
}
|
||||
Reference in New Issue
Block a user