sendou.ink/app/modules/brackets-manager/ordering.ts
Kalle ef78d3a2c2
Tournament full (#1373)
* Got something going

* Style overwrites

* width != height

* More playing with lines

* Migrations

* Start bracket initial

* Unhardcode stage generation params

* Link to match page

* Matches page initial

* Support directly adding seed to map list generator

* Add docs

* Maps in matches page

* Add invariant about tie breaker map pool

* Fix PICNIC lacking tie breaker maps

* Only link in bracket when tournament has started

* Styled tournament roster inputs

* Prefer IGN in tournament match page

* ModeProgressIndicator

* Some conditional rendering

* Match action initial + better error display

* Persist bestOf in DB

* Resolve best of ahead of time

* Move brackets-manager to core

* Score reporting works

* Clear winner on score report

* ModeProgressIndicator: highlight winners

* Fix inconsistent input

* Better text when submitting match

* mapCountPlayedInSetWithCertainty that works

* UNDO_REPORT_SCORE implemented

* Permission check when starting tournament

* Remove IGN from upsert

* View match results page

* Source in DB

* Match page waiting for teams

* Move tournament bracket to feature folder

* REOPEN_MATCH initial

* Handle proper resetting of match

* Inline bracket-manager

* Syncify

* Transactions

* Handle match is locked gracefully

* Match page auto refresh

* Fix match refresh called "globally"

* Bracket autoupdate

* Move fillWithNullTillPowerOfTwo to utils with testing

* Fix map lists not visible after tournament started

* Optimize match events

* Show UI while in progress to members

* Fix start tournament alert not being responsive

* Teams can check in

* Fix map list 400

* xxx -> TODO

* Seeds page

* Remove map icons for team page

* Don't display link to seeds after tournament has started

* Admin actions initial

* Change captain admin action

* Make all hooks ts

* Admin actions functioning

* Fix validate error not displaying in CatchBoundary

* Adjust validate args order

* Remove admin loader

* Make delete team button menancing

* Only include checked in teams to bracket

* Optimize to.id route loads

* Working show map list generator toggle

* Update full tournaments flow

* Make full tournaments work with many start times

* Handle undefined in crud

* Dynamic stage banner

* Handle default strat if map list generation fails

* Fix crash on brackets if less than 2 teams

* Add commented out test for reference

* Add TODO

* Add players from team during register

* TrustRelationship

* Prefers not to host feature

* Last before merge

* Rename some vars

* More renames
2023-05-15 22:37:43 +03:00

115 lines
3.3 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 "brackets-model";
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;
},
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,
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",
],
};