sendou.ink/app/utils/arrays.ts
Kalle 144da5d158
Tournament groups->SE, underground bracket etc. (#1628)
* Renders groups

* Bracket data refactoring

* Starting bracket working (first bracket only)

* TODOs + crash fix

* Source bracket logic initial

* Bracket progression (DE underground bracket)

* Preview working for second bracket

* Bracket nav initial

* Check-in to bracket feature

* Start Underground bracket

* Team/teams pages tweaks to support underground bracket

* Underground bracket finalization progress

* Tournament class

* id -> userId + more useOutletContext removed

* Bracket loader refactored out

* Migrate admin to useTournament

* Bracket.settings

* Slim tournament loader

* Fix useEffect infinite loop

* Adjust waiting for teams text

* Refactor old tournament DB call from to admin

* Admin action: check in/out from specific bracket

* Standings work

* Back button from match page -> correct bracket

* Standings logic for DE grand finals

* Standings + finalize bracket

* Dev log

* Unit tests utils etc.

* Adjust TODOs

* Fix round robin issues

* Add RR tests

* Round robin standings initial

* Wins against tied + points tiebreaker progress

* Fix losing state when switching between tabs

* Add check-in indications to seeding page

* Link to user page on seed tool

* Submit points

* Total points from bracket manager

* findById gonezino

* Ahead of time check-in

* Couple todos

* Reopen logic refactor

* Tournament format settings

* RR->SE placements, skipping underground bracket

* Fix tournament team page round names

* More teams to UG bracket if first round of DE only byes

* Fix graphics bug

* Fixes

* Fix some E2E tests

* Fix E2E tests
2024-01-30 00:32:13 +02:00

94 lines
2.5 KiB
TypeScript

// TODO: when more examples of permissions profile difference between
// this implementation and one that takes arrays
import clone from "just-clone";
import shuffle from "just-shuffle";
import invariant from "tiny-invariant";
// (not all arrays need to necessarily run but they need to be defined)
export function allTruthy(arr: unknown[]) {
return arr.every(Boolean);
}
/** Mimics Array.prototype.at except throws an error if index out of bounds */
export function atOrError<T>(arr: T[], n: number) {
const result = at(arr, n);
if (result === undefined) {
throw new Error(`Index ${n} out of bounds. Array length is ${arr.length}`);
}
return result;
}
// https://github.com/tc39/proposal-relative-indexing-method#polyfill
/** Array.at polyfill */
function at<T>(arr: T[], n: number) {
// ToInteger() abstract op
n = Math.trunc(n) || 0;
// Allow negative indexing from the end
if (n < 0) n += arr.length;
// OOB access is guaranteed to return undefined
if (n < 0 || n >= arr.length) return undefined;
// Otherwise, this is just normal property access
return arr[n];
}
// TODO: i18n (at least for SendouQ)
export function joinListToNaturalString(arg: string[], lastSeparator = "and") {
if (arg.length === 1) return arg[0];
const list = [...arg];
const last = list.pop();
const commaJoined = list.join(", ");
return last ? `${commaJoined} ${lastSeparator} ${last}` : commaJoined;
}
export function normalizeFormFieldArray(
value: undefined | null | string | string[],
): string[] {
return value == null ? [] : typeof value === "string" ? [value] : value;
}
/** Can be used as a strongly typed array filter */
export function isDefined<T>(value: T | undefined | null): value is T {
return value !== null && value !== undefined;
}
export function removeDuplicates<T>(arr: T[]): T[] {
const seen = new Set<T>();
return arr.filter((item) => {
if (seen.has(item)) return false;
seen.add(item);
return true;
});
}
export function removeDuplicatesByProperty<T>(
arr: T[],
getter: (arg0: T) => number | string,
): T[] {
const seen = new Set();
return arr.filter((item) => {
const id = getter(item);
if (seen.has(id)) return false;
seen.add(id);
return true;
});
}
export function nullFilledArray(size: number) {
return new Array(size).fill(null);
}
export function pickRandomItem<T>(array: T[]): T {
invariant(array.length > 0, "Can't pick from empty array");
const shuffled = shuffle(clone(array));
return shuffled[0];
}