This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Create players | |
const initialRating = 1000 | |
const numPlayers = 10 | |
const playerTiers = 5 | |
const playerRatingRange = 6000 - initialRating | |
const playerSegmentSize = Math.floor(numPlayers / playerTiers) | |
const playerIncrementAmount = Math.floor(playerRatingRange / playerTiers) | |
const playerGeneration = { | |
total: numPlayers, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const symmetricRatingSystem = createRatingSystem() | |
const playerKFactor = 32 | |
const questionKFactor = 4 | |
const asymmetricKFactorFn: KFactorFunctionWithPlayers = (rating, playerIndex) => { | |
let kFactor = playerIndex === 0 | |
? playerKFactor | |
: questionKFactor | |
if (rating > 6000) { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export type KFactorOption = | |
| KFactorFunctionWithPlayers | |
| KFactorFunction | |
| number | |
export function createRatingSystem(kFactor: KFactorOption = 32, exponentDenominator: number = 400, exponentBase: number = 10): RatingSystem { | |
let resolvedKFactor: KFactorFunctionWithPlayers | |
if (typeof kFactor === 'number') { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { | |
playerAProbability, | |
playerBProbability, | |
nextPlayerARating, | |
playerARatingDiff, | |
nextPlayerBRating, | |
playerBRatingDiff | |
} = rating.getNextRatings(playerARating, playerBRating, actualScore) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function createNextRatingsFn( | |
getExpectedPlayerProbabilities: ExpectedProbabilitiesFn, | |
getNextARating: NextRatingFn, | |
getNextBRating: NextRatingFn | |
): NextRatingsFn { | |
const nextRatingsFn = (playerARating: number, playerBRating: number, playerAScore: number) => { | |
const [expectedPlayerAProbability, expectedPlayerBProbability] = getExpectedPlayerProbabilities(playerARating, playerBRating) | |
const aProbability = playerAScore | |
const bProbability = 1 - playerAScore |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import createRatingSystem from '@sc2/rating' | |
// Defaults to K 32, Scale 400, Base 10 | |
const ratingSystem = createRatingSystem() | |
// get two players | |
const playerA = { | |
id: 'playerA', | |
rating: 1000, | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function createRatingSystem(kFactor = 32, exponentDenominator = 400, exponentBase = 10): RatingSystem { | |
// Standard Elo implementation with symmetric kfactor functions for each player | |
// This would be a true zero-sum game where A(-x) = B(+x) | |
const getPlayerProbabilities = createPlayerProbabilitiesFn(exponentBase, exponentDenominator) | |
const getNextRating = createNextRatingFn(kFactor) | |
return { | |
getPlayerProbabilities, | |
getNextRating | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type NextRatingFn = (rating: number, actualPoints: number, expectedPoints: number) => [nextRating: number, ratingChange: number] | |
type KFactorFunction = (rating: number) => number | |
function createNextRatingFn(kFactor: number | KFactorFunction): NextRatingFn { | |
const kFactorFn: KFactorFunction = typeof kFactor === 'number' | |
? () => kFactor | |
: kFactor | |
return (rating: number, actualPoints: number, expectedPoints: number): [number, number] => { | |
const change = Math.round(kFactorFn(rating) * (actualPoints - expectedPoints)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type ExpectedProbabilitiesFn = (playerARating: number, playerBRating: number) => | |
[ | |
playerAProbability: number, | |
playerBProbability: number, | |
ratingADifference: number, | |
ratingBDifference: number | |
] | |
function createPlayerProbabilitiesFn(exponentBase: number, exponentDenominator: number): ExpectedProbabilitiesFn { | |
const expectedPlayerProbabilityFn = createBaseExpectedPlayerProbabilityFn(exponentBase, exponentDenominator) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function createBaseExpectedPlayerProbabilityFn(exponentBase: number, exponentDenominator: number) { | |
return (ratingDifference: number): number => { | |
const exponent = ratingDifference / exponentDenominator | |
return 1 / (1 + Math.pow(exponentBase, exponent)) | |
} | |
} |