teslo
Version:
Elo rating system
1 lines • 22.2 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","sources":["../src/main/contestants/player/index.ts","../src/main/contestants/team/index.ts","../src/lib/error/index.ts","../src/lib/match/error/index.ts","../src/lib/match/index.ts","../src/lib/match/options.ts","../src/main/matches/duel/index.ts","../src/main/matches/free-for-all/index.ts","../src/main/matches/team-duel/index.ts","../src/main/matches/team-free-for-all/index.ts"],"sourcesContent":["const DEFAULT_ELO_SCALE_FACTOR = 400\nconst Result = {\n WIN: 1,\n LOSS: 0\n}\n\nexport class Player {\n id: string\n elo: number\n\n constructor(id: string, elo: number) {\n this.id = id\n this.elo = elo\n }\n\n static create(id: string, elo: number): Player {\n return new Player(id, elo)\n }\n\n getExpectedResult(opponentElo: number): number {\n return 1 / (1 + Math.pow(10, (opponentElo - this.elo) / DEFAULT_ELO_SCALE_FACTOR))\n }\n\n calculate(opponentElo: number, won: boolean, kFactor: number): number {\n const result = won ? Result.WIN : Result.LOSS\n const expectedResult = this.getExpectedResult(opponentElo)\n return Math.round(this.elo + kFactor * (result - expectedResult))\n }\n}\n","import { Player } from '../player'\n\nexport class Team {\n id: string\n players: Map<string, Player>\n\n constructor(id: string, players?: Player[]) {\n this.id = id\n this.players = new Map()\n\n if (players) {\n this.addPlayers(...players)\n }\n }\n\n static create(id: string, players?: Player[]): Team {\n return new Team(id, players)\n }\n\n addPlayer(player: Player): this {\n this.players.set(player.id, player)\n return this\n }\n\n addPlayers(...players: Player[]): this {\n players.forEach(player => this.addPlayer(player))\n return this\n }\n\n getAverageElo(): number {\n if (this.players.size === 0) {\n return 0\n }\n\n let elo = 0\n\n for (const player of this.players.values()) {\n elo += player.elo\n }\n\n return elo / this.players.size\n }\n}\n","export class BaseError<T extends string> extends Error {\n name: T\n\n constructor(name: T, message: string) {\n super(message)\n this.name = name\n }\n}\n","import { BaseError } from '../../error'\n\nconst ERROR_NAME = 'MATCH_ERROR'\n\nexport const ErrorType = {\n MATCH_COMPLETE: 'Match completed',\n MATCH_INCOMPLETE: 'Match incomplete',\n MAX_PLAYERS: 'Cannot add more players',\n MIN_PLAYERS: 'Need more players',\n MAX_TEAMS: 'Cannot add more teams',\n MIN_TEAMS: 'Need more teams',\n SIZE_MISMATCH: 'Calculation does not match contestant size in match',\n PLAYER_NOT_FOUND: 'Player not found',\n TEAM_NOT_FOUND: 'Team not found',\n MISSING_OPPONENT_ELO: 'Could not find opponent elo'\n}\n\ntype ErrorTypeKey = keyof typeof ErrorType\n\nexport class MatchError<T extends ErrorTypeKey> extends BaseError<typeof ERROR_NAME> {\n constructor(message: (typeof ErrorType)[T]) {\n super(ERROR_NAME, message)\n }\n}\n","import { Player } from '../../main/contestants/player'\nimport { Team } from '../../main/contestants/team'\nimport {\n Options,\n DEFAULT_K_FACTOR,\n DEFAULT_MIN_CONTESTANTS,\n DEFAULT_MAX_CONTESTANTS\n} from './options'\nimport { Results } from './results'\nimport { ErrorType, MatchError } from './error'\n\ntype Contestant = Player | Team\n\nexport abstract class Match {\n private _contestants: Map<string, Contestant>\n private _completed: boolean\n protected readonly minContestants: number\n protected readonly maxContestants: number\n protected readonly kFactor: number\n\n constructor(options?: Options) {\n this._contestants = new Map()\n this._completed = false\n this.minContestants = options?.minContestants ?? DEFAULT_MIN_CONTESTANTS\n this.maxContestants = options?.maxContestants ?? DEFAULT_MAX_CONTESTANTS\n this.kFactor = options?.kFactor ?? DEFAULT_K_FACTOR\n }\n\n get contestants(): Map<string, Contestant> {\n return this._contestants\n }\n\n get size(): number {\n return this._contestants.size\n }\n\n get completed(): boolean {\n return this._completed\n }\n\n protected set completed(completed: boolean) {\n if (this._completed) {\n throw new MatchError(ErrorType.MATCH_COMPLETE)\n }\n\n this._completed = completed\n }\n\n protected contestantMapToEloMap(): Map<string, number> {\n const elos = new Map<string, number>()\n\n for (const [id, contestant] of this._contestants) {\n if (contestant instanceof Player) {\n elos.set(id, contestant.elo)\n } else if (contestant instanceof Team) {\n elos.set(id, contestant.getAverageElo())\n }\n }\n\n return elos\n }\n\n protected contestantMapToResults<T extends Results>(): T {\n const results = []\n\n for (const [id, contestant] of this._contestants) {\n if (contestant instanceof Player) {\n const player = { id, elo: contestant.elo }\n results.push(player)\n } else if (contestant instanceof Team) {\n const team = {\n id,\n players: [...contestant.players.values()].map(player => ({\n id: player.id,\n elo: player.elo\n }))\n }\n results.push(team)\n }\n }\n\n return results as T\n }\n\n protected findOpponentElos(contestantId: string, contestants: Map<string, number>): number[] {\n const elos: number[] = []\n\n for (const [id, elo] of contestants) {\n if (id !== contestantId) {\n elos.push(elo)\n }\n }\n\n return elos\n }\n\n protected addContestant(contestant: Contestant) {\n if (this._completed) {\n throw new MatchError(ErrorType.MATCH_COMPLETE)\n }\n\n this._contestants.set(contestant.id, contestant)\n }\n\n getResults(): Results {\n if (!this._completed) {\n throw new MatchError(ErrorType.MATCH_INCOMPLETE)\n }\n\n return this.contestantMapToResults()\n }\n\n abstract calculate(contestantIds: string | string[]): Results\n}\n","export interface Options {\n kFactor?: number\n minContestants?: number\n maxContestants?: number\n}\n\n// Elo calculation\nexport const DEFAULT_K_FACTOR = 32\n\n// Min/max contestants\nexport const DUEL_SIZE = 2\nexport const DEFAULT_MIN_CONTESTANTS = 2\nexport const DEFAULT_MAX_CONTESTANTS = 256\n","import { Player } from '../../contestants/player'\nimport { Match } from '../../../lib/match'\nimport { Options, DUEL_SIZE } from '../../../lib/match/options'\nimport { PlayerResult } from '../../../lib/match/results'\nimport { MatchError, ErrorType } from '../../../lib/match/error'\n\ntype DuelOptions = Partial<Pick<Options, 'kFactor'>>\n\nexport class Duel extends Match {\n constructor(players?: Player[], options?: DuelOptions) {\n super({\n minContestants: DUEL_SIZE,\n maxContestants: DUEL_SIZE,\n ...options\n })\n\n if (players) {\n this.addPlayers(...players)\n }\n }\n\n static create(players?: Player[], options?: DuelOptions): Duel {\n return new Duel(players, options)\n }\n\n addPlayer(player: Player): this {\n if (this.size === DUEL_SIZE) {\n throw new MatchError(ErrorType.MAX_PLAYERS)\n }\n\n this.addContestant(player)\n\n return this\n }\n\n addPlayers(...players: Player[]): this {\n players.forEach(player => this.addPlayer(player))\n return this\n }\n\n calculate(playerId: string): PlayerResult[] {\n if (this.completed) {\n throw new MatchError(ErrorType.MATCH_COMPLETE)\n }\n\n if (this.size !== DUEL_SIZE) {\n throw new MatchError(ErrorType.MIN_PLAYERS)\n }\n\n if (!this.contestants.has(playerId)) {\n throw new MatchError(ErrorType.PLAYER_NOT_FOUND)\n }\n\n const players = this.contestantMapToEloMap()\n\n for (const [id, contestant] of this.contestants) {\n const player = contestant as Player\n const elos = this.findOpponentElos(id, players)\n\n if (elos.length === 0) {\n throw new MatchError(ErrorType.MISSING_OPPONENT_ELO)\n }\n\n const elo = player.calculate(elos[0], playerId === id, this.kFactor)\n\n player.elo = elo\n }\n\n this.completed = true\n\n return this.contestantMapToResults()\n }\n}\n","import { Player } from '../../contestants/player'\nimport { Match } from '../../../lib/match'\nimport { Options } from '../../../lib/match/options'\nimport { PlayerResult } from '../../../lib/match/results'\nimport { MatchError, ErrorType } from '../../../lib/match/error'\n\ninterface FreeForAllOptions extends Partial<Pick<Options, 'kFactor'>> {\n minPlayers?: number\n maxPlayers?: number\n}\n\nexport class FreeForAll extends Match {\n constructor(players?: Player[], options?: FreeForAllOptions) {\n super({\n minContestants: options?.minPlayers,\n maxContestants: options?.maxPlayers,\n ...options\n })\n\n if (players) {\n this.addPlayers(...players)\n }\n }\n\n static create(players?: Player[], options?: FreeForAllOptions): FreeForAll {\n return new FreeForAll(players, options)\n }\n\n addPlayer(player: Player): this {\n if (this.size === this.maxContestants) {\n throw new MatchError(ErrorType.MAX_PLAYERS)\n }\n\n this.addContestant(player)\n\n return this\n }\n\n addPlayers(...players: Player[]): this {\n players.forEach(player => this.addPlayer(player))\n return this\n }\n\n calculate(playerIds: string[]): PlayerResult[] {\n if (this.completed) {\n throw new MatchError(ErrorType.MATCH_COMPLETE)\n }\n\n if (this.size < this.minContestants) {\n throw new MatchError(ErrorType.MIN_PLAYERS)\n }\n\n if (this.size !== playerIds.length) {\n throw new MatchError(ErrorType.SIZE_MISMATCH)\n }\n\n const players = this.contestantMapToEloMap()\n\n for (let i = 0; i < playerIds.length; i++) {\n const player = this.contestants.get(playerIds[i]) as Player\n\n if (!player) {\n throw new MatchError(ErrorType.PLAYER_NOT_FOUND)\n }\n\n let eloDiff = 0\n\n for (let j = 0; j < playerIds.length; j++) {\n if (i !== j) {\n const opponentElo = players.get(playerIds[j])\n\n if (opponentElo === undefined) {\n throw new MatchError(ErrorType.MISSING_OPPONENT_ELO)\n }\n\n eloDiff += player.calculate(opponentElo, j > i, this.kFactor)\n }\n }\n\n player.elo = Math.floor(eloDiff / (playerIds.length - 1))\n }\n\n this.completed = true\n\n return this.contestantMapToResults()\n }\n}\n","import { Team } from '../../contestants/team'\nimport { Match } from '../../../lib/match'\nimport { Options, DUEL_SIZE } from '../../../lib/match/options'\nimport { TeamResult } from '../../../lib/match/results'\nimport { MatchError, ErrorType } from '../../../lib/match/error'\n\ntype TeamDuelOptions = Partial<Pick<Options, 'kFactor'>>\n\nexport class TeamDuel extends Match {\n constructor(teams?: Team[], options?: TeamDuelOptions) {\n super({\n minContestants: DUEL_SIZE,\n maxContestants: DUEL_SIZE,\n ...options\n })\n\n if (teams) {\n this.addTeams(...teams)\n }\n }\n\n static create(teams?: Team[], options?: TeamDuelOptions): TeamDuel {\n return new TeamDuel(teams, options)\n }\n\n addTeam(team: Team): this {\n if (this.size === DUEL_SIZE) {\n throw new MatchError(ErrorType.MAX_TEAMS)\n }\n\n this.addContestant(team)\n\n return this\n }\n\n addTeams(...teams: Team[]): this {\n teams.forEach(team => this.addTeam(team))\n return this\n }\n\n calculate(teamId: string): TeamResult[] {\n if (this.completed) {\n throw new MatchError(ErrorType.MATCH_COMPLETE)\n }\n\n if (this.size !== DUEL_SIZE) {\n throw new MatchError(ErrorType.MIN_TEAMS)\n }\n\n if (!this.contestants.has(teamId)) {\n throw new MatchError(ErrorType.TEAM_NOT_FOUND)\n }\n\n const teams = this.contestantMapToEloMap()\n\n for (const [id, contestant] of this.contestants) {\n const team = contestant as Team\n const elos = this.findOpponentElos(id, teams)\n\n if (elos.length === 0) {\n throw new MatchError(ErrorType.MISSING_OPPONENT_ELO)\n }\n\n for (const [, player] of team.players) {\n const elo = player.calculate(elos[0], teamId === id, this.kFactor)\n\n player.elo = elo\n }\n }\n\n this.completed = true\n\n return this.contestantMapToResults()\n }\n}\n","import { Team } from '../../contestants/team'\nimport { Match } from '../../../lib/match'\nimport { Options } from '../../../lib/match/options'\nimport { TeamResult } from '../../../lib/match/results'\nimport { MatchError, ErrorType } from '../../../lib/match/error'\n\ninterface TeamFreeForAllOptions extends Partial<Pick<Options, 'kFactor'>> {\n minTeams?: number\n maxTeams?: number\n}\n\nexport class TeamFreeForAll extends Match {\n constructor(teams?: Team[], options?: TeamFreeForAllOptions) {\n super({\n minContestants: options?.minTeams,\n maxContestants: options?.maxTeams,\n ...options\n })\n\n if (teams) {\n this.addTeams(...teams)\n }\n }\n\n static create(teams?: Team[], options?: TeamFreeForAllOptions): TeamFreeForAll {\n return new TeamFreeForAll(teams, options)\n }\n\n addTeam(team: Team): this {\n if (this.size === this.maxContestants) {\n throw new MatchError(ErrorType.MAX_TEAMS)\n }\n\n this.addContestant(team)\n\n return this\n }\n\n addTeams(...teams: Team[]): this {\n teams.forEach(team => this.addTeam(team))\n return this\n }\n\n calculate(teamIds: string[]): TeamResult[] {\n if (this.completed) {\n throw new MatchError(ErrorType.MATCH_COMPLETE)\n }\n\n if (this.size < this.minContestants) {\n throw new MatchError(ErrorType.MIN_TEAMS)\n }\n\n if (this.size !== teamIds.length) {\n throw new MatchError(ErrorType.SIZE_MISMATCH)\n }\n\n const teams = this.contestantMapToEloMap()\n\n for (let i = 0; i < teamIds.length; i++) {\n const team = this.contestants.get(teamIds[i]) as Team\n\n if (!team) {\n throw new MatchError(ErrorType.TEAM_NOT_FOUND)\n }\n\n for (const [, player] of team.players) {\n let eloDiff = 0\n\n for (let j = 0; j < teamIds.length; j++) {\n if (i !== j) {\n const opponentElo = teams.get(teamIds[j])\n\n if (opponentElo === undefined) {\n throw new MatchError(ErrorType.MISSING_OPPONENT_ELO)\n }\n\n eloDiff += player.calculate(opponentElo, j > i, this.kFactor)\n }\n }\n\n player.elo = Math.floor(eloDiff / (teamIds.length - 1))\n }\n }\n\n this.completed = true\n\n return this.contestantMapToResults()\n }\n}\n"],"names":["Result","Player","constructor","id","elo","this","create","getExpectedResult","opponentElo","Math","pow","calculate","won","kFactor","result","expectedResult","round","Team","players","Map","addPlayers","addPlayer","player","set","forEach","getAverageElo","size","values","BaseError","Error","name","message","super","ErrorType","MATCH_COMPLETE","MATCH_INCOMPLETE","MAX_PLAYERS","MIN_PLAYERS","MAX_TEAMS","MIN_TEAMS","SIZE_MISMATCH","PLAYER_NOT_FOUND","TEAM_NOT_FOUND","MISSING_OPPONENT_ELO","MatchError","Match","options","_contestants","_completed","minContestants","_a","maxContestants","_b","_c","contestants","completed","contestantMapToEloMap","elos","contestant","contestantMapToResults","results","push","team","map","findOpponentElos","contestantId","addContestant","getResults","Duel","Object","assign","playerId","has","length","FreeForAll","minPlayers","maxPlayers","playerIds","i","get","eloDiff","j","undefined","floor","TeamDuel","teams","addTeams","addTeam","teamId","TeamFreeForAll","minTeams","maxTeams","teamIds"],"mappings":"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"}