test
typescript
a month ago
3.5 kB
4
Indexable
Never
interface Team { name: string province: string club: string } interface Groups { A: Team[] B: Team[] C: Team[] D: Team[] } function shuffleArray(array: any[]) { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)) ;[array[i], array[j]] = [array[j], array[i]] } } function areSameClub(team1: Team, team2: Team) { return team1.club === team2.club } function hasThreeTeamsFromSameProvince(group: Team[], province: string) { const provinceCount = group.filter(team => team.province === province).length return provinceCount >= 3 } function isGroupFull(group: any[]) { return group.length >= 4 } // Main algorithm function distributeTeams(seedTeams: Team[], otherTeams: Team[]) { const groups: Groups = { A: [], B: [], C: [], D: [] } // Shuffle seedTeams shuffleArray(seedTeams) // Assign seed teams to groups seedTeams.forEach((seedTeam: Team, index: number) => { const group: string = Object.keys(groups)[index] groups[group as keyof Groups].push(seedTeam) }) // Shuffle otherTeams shuffleArray(otherTeams) // *** Move team Stechco2 to the last position of otherTeams (to make sure Stechco2 is assigned first) // The reason we do this is to avoid a potential bug where at the end we can not assign Stechco2 to any group due to the conditions const stechco2Index = otherTeams.findIndex(team => team.name === 'Stechco2') if (stechco2Index !== -1) { otherTeams.push(...otherTeams.splice(stechco2Index, 1)) } // As long as otherTeams is not empty, push the team to each group based on the conditions while (otherTeams.length > 0) { // Get the current last team from otherTeams and remove it from otherTeams // @ts-ignore const currentTeam: Team = otherTeams.pop() // Find a group that satisfies 3 conditions, if all satisfied, push currentTeam to that group for (const group in groups) { const province = currentTeam.province if ( groups[group as keyof Groups].every( team => !areSameClub(currentTeam, team) ) && !hasThreeTeamsFromSameProvince( groups[group as keyof Groups], province ) && !isGroupFull(groups[group as keyof Groups]) ) { groups[group as keyof Groups].push(currentTeam) break } } } return groups } // ----------- Example --------------- const seedTeams: Team[] = [ { name: 'Stechco1', province: 'Quebec', club: 'Stechco' }, { name: 'VietUnitedFC', province: 'BC', club: 'VietUnitedFC' }, { name: 'CICC', province: 'Ontario', club: 'CICC' }, { name: 'CalgaryVFC', province: 'Alberta', club: 'CalgaryVFC' } ] const otherTeams: Team[] = [ { name: 'CTC', province: 'Ontario', club: 'CTC' }, { name: 'FCKingston', province: 'Ontario', club: 'FCKingston' }, { name: 'KWFC', province: 'Ontario', club: 'KWFC' }, { name: 'BFC', province: 'Ontario', club: 'BFC' }, { name: 'YGOfVN', province: 'Ontario', club: 'YGOfVN' }, { name: 'FCAE', province: 'Ontario', club: 'FCAE' }, { name: 'LankFC', province: 'Ontario', club: 'LankFC' }, { name: 'SFC', province: 'Quebec', club: 'SFC' }, { name: 'VMU', province: 'Quebec', club: 'VMU' }, { name: 'Stechco2', province: 'Quebec', club: 'Stechco' }, { name: 'FC3Mien', province: 'Quebec', club: 'FC3Mien' }, { name: 'RBJunior', province: 'Quebec', club: 'RBJunior' } ] const result: Groups = distributeTeams(seedTeams, otherTeams) console.log(result)