Map list algorithm better mode picking

Don't repeat a mode before other modes have appeared in the round
This commit is contained in:
Kalle (Sendou)
2021-12-17 10:12:43 +02:00
parent 2cef8ad5e4
commit dc84895b4e
2 changed files with 37 additions and 4 deletions

View File

@@ -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();

View File

@@ -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));
}