test

mail@pastecode.io avatarunknown
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)