From dc84895b4ed1dfb9e4d88539385d7d9a9eaffb35 Mon Sep 17 00:00:00 2001 From: "Kalle (Sendou)" <38327916+Sendouc@users.noreply.github.com> Date: Fri, 17 Dec 2021 10:12:43 +0200 Subject: [PATCH] Map list algorithm better mode picking Don't repeat a mode before other modes have appeared in the round --- app/core/tournament/mapList.test.ts | 24 +++++++++++++++++++++++- app/core/tournament/mapList.ts | 17 ++++++++++++++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/app/core/tournament/mapList.test.ts b/app/core/tournament/mapList.test.ts index 9f087e259..309c1eede 100644 --- a/app/core/tournament/mapList.test.ts +++ b/app/core/tournament/mapList.test.ts @@ -1,4 +1,4 @@ -import { Stage } from ".prisma/client"; +import type { Mode, Stage } from ".prisma/client"; import clone from "just-clone"; import { suite } from "uvu"; import * as assert from "uvu/assert"; @@ -8,6 +8,7 @@ import { generateMapListForRounds } from "./mapList"; const MapListForRounds = suite("generateMapListMapForRounds()"); +const ALL_MODES_LENGTH = 4; const mapPool: Stage[] = JSON.parse( `[{"id":923,"mode":"TC","name":"The Reef"},{"id":925,"mode":"CB","name":"The Reef"},{"id":927,"mode":"SZ","name":"Musselforge Fitness"},{"id":929,"mode":"RM","name":"Musselforge Fitness"},{"id":934,"mode":"RM","name":"Starfish Mainstage"},{"id":942,"mode":"SZ","name":"Inkblot Art Academy"},{"id":943,"mode":"TC","name":"Inkblot Art Academy"},{"id":947,"mode":"SZ","name":"Sturgeon Shipyard"},{"id":948,"mode":"TC","name":"Sturgeon Shipyard"},{"id":953,"mode":"TC","name":"Moray Towers"},{"id":959,"mode":"RM","name":"Port Mackerel"},{"id":960,"mode":"CB","name":"Port Mackerel"},{"id":972,"mode":"SZ","name":"Snapper Canal"},{"id":978,"mode":"TC","name":"Blackbelly Skatepark"},{"id":980,"mode":"CB","name":"Blackbelly Skatepark"},{"id":985,"mode":"CB","name":"MakoMart"},{"id":987,"mode":"SZ","name":"Walleye Warehouse"},{"id":988,"mode":"TC","name":"Walleye Warehouse"},{"id":994,"mode":"RM","name":"Shellendorf Institute"},{"id":995,"mode":"CB","name":"Shellendorf Institute"},{"id":1007,"mode":"SZ","name":"Piranha Pit"},{"id":1012,"mode":"SZ","name":"Camp Triggerfish"},{"id":1019,"mode":"RM","name":"Wahoo World"},{"id":1020,"mode":"CB","name":"Wahoo World"},{"id":1027,"mode":"SZ","name":"Ancho-V Games"},{"id":1034,"mode":"RM","name":"Skipper Pavilion"}]` ); @@ -42,4 +43,25 @@ MapListForRounds("Should have all the map and mode combos", () => { assert.equal(mapPoolToEmpty.length, 0); }); +MapListForRounds( + "Should not repeat mode (except SZ) in a round before other modes have appeared", + () => { + for (const side of [mapList.winners, mapList.losers]) { + for (const round of side) { + const modes: Mode[] = []; + for (const stage of round) { + if ( + modes.includes(stage.mode) && + modes.length < ALL_MODES_LENGTH && + stage.mode !== "SZ" + ) { + throw new Error(`Repeated mode: ${JSON.stringify(round, null, 2)}`); + } + modes.push(stage.mode); + } + } + } + } +); + MapListForRounds.run(); diff --git a/app/core/tournament/mapList.ts b/app/core/tournament/mapList.ts index d674af5ef..e2b6dafd7 100644 --- a/app/core/tournament/mapList.ts +++ b/app/core/tournament/mapList.ts @@ -27,6 +27,7 @@ export function generateMapListForRounds({ }, []); let currentModes = clone(modes); const hasSZ = mapPool.some((stage) => stage.mode === "SZ"); + const allModesLength = modes.length + Number(hasSZ); return { winners: rounds.winners.map((round) => roundsMapList(round)), @@ -81,8 +82,18 @@ export function generateMapListForRounds({ resetCurrentModesIfWouldHaveToRepeatMode(previous); currentModes = shuffle(currentModes); currentModes.sort((a, b) => { - if (previous && previous === a[0]) return 1; - if (previous && previous === b[0]) return -1; + // Don't repeat a mode before all the modes have appeared in a round + const modesOfTheRound = Array.from(new Set(resultWithNoNull)); + if (modesOfTheRound.length < allModesLength) { + if ( + modesOfTheRound.includes(a[0]) && + modesOfTheRound.includes(b[0]) + ) { + return 0; + } + if (modesOfTheRound.includes(b[0])) return -1; + if (modesOfTheRound.includes(a[0])) return 1; + } return b[1] - a[1]; }); @@ -171,7 +182,7 @@ export function generateMapListForRounds({ !stagesAlreadyIncludedThisRound.includes(mapPoolMap.name) ); - // TODO: handle this smarter + // TODO: handle this fallback behavior smarter if (!stage) { stage = stages.find((mapPoolMap) => mapPoolMap.modes.includes(mode)); }