sendou.ink/app/modules/brackets-manager/ordering.ts
Kalle fd48bced91
Migrate Prettier/Eslint/Stylelint setup to Biome (#1772)
* Initial

* CSS lint

* Test CI

* Add 1v1, 2v2, and 3v3 Tags (#1771)

* Initial

* CSS lint

* Test CI

* Rename step

---------

Co-authored-by: xi <104683822+ximk@users.noreply.github.com>
2024-06-24 13:07:17 +03:00

144 lines
3.9 KiB
TypeScript

// https://web.archive.org/web/20200601102344/https://tl.net/forum/sc2-tournaments/202139-superior-double-elimination-losers-bracket-seeding
import type { SeedOrdering } from "~/modules/brackets-model";
import invariant from "~/utils/invariant";
import type { OrderingMap } from "./types";
export const ordering: OrderingMap = {
natural: <T>(array: T[]) => [...array],
reverse: <T>(array: T[]) => [...array].reverse(),
half_shift: <T>(array: T[]) => [
...array.slice(array.length / 2),
...array.slice(0, array.length / 2),
],
reverse_half_shift: <T>(array: T[]) => [
...array.slice(0, array.length / 2).reverse(),
...array.slice(array.length / 2).reverse(),
],
pair_flip: <T>(array: T[]) => {
const result: T[] = [];
for (let i = 0; i < array.length; i += 2)
result.push(array[i + 1], array[i]);
return result;
},
// https://stackoverflow.com/a/11631472
space_between: <T>(array: T[]) => {
const numPlayers = array.length;
const rounds = Math.log(numPlayers) / Math.log(2) - 1;
let pls = [1, 2];
for (let i = 0; i < rounds; i++) {
pls = nextLayer(pls);
}
return seedsToOrderedArray(pls);
function nextLayer(pls: number[]) {
const out: number[] = [];
const length = pls.length * 2 + 1;
for (const d of pls) {
out.push(d);
out.push(length - d);
}
return out;
}
// this part added to the SO answer
function seedsToOrderedArray(seeds: number[]) {
return seeds.map((seed) => {
const participant = array[seed - 1];
invariant(participant !== undefined, `No participant for seed ${seed}`);
return participant;
});
}
},
inner_outer: <T>(array: T[]) => {
if (array.length === 2) return array;
const size = array.length / 4;
const innerPart = [
array.slice(size, 2 * size),
array.slice(2 * size, 3 * size),
]; // [_, X, X, _]
const outerPart = [array.slice(0, size), array.slice(3 * size, 4 * size)]; // [X, _, _, X]
const methods = {
inner(part: T[][]): T[] {
return [part[0].pop()!, part[1].shift()!];
},
outer(part: T[][]): T[] {
return [part[0].shift()!, part[1].pop()!];
},
};
const result: T[] = [];
/**
* Adds a part (inner or outer) of a part.
*
* @param part The part to process.
* @param method The method to use.
*/
function add(part: T[][], method: "inner" | "outer"): void {
if (part[0].length > 0 && part[1].length > 0)
result.push(...methods[method](part));
}
for (let i = 0; i < size / 2; i++) {
add(outerPart, "outer"); // Outer part's outer
add(innerPart, "inner"); // Inner part's inner
add(outerPart, "inner"); // Outer part's inner
add(innerPart, "outer"); // Inner part's outer
}
return result;
},
"groups.effort_balanced": <T>(array: T[], groupCount: number) => {
const result: T[] = [];
let i = 0;
let j = 0;
while (result.length < array.length) {
result.push(array[i]);
i += groupCount;
if (i >= array.length) i = ++j;
}
return result;
},
"groups.seed_optimized": <T>(array: T[], groupCount: number) => {
const groups = Array.from(Array(groupCount), (_): T[] => []);
for (let run = 0; run < array.length / groupCount; run++) {
if (run % 2 === 0) {
for (let group = 0; group < groupCount; group++)
groups[group].push(array[run * groupCount + group]);
} else {
for (let group = 0; group < groupCount; group++)
groups[groupCount - group - 1].push(array[run * groupCount + group]);
}
}
return groups.flat();
},
"groups.bracket_optimized": () => {
throw Error("Not implemented.");
},
};
export const defaultMinorOrdering: { [key: number]: SeedOrdering[] } = {
// 1 or 2: Not possible.
4: ["natural", "reverse"],
8: ["natural", "reverse", "natural"],
16: ["natural", "reverse_half_shift", "reverse", "natural"],
32: ["natural", "reverse", "half_shift", "natural", "natural"],
64: ["natural", "reverse", "half_shift", "reverse", "natural", "natural"],
128: [
"natural",
"reverse",
"half_shift",
"pair_flip",
"pair_flip",
"pair_flip",
"natural",
],
};