Skip to content

Commit d18f66a

Browse files
committed
halves & quarters
1 parent b771db7 commit d18f66a

File tree

1 file changed

+56
-2
lines changed

1 file changed

+56
-2
lines changed

src/engine/predicates/wc/index.ts

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { countBy, identity, mapValues, sumBy } from 'lodash';
1+
import { chunk, countBy, identity, mapValues, stubTrue, sumBy } from 'lodash';
22

3-
import { type Confederation } from '#model/types';
3+
import { type Confederation, type Country } from '#model/types';
44
import type NationalTeam from '#model/team/NationalTeam';
55
import type UnknownNationalTeam from '#model/team/UnknownNationalTeam';
66
import { type Predicate } from '#engine/dfs/gs';
@@ -46,6 +46,56 @@ export default (year: number, teams: readonly Team[]): Predicate<Team> => {
4646
return r === 0 ? numGroups : r;
4747
});
4848

49+
const isPossibleByRankingConstraint = ((): Predicate<Team> => {
50+
if (year === 2026) {
51+
const quarters = [
52+
[4, 8, 5],
53+
[7, 3, 6],
54+
[2, 0, 11],
55+
[9, 1, 10],
56+
] satisfies number[][];
57+
58+
const halves = chunk(quarters, 2).map(c => c.flat());
59+
60+
const quarterByGroup = new Map(
61+
quarters.values().flatMap((arr, qi) => arr.values().map(i => [i, qi])),
62+
);
63+
64+
const firstFourTeams = (
65+
['Spain', 'Argentina', 'France', 'England'] satisfies Country[]
66+
).map(name => teams.find(t => t.name === name)!);
67+
68+
const rankByTeam = new Map(
69+
firstFourTeams.values().map((t, i) => [t.id, i]),
70+
);
71+
72+
return (picked, groups, groupIndex) => {
73+
const rank = rankByTeam.get(picked.id);
74+
if (rank !== undefined) {
75+
const quarter = quarterByGroup.get(groupIndex)!;
76+
const isAnotherTeamInSameQuarter = quarters[quarter].some(gi =>
77+
groups[gi].some(t => rankByTeam.has(t.id)),
78+
);
79+
if (isAnotherTeamInSameQuarter) {
80+
return false;
81+
}
82+
const half = quarter >> 1;
83+
const otherRank = rank ^ 1;
84+
const otherRankTeam = firstFourTeams[otherRank];
85+
const isOtherTeamInSameHalf = halves[half].some(gi =>
86+
groups[gi].some(t => t.id === otherRankTeam.id),
87+
);
88+
if (isOtherTeamInSameHalf) {
89+
return false;
90+
}
91+
}
92+
return true;
93+
};
94+
}
95+
96+
return stubTrue;
97+
})();
98+
4999
return (picked, groups, groupIndex) => {
50100
const group = groups[groupIndex];
51101
const currentPotIndex = getSmallestArrayLength(groups);
@@ -54,6 +104,10 @@ export default (year: number, teams: readonly Team[]): Predicate<Team> => {
54104
return false;
55105
}
56106

107+
if (!isPossibleByRankingConstraint(picked, groups, groupIndex)) {
108+
return false;
109+
}
110+
57111
const virtualGroup = [...group, picked] as const;
58112
const numRemainingTeams = groupSize - virtualGroup.length;
59113
const isGroupPossible = confMinMaxEntries.every(([conf, [min, max]]) => {

0 commit comments

Comments
 (0)