Skip to content

Commit

Permalink
More compact schedule (fewer bye weeks) in FBGM
Browse files Browse the repository at this point in the history
  • Loading branch information
dumbmatter committed Feb 21, 2024
1 parent d5313c6 commit b6e3515
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 1 deletion.
2 changes: 1 addition & 1 deletion TODO
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
reduce number of bye weeks - see how baseball schedule is divided into series
FBGM kick FG in overtime when losing by TD? https://old.reddit.com/r/Football_GM/comments/1av0fev/overtime_logic_may_need_a_tweak/

FBGM snap counts https://discord.com/channels/@me/778760871911751700/1206814062621491233
- by position?
Expand Down
88 changes: 88 additions & 0 deletions src/worker/core/season/groupScheduleCompact.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { orderBy } from "../../../common/utils";
import { random } from "../../util";

const groupScheduleCompact = (tids: [number, number][]) => {
const dailyMatchups: [number, number][][] = [];

const matchups = [...tids];
random.shuffle(matchups);

const remainingMatchups = new Set(matchups);

const allTids = Array.from(new Set(tids.flat()));

while (remainingMatchups.size > 0) {
const tidsUsed = new Set();

const matchupsToday: [number, number][] = [];
dailyMatchups.push(matchupsToday);

// First look at games from teams with the most games left, otherwise they might be left until the end and take up entire days with one team
const numGamesLeftByTid: Record<number, number> = {};
for (const matchup of remainingMatchups) {
for (const tid of matchup) {
if (numGamesLeftByTid[tid] === undefined) {
numGamesLeftByTid[tid] = 1;
} else {
numGamesLeftByTid[tid] += 1;
}
}
}
const remainingMatchupsArray = orderBy(
Array.from(remainingMatchups),
matchup => {
return Math.min(...matchup.map(tid => numGamesLeftByTid[tid] ?? 0));
},
"desc",
);

for (const matchup of remainingMatchupsArray) {
if (!tidsUsed.has(matchup[0]) && !tidsUsed.has(matchup[1])) {
matchupsToday.push(matchup);
remainingMatchups.delete(matchup);
tidsUsed.add(matchup[0]);
tidsUsed.add(matchup[1]);

if (tidsUsed.size === allTids.length) {
break;
}
}
}
}

// Start on 2nd to last day, see what we can move to the last day. Keep repeating, going further back each time. This is to make the end of season schedule less "jagged" (fewer teams that end the season early)
for (
let startIndex = dailyMatchups.length - 2;
startIndex >= 0;
startIndex--
) {
for (let i = startIndex; i < dailyMatchups.length - 1; i++) {
const today = dailyMatchups[i];
const tomorrow = dailyMatchups[i + 1];

const tidsTomorrow = new Set(tomorrow.flat());

const toRemove = [];
for (let k = 0; k < today.length; k++) {
const matchup = today[k];
if (!tidsTomorrow.has(matchup[0]) && !tidsTomorrow.has(matchup[1])) {
tomorrow.push(matchup);
toRemove.push(k);
}
}

// Remove from end, so indexes don't change
toRemove.reverse();
for (const index of toRemove) {
today.splice(index, 1);
}
}
}

// Some jaggedness remains, so just randomize it
random.shuffle(dailyMatchups);

return dailyMatchups.flat();
};

export default groupScheduleCompact;
5 changes: 5 additions & 0 deletions src/worker/core/season/newScheduleGood.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { groupByUnique, orderBy, range } from "../../../common/utils";
import type { Div, GameAttributesLeague } from "../../../common/types";
import { TOO_MANY_TEAMS_TOO_SLOW } from "./getInitialNumGamesConfDivSettings";
import groupScheduleSeries from "./groupScheduleSeries";
import { isSport } from "../../../common";
import groupScheduleCompact from "./groupScheduleCompact";

type MyTeam = {
seasonAttrs: {
Expand Down Expand Up @@ -753,6 +755,9 @@ const newSchedule = (
if (Object.hasOwn(g, "groupScheduleSeries") && g.get("groupScheduleSeries")) {
// Group schedule into series
tids = groupScheduleSeries(tids);
} else if (isSport("football")) {
// For football, ideally we'd have explicit bye weeks, but failing that we should at least make the schedule as compact as possible. Whereas the code below makes it only somewhat compact.
tids = groupScheduleCompact(tids);
} else {
// Order the schedule so that it takes fewer days to play
random.shuffle(tids);
Expand Down

0 comments on commit b6e3515

Please sign in to comment.