Spaces:
Runtime error
Runtime error
File size: 4,769 Bytes
cd8bd0a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | /**
* XP/Level Engine for OmniRoute Gamification
*
* Pure functions for XP calculations, level progression, and reward definitions.
* No side effects or DB calls β all stateful logic lives in the persistence layer.
*/
// βββ XP Curve ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
/**
* XP required for a specific level (delta, not cumulative).
* Polynomial curve: `xp_for_level(n) = floor(100 * n^1.5)`
*
* @param level - Target level (must be >= 1)
* @returns XP needed to gain this level (0 for level 1)
*
* @example
* xpForLevel(1) // 0
* xpForLevel(10) // 3162
* xpForLevel(50) // 35355
*/
export function xpForLevel(level: number): number {
if (level <= 1) return 0;
return Math.floor(100 * Math.pow(level, 1.5));
}
/**
* Cumulative XP required to reach a given level (sum of all prior level deltas).
*
* @param level - Target level (must be >= 1)
* @returns Total XP accumulated by that level
*
* @example
* cumulativeXpForLevel(1) // 0
* cumulativeXpForLevel(10) // sum of xpForLevel(2..10)
*/
export function cumulativeXpForLevel(level: number): number {
if (level <= 1) return 0;
let total = 0;
for (let i = 2; i <= level; i++) {
total += xpForLevel(i);
}
return total;
}
/**
* Calculate level from total XP using the inverse of the cumulative XP curve.
*
* The cumulative XP for level L approximates to `100 * L^2.5 / 2.5`.
* Solving for L gives `L β (totalXp * 2.5 / 100) ^ 0.4`.
*
* @param totalXp - Total accumulated XP
* @returns Current level (minimum 1)
*
* @example
* calculateLevel(0) // 1
* calculateLevel(5000) // ~8
* calculateLevel(100000) // ~100
*/
export function calculateLevel(totalXp: number): number {
if (totalXp <= 0) return 1;
return Math.max(1, Math.floor(Math.pow((totalXp * 2.5) / 100, 0.4)));
}
/**
* Get XP needed to reach the next level from the current total XP.
*
* @param totalXp - Current total XP
* @returns Remaining XP until next level-up
*
* @example
* xpToNextLevel(0) // XP needed to reach level 2
* xpToNextLevel(5000) // XP needed from 5000 to next level
*/
export function xpToNextLevel(totalXp: number): number {
const currentLevel = calculateLevel(totalXp);
const nextLevelXp = cumulativeXpForLevel(currentLevel + 1);
return nextLevelXp - totalXp;
}
// βββ Level Titles & Tiers ββββββββββββββββββββββββββββββββββββββββββββββββββββ
/**
* Get a human-readable title for a given level.
*
* @param level - Current level
* @returns Level title string
*
* @example
* getLevelTitle(5) // "Beginner"
* getLevelTitle(15) // "Explorer"
* getLevelTitle(30) // "Expert"
* getLevelTitle(60) // "Master"
* getLevelTitle(80) // "Legend"
*/
export function getLevelTitle(level: number): string {
if (level >= 76) return "Legend";
if (level >= 51) return "Master";
if (level >= 26) return "Expert";
if (level >= 11) return "Explorer";
return "Beginner";
}
/**
* Get the badge tier for a given level.
*
* @param level - Current level
* @returns Tier identifier suitable for badge display
*
* @example
* getLevelTier(5) // "bronze"
* getLevelTier(20) // "silver"
* getLevelTier(40) // "gold"
* getLevelTier(60) // "platinum"
* getLevelTier(90) // "diamond"
*/
export function getLevelTier(level: number): "bronze" | "silver" | "gold" | "platinum" | "diamond" {
if (level >= 76) return "diamond";
if (level >= 51) return "platinum";
if (level >= 26) return "gold";
if (level >= 11) return "silver";
return "bronze";
}
// βββ XP Rewards ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
/** Base XP rewards for each gamified action. */
export const XP_REWARDS = {
/** Per API request routed through OmniRoute */
request: 1,
/** Switching to a different provider */
provider_switch: 5,
/** Switching to a different model */
model_switch: 3,
/** Creating a new combo */
combo_create: 10,
/** Using a combo for a request */
combo_use: 2,
/** Per 1 000 tokens shared with another user */
token_share: 1,
/** Redeeming an invite code */
invite_redeem: 50,
/** Daily active usage (once per day) */
daily_login: 5,
/** Per consecutive streak day (multiplied by streak length) */
streak_bonus: 2,
/** Unlocking a badge */
badge_unlock: 10,
} as const;
/** Union type of all XP action keys. */
export type XpAction = keyof typeof XP_REWARDS;
|