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' ;
44import type NationalTeam from '#model/team/NationalTeam' ;
55import type UnknownNationalTeam from '#model/team/UnknownNationalTeam' ;
66import { 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