refactor: extract magic numbers to named constants

Frontend: choreography selection ratios, morph trigger chances,
creator cameo/ultimate chances, dodge/counter probabilities.
Server: HP, K-factors, Elo divisor, tier thresholds, fight loop interval.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-08 23:34:05 +00:00
co-authored by Claude Opus 4.6
parent 1731a64ae8
commit 7c8e404cf1
8 changed files with 129 additions and 45 deletions
+4 -3
View File
@@ -1,3 +1,4 @@
import { FIGHT_LOOP_INTERVAL_MS, ELO_MATCHING_RANDOMNESS } from '../lib/constants.js'
import { db, schema } from '../db/index.js'
import { runMockFight } from './mock.js'
import { eq } from 'drizzle-orm'
@@ -31,7 +32,7 @@ export interface FightLoopOptions {
export async function startFightLoop(options: FightLoopOptions = {}): Promise<void> {
const {
intervalMs = 8000,
intervalMs = FIGHT_LOOP_INTERVAL_MS,
maxFights = Infinity,
matchmakingStyle = 'mixed',
onFightStart,
@@ -161,8 +162,8 @@ function pickMatchup(
const bot = pick(bots)
const others = bots.filter(b => b.id !== bot.id)
others.sort((a, b) => {
const diffA = Math.abs(a.eloRating - bot.eloRating) + Math.random() * 150
const diffB = Math.abs(b.eloRating - bot.eloRating) + Math.random() * 150
const diffA = Math.abs(a.eloRating - bot.eloRating) + Math.random() * ELO_MATCHING_RANDOMNESS
const diffB = Math.abs(b.eloRating - bot.eloRating) + Math.random() * ELO_MATCHING_RANDOMNESS
return diffA - diffB
})
return [bot, others[0]]
+3 -2
View File
@@ -1,3 +1,4 @@
import { STARTING_HP } from '../lib/constants.js'
import { nanoid } from 'nanoid'
import { logger } from '../lib/logger.js'
import { createHash, randomBytes } from 'crypto'
@@ -433,8 +434,8 @@ export async function runMockFight(botAId: string, botBId: string): Promise<stri
createdAt: now,
})
let hpA = 200
let hpB = 200
let hpA = STARTING_HP
let hpB = STARTING_HP
let comboA = 0
let comboB = 0
let winnerId: string | null = null
+6 -8
View File
@@ -35,9 +35,7 @@ interface WebhookResponse {
error: boolean
}
const MAX_ROUNDS = 10
const KO_THRESHOLD = 0
const MAX_RESPONSE_BYTES = 10 * 1024 // 10KB
import { MAX_ROUNDS, KO_THRESHOLD, MAX_RESPONSE_BYTES, STARTING_HP, ELO_K_FACTOR, ELO_K_FACTOR_MOCK } from '../lib/constants.js'
// Track bots currently in a fight to prevent concurrent fights
const activeFighters = new Set<string>()
@@ -333,8 +331,8 @@ async function trackWebhookResult(botId: string, webhookUrl: string, succeeded:
}
async function executeFightRounds(fightId: string, botA: BotRecord, botB: BotRecord, arena: Arena, mode: 'free' | 'ranked' = 'free'): Promise<void> {
let hpA = 200
let hpB = 200
let hpA = STARTING_HP
let hpB = STARTING_HP
let comboA = 0
let comboB = 0
let winnerId: string | null = null
@@ -447,13 +445,13 @@ async function executeFightRounds(fightId: string, botA: BotRecord, botB: BotRec
const winnerName = winnerId === botA.id ? botA.name : winnerId === botB.id ? botB.name : 'nobody'
const isPerfect = winnerId && (
(winnerId === botA.id && hpA === 200) ||
(winnerId === botB.id && hpB === 200)
(winnerId === botA.id && hpA === STARTING_HP) ||
(winnerId === botB.id && hpB === STARTING_HP)
)
// Finalize fight + update bot stats atomically
const isMockFight = isMockBot(botA.webhookUrl) || isMockBot(botB.webhookUrl) || isClassicBot(botA.webhookUrl) || isClassicBot(botB.webhookUrl)
const kFactor = isMockFight ? 12 : 32 // Dampened Elo for mock/classic fights
const kFactor = isMockFight ? ELO_K_FACTOR_MOCK : ELO_K_FACTOR
let winnerEloChange = 0
let loserEloChange = 0
let newWinnerEloFinal = 0
+6 -8
View File
@@ -1,3 +1,4 @@
import { ELO_DIVISOR, TIER_THRESHOLDS } from '../lib/constants.js'
import type { Challenge } from './challenges.js'
import { pick } from '../lib/utils.js'
import { checkAnswer } from './answers.js'
@@ -523,7 +524,7 @@ export function calculateElo(
loserElo: number,
k: number = 32,
): { newWinnerElo: number; newLoserElo: number } {
const expectedWinner = 1 / (1 + Math.pow(10, (loserElo - winnerElo) / 400))
const expectedWinner = 1 / (1 + Math.pow(10, (loserElo - winnerElo) / ELO_DIVISOR))
const expectedLoser = 1 - expectedWinner
return {
@@ -534,13 +535,10 @@ export function calculateElo(
// Tier calculation
export function calculateTier(elo: number, wins: number): number {
if (elo >= 1900 && wins >= 40) return 6 // Legend
if (elo >= 1700 && wins >= 25) return 5 // Diamond
if (elo >= 1500 && wins >= 15) return 4 // Platinum
if (elo >= 1350 && wins >= 7) return 3 // Gold
if (elo >= 1200 && wins >= 3) return 2 // Silver
if (wins >= 1) return 1 // Bronze
return 0 // Baby
for (const t of TIER_THRESHOLDS) {
if (elo >= t.elo && wins >= t.wins) return t.tier
}
return 0 // Baby
}
export const TIER_NAMES = ['BABY', 'BRONZE', 'SILVER', 'GOLD', 'PLATINUM', 'DIAMOND', 'LEGEND'] as const