mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-12 12:31:42 -05:00
Fix not optimal matchlist found with recently played matches
This commit is contained in:
@@ -55,7 +55,11 @@ function generateWithInput(
|
||||
if (validationError) return err(validationError);
|
||||
|
||||
const { seededShuffle } = seededRandom(input.seed);
|
||||
const stages = seededShuffle(resolveCommonStages());
|
||||
// trying the least recently played maps first lets the search find a good
|
||||
// enough list before the recursion depth cap is hit
|
||||
const stages = seededShuffle(resolveCommonStages()).sort(
|
||||
(a, b) => recencyPenalty(a) - recencyPenalty(b),
|
||||
);
|
||||
const mapList: Array<ModeWithStageAndScore & { score: number }> = [];
|
||||
const bestMapList: { maps?: Array<ModeWithStageAndScore>; score: number } = {
|
||||
score: Number.POSITIVE_INFINITY,
|
||||
@@ -108,10 +112,12 @@ function generateWithInput(
|
||||
return true;
|
||||
};
|
||||
|
||||
const success = backtrack();
|
||||
const searchExhausted = backtrack();
|
||||
|
||||
if (!success) return err("MAX_RECURSION_DEPTH_EXCEEDED");
|
||||
// a complete list found before the depth cap was hit is still valid,
|
||||
// only its optimality is unproven
|
||||
if (bestMapList.maps) return ok(bestMapList.maps);
|
||||
if (!searchExhausted) return err("MAX_RECURSION_DEPTH_EXCEEDED");
|
||||
|
||||
return err("COULD_NOT_GENERATE_MAPLIST");
|
||||
|
||||
@@ -435,26 +441,24 @@ function generateWithInput(
|
||||
score += 100;
|
||||
}
|
||||
|
||||
if (input.recentlyPlayedMaps) {
|
||||
for (const map of mapList) {
|
||||
const recentIndex = input.recentlyPlayedMaps.findIndex(
|
||||
(recent) =>
|
||||
recent.stageId === map.stageId && recent.mode === map.mode,
|
||||
);
|
||||
|
||||
if (recentIndex !== -1) {
|
||||
const recencyPenalty = Math.max(
|
||||
10 - Math.floor(recentIndex / 2) * 2,
|
||||
0,
|
||||
);
|
||||
score += recencyPenalty;
|
||||
}
|
||||
}
|
||||
for (const map of mapList) {
|
||||
score += recencyPenalty(map);
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
function recencyPenalty(map: Pick<TournamentMapListMap, "stageId" | "mode">) {
|
||||
if (!input.recentlyPlayedMaps) return 0;
|
||||
|
||||
const recentIndex = input.recentlyPlayedMaps.findIndex(
|
||||
(recent) => recent.stageId === map.stageId && recent.mode === map.mode,
|
||||
);
|
||||
if (recentIndex === -1) return 0;
|
||||
|
||||
return Math.max(10 - Math.floor(recentIndex / 2) * 2, 0);
|
||||
}
|
||||
|
||||
function lastMapIsAGoodTieBreaker() {
|
||||
// guaranteed to be good if more than one mode
|
||||
if (!tournamentIsOneModeOnly()) return true;
|
||||
|
||||
@@ -798,6 +798,46 @@ describe("TournamentMapListGeneratorOneMode", () => {
|
||||
});
|
||||
|
||||
describe("Recently played maps", () => {
|
||||
test("One mode Bo7 avoids recently played maps when a full avoiding list exists", () => {
|
||||
const team1Pool = new MapPool(
|
||||
([1, 2, 3, 4, 5, 6] as const).map((stageId) => ({
|
||||
mode: "SZ" as const,
|
||||
stageId,
|
||||
})),
|
||||
);
|
||||
const team2Pool = new MapPool(
|
||||
([7, 8, 9, 10, 11, 12] as const).map((stageId) => ({
|
||||
mode: "SZ" as const,
|
||||
stageId,
|
||||
})),
|
||||
);
|
||||
// the bo5 both teams played right before this match
|
||||
const recentlyPlayedMaps = ([1, 7, 2, 8, 3] as const).map((stageId) => ({
|
||||
mode: "SZ" as const,
|
||||
stageId,
|
||||
}));
|
||||
|
||||
const mapList = generateMaps({
|
||||
count: 7,
|
||||
seed: "1000",
|
||||
teams: [
|
||||
{ id: 1, maps: team1Pool },
|
||||
{ id: 2, maps: team2Pool },
|
||||
],
|
||||
tiebreakerMaps: new MapPool([]),
|
||||
modesIncluded: ["SZ"],
|
||||
recentlyPlayedMaps,
|
||||
});
|
||||
|
||||
const recentMapsInList = mapList.filter((map) =>
|
||||
recentlyPlayedMaps.some(
|
||||
(recent) => recent.mode === map.mode && recent.stageId === map.stageId,
|
||||
),
|
||||
);
|
||||
|
||||
expect(recentMapsInList).toEqual([]);
|
||||
});
|
||||
|
||||
test("Avoids recently played maps when possible", () => {
|
||||
const recentlyPlayedMaps = [
|
||||
{ mode: "SZ" as const, stageId: 4 as const },
|
||||
|
||||
Reference in New Issue
Block a user