sendou.ink/app/components/match-page/utils.ts
Kalle 2b5b1b1948
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
New match page (#3032)
2026-05-04 18:15:10 +03:00

84 lines
2.2 KiB
TypeScript

import * as R from "remeda";
import type { CommonUser } from "~/utils/kysely.server";
import { seededRandom } from "~/utils/random";
type MatchSide = "ALPHA" | "BRAVO";
type Rosters = {
alpha: CommonUser[];
bravo: CommonUser[];
};
export interface InferredSubstitution {
side: MatchSide;
playerOut: CommonUser;
playerIn: CommonUser;
}
/**
* Compares the rosters of two consecutive maps and pairs up any
* players that dropped from a side with new players that joined the same side.
* The pairs are returned in roster order, so the first player out is paired with
* the first new player in. When the counts don't match, unpaired players are ignored.
*/
export function inferSubstitutions(
previousRosters: Rosters,
currentRosters: Rosters,
): InferredSubstitution[] {
const result: InferredSubstitution[] = [];
for (const side of ["alpha", "bravo"] as const) {
const prevIds = new Set(previousRosters[side].map((u) => u.id));
const currIds = new Set(currentRosters[side].map((u) => u.id));
const out = previousRosters[side].filter((u) => !currIds.has(u.id));
const inn = currentRosters[side].filter((u) => !prevIds.has(u.id));
for (const [playerOut, playerIn] of R.zip(out, inn)) {
result.push({
side: side === "alpha" ? "ALPHA" : "BRAVO",
playerOut,
playerIn,
});
}
}
return result;
}
const NUM_MAP = {
"1": ["1", "2", "4"],
"2": ["2", "1", "3", "5"],
"3": ["3", "2", "6"],
"4": ["4", "1", "5", "7"],
"5": ["5", "2", "4", "6", "8"],
"6": ["6", "3", "5", "9"],
"7": ["7", "4", "8"],
"8": ["8", "7", "5", "9", "0"],
"9": ["9", "6", "8"],
"0": ["0", "8"],
};
/**
* Generates a deterministic 4-digit Splatoon private battle room password based on the provided seed.
*
* Given the same seed, this function will always return the same password.
*/
export function resolveRoomPass(seed: number | string) {
let pass = "5";
for (let i = 0; i < 3; i++) {
const { seededShuffle } = seededRandom(`${seed}-${i}`);
const key = pass[i] as keyof typeof NUM_MAP;
const opts = NUM_MAP[key];
const next = seededShuffle(opts)[0];
pass += next;
}
// prevent 5555 since many use it as a default pass
// making it a bit more common guess
if (pass === "5555") return "5800";
return pass;
}