sendou.ink/app/features/sidebar/core/StreamRanking.ts
Kalle 0fbd851b91
Some checks are pending
E2E Tests / e2e (push) Waiting to run
Tests and checks on push / run-checks-and-tests (push) Waiting to run
Updates translation progress / update-translation-progress-issue (push) Waiting to run
Allow 1v1/2v2/3v3 tournaments to show on the sidebar for streams
2026-04-11 16:34:55 +03:00

77 lines
2.0 KiB
TypeScript

import type { SidebarStream } from "~/features/core/streams/streams.server";
import { TIERS, type TierName } from "~/features/mmr/mmr-constants";
import type { TournamentTierNumber } from "~/features/tournament/core/tiering";
type RankedStream = { stream: SidebarStream; score: number };
export function rank(
streams: RankedStream[],
maxStreams: number,
): SidebarStream[] {
const now = Math.floor(Date.now() / 1000);
const selected = streams
.sort((a, b) => a.score - b.score || a.stream.startsAt - b.stream.startsAt)
.slice(0, maxStreams);
const live = selected
.filter((rs) => rs.stream.startsAt <= now)
.sort((a, b) => a.score - b.score);
const upcoming = selected
.filter((rs) => rs.stream.startsAt > now)
.sort((a, b) => a.stream.startsAt - b.stream.startsAt);
return [...live, ...upcoming].map((rs) => rs.stream);
}
const SMALL_TOURNAMENT_PENALTY = 4;
export function tournamentTierToScore(
tier: TournamentTierNumber | null,
membersPerTeam?: number,
): number {
const base = tier ?? 9;
const isSmallTeamSize = (membersPerTeam ?? 4) < 4;
return Math.min(9, base + (isSmallTeamSize ? SMALL_TOURNAMENT_PENALTY : 0));
}
export function upcomingTournamentTierToScore(
tier: number,
membersPerTeam?: number,
): number {
const isSmallTeamSize = (membersPerTeam ?? 4) < 4;
return Math.min(
9,
tier + 4 + (isSmallTeamSize ? SMALL_TOURNAMENT_PENALTY : 0),
);
}
export function sendouQTierToScore(tier: {
name: TierName;
isPlus: boolean;
}): number {
const baseIndex = TIERS.findIndex((t) => t.name === tier.name);
if (baseIndex === -1) return 9;
return Math.min(9, baseIndex * 2 + (tier.isPlus ? 1 : 2));
}
const X_RANK_SCORES = [
[3800, 5],
[3600, 6],
[3400, 7],
[3200, 8],
[3000, 9],
] as const;
export function minXpForStreamToBeShown(): number {
return X_RANK_SCORES.at(-1)?.[0] ?? 3_000;
}
export function xpToScore(peakXp: number): number | null {
const entry = X_RANK_SCORES.find(([minXp]) => peakXp >= minXp);
return entry ? entry[1] : null;
}