weed-sim / src /shared /valuation.ts
Yufok1
Checkpoint Devvit v0.0.26
616ae7b
Raw
History Blame Contribute Delete
2.96 kB
export type RarityTier =
| 'common'
| 'uncommon'
| 'notable'
| 'rare'
| 'elite'
| 'exotic'
| 'legendary'
| 'mythic'
| 'primordial';
// Ascending order (weakest -> apex). Index positions double as a numeric rank.
export const RARITY_TIERS: RarityTier[] = [
'common',
'uncommon',
'notable',
'rare',
'elite',
'exotic',
'legendary',
'mythic',
'primordial',
];
export type RarityInput = {
thc: number;
cbd: number;
yield: number;
growTime: number;
stability: number;
generation: number;
vibrance: number;
bloom: number;
canAttempt: boolean;
};
function clamp01(value: number): number {
return Math.max(0, Math.min(1, value));
}
// Market valuation: unbounded, drives pricing (commonCloneEquivalent) and the
// leaderboard "Rarity" metric. Left intentionally as-is so the economy is untouched.
export function rarityScore(input: RarityInput): number {
return Math.round((
input.thc * 1.35 +
input.cbd * 0.55 +
input.yield * 0.18 +
Math.max(0, 90 - input.growTime) * 0.18 +
input.stability * 18 +
input.generation * 4 +
input.vibrance * 0.16 +
input.bloom * 0.14 +
(input.canAttempt ? 5 : 0)
) * 10) / 10;
}
// Bounded 0-100 collectibility index that drives the visual rarity TIER only.
// Every term is normalized to 0..1 and generation saturates (gen/(gen+6)) so
// breeding deeper cannot inflate a plant into the top tier forever -- the top
// tiers stay rare permanently, unlike the raw score.
export function rarityIndex(input: RarityInput): number {
const potency = clamp01(input.thc / 40);
const cannabinoid = clamp01(input.cbd / 18);
const yieldN = clamp01((input.yield - 25) / 135);
const speed = clamp01((90 - input.growTime) / 50);
const stability = clamp01(input.stability);
const bloomN = clamp01(input.bloom / 100);
const vibranceN = clamp01(input.vibrance / 100);
const genN = input.generation / (input.generation + 6);
const blended =
potency * 0.2 +
bloomN * 0.18 +
genN * 0.15 +
vibranceN * 0.12 +
yieldN * 0.1 +
stability * 0.1 +
speed * 0.09 +
cannabinoid * 0.06;
return Math.round(clamp01(blended) * 1000) / 10;
}
// Thresholds calibrated against the simulated index distribution (the index tops
// out near 80 in practice) so every tier is reachable and legendary+ stay scarce:
// veterans land ~58% exotic / 12% legendary / 2% mythic / 0.1% primordial, while
// early players span common->rare with headroom to climb.
export function rarityTier(index: number): RarityTier {
if (index >= 77) return 'primordial';
if (index >= 74) return 'mythic';
if (index >= 70) return 'legendary';
if (index >= 65) return 'exotic';
if (index >= 60) return 'elite';
if (index >= 55) return 'rare';
if (index >= 49) return 'notable';
if (index >= 43) return 'uncommon';
return 'common';
}
export function rarityRank(tier: RarityTier): number {
return RARITY_TIERS.indexOf(tier);
}