def build_stacks(self, players, optimizer): players_by_teams = get_players_grouped_by_teams(players) all_groups: List[BaseGroup] = [] for game in optimizer.games: groups = [ PlayersGroup( players=players_by_teams[game.home_team], min_from_group=self.min_from_team, ), PlayersGroup( players=players_by_teams[game.away_team], min_from_group=self.min_from_team, ), PlayersGroup( players=[ *players_by_teams[game.home_team], *players_by_teams[game.away_team] ], min_from_group=self.size, ) ] nested_group = NestedPlayersGroup( groups=groups, max_exposure=self.max_exposure, ) all_groups.append(nested_group) return [OptimizerStack(groups=all_groups)]
def apply(self, solver): all_restrict_positions = self.optimizer.same_team_restrict_positions if not all_restrict_positions: return players_by_team = get_players_grouped_by_teams( self.players_dict.keys()) for restrict_positions in all_restrict_positions: for team_players in players_by_team.values(): first_position_players = [ player for player in team_players if restrict_positions[0] in player.positions ] second_position_players = [ player for player in team_players if restrict_positions[1] in player.positions ] for players_combination in product(first_position_players, second_position_players): if players_combination[0] == players_combination[1]: continue variables = [ self.players_dict[player] for player in players_combination ] solver.add_constraint(variables, None, SolverSign.LTE, 1)
def build_stacks(self, players: List[Player], optimizer: 'LineupOptimizer') -> List[OptimizerStack]: players_by_teams = get_players_grouped_by_teams( players, for_teams=self.for_teams) all_positions = tuple(set(chain.from_iterable(self.positions))) positions_for_optimizer = Counter(self.positions) positions_for_optimizer[all_positions] = len(self.positions) all_groups = [] # type: List[BaseGroup] for team_name, team_players in players_by_teams.items(): groups = [] for positions, total in positions_for_optimizer.items(): groups.append( PlayersGroup( players=[ player for player in team_players if list_intersection(player.positions, positions) ], min_from_group=total, )) nested_group = NestedPlayersGroup( groups=groups, max_exposure=self.max_exposure_per_team.get( team_name, self.max_exposure), ) all_groups.append(nested_group) return [OptimizerStack(groups=all_groups)]
def apply(self, solver, players_dict): total_teams = self.optimizer.total_teams settings = self.optimizer.settings min_teams = settings.min_teams if not min_teams and not total_teams: return total_players = self.optimizer.settings.get_total_players() players_by_teams = get_players_grouped_by_teams( players_dict.keys(), for_positions=[ position for position in self.optimizer.available_positions if position not in settings.total_teams_exclude_positions ]) teams_variables = [] for team, team_players in players_by_teams.items(): variable = solver.add_variable('total_teams_%s' % team) teams_variables.append(variable) variables = [players_dict[player] for player in team_players] solver.add_constraint(variables, None, SolverSign.LTE, variable * total_players) solver.add_constraint(variables, None, SolverSign.GTE, variable) if total_teams: solver.add_constraint(teams_variables, None, SolverSign.EQ, total_teams) else: solver.add_constraint(teams_variables, None, SolverSign.GTE, min_teams)
def _create_constraints(self, solver, players_dict, exclude_teams=None): # type: (Solver, Dict[Player, Any], Optional[Set[str]]) -> None all_combinations = defaultdict(set) # type: DefaultDict[Tuple[Any, ...], Set[Any]] players_by_teams = get_players_grouped_by_teams(players_dict.keys()) for stack, total_stacks in self.stacks_dict.items(): stack_variables = [] variable_prefix = 'rules_%s' % '_'.join(str(stack)) all_positions = tuple(set(chain.from_iterable(stack))) positions_for_optimizer = Counter(stack) positions_for_optimizer[all_positions] = len(stack) for team_name, team_players in players_by_teams.items(): if exclude_teams and team_name in exclude_teams: variables = [players_dict[player] for player in team_players if list_intersection(player.positions, all_positions)] solver.add_constraint(variables, None, SolverSign.LTE, len(stack) - 1) continue variable_name = '%s_players_%s' % (variable_prefix, team_name) team_stack_var = solver.add_variable(variable_name) stack_variables.append(team_stack_var) for positions, total in positions_for_optimizer.items(): position_variables = set( players_dict[player] for player in sorted(team_players, key=lambda p: p.full_name) if list_intersection(player.positions, positions)) all_combinations[tuple(position_variables)].add(team_stack_var) solver.add_constraint(position_variables, None, SolverSign.GTE, total * team_stack_var) solver.add_constraint(stack_variables, None, SolverSign.GTE, total_stacks) for combination_variables in all_combinations.values(): if len(combination_variables) > 1: solver.add_constraint(combination_variables, None, SolverSign.LTE, 1)
def _get_players_combinations_by_team(self, players_dict): players_combinations_by_team = defaultdict(lambda: defaultdict( set)) # type: Dict[Tuple[str, ...], Dict[str, Set]] players_by_teams = get_players_grouped_by_teams(players_dict.keys()) for stack in self.stacks_dict.keys(): for team_name, team_players in players_by_teams.items(): all_players_combinations = set() players_by_positions = [] for position in stack: players_by_positions.append([ player for player in team_players if position in player.positions ]) # Create all possible players combinations for stack for players_combination in product(*players_by_positions): # Remove combinations with duplicated players if len(set(players_combination)) != len(stack): continue players_combination = tuple([ players_dict[player] for player in sorted(players_combination, key=lambda p: p.id) ]) all_players_combinations.add(players_combination) players_combinations_by_team[stack][ team_name] = all_players_combinations return players_combinations_by_team
def apply(self, solver, players_dict): all_players = players_dict.keys() for_positions = self.optimizer.team_stacks_for_positions if for_positions: all_players = [player for player in all_players if list_intersection(player.positions, for_positions)] players_by_teams = get_players_grouped_by_teams(all_players) for team, players in players_by_teams.items(): variables = [players_dict[player] for player in players] self.player_variables_by_teams[team] = variables if not self.teams_max_exposures: self._create_constraints(solver)
def build_stacks(self, players: List[Player], optimizer: 'LineupOptimizer') -> List[OptimizerStack]: players_by_teams = get_players_grouped_by_teams( players, for_teams=self.for_teams, for_positions=self.for_positions) groups = [] # type: List[BaseGroup] spacing_groups = [] # type: List[BaseGroup] for team, players in players_by_teams.items(): parent_group = PlayersGroup( players=players, min_from_group=self.size, max_exposure=self.max_exposure_per_team.get( team, self.max_exposure)) groups.append(parent_group) if not self.spacing: continue players_by_roster_positions = defaultdict( list) # type: Dict[int, List[Player]] for player in players: if player.roster_order is None: continue players_by_roster_positions[player.roster_order].append(player) if not players_by_roster_positions: continue all_allowed_roster_orders = set() max_spacing = max(players_by_roster_positions.keys()) for roster_position in players_by_roster_positions.keys(): allowed_roster_orders = [] for i in range(self.spacing): if roster_position + i <= max_spacing: allowed_roster_orders.append(roster_position + i) else: allowed_roster_orders.append(((roster_position + i) % (max_spacing + 1)) + 1) all_allowed_roster_orders.add( tuple(sorted(allowed_roster_orders))) for roster_orders in all_allowed_roster_orders: spacing_groups.append( PlayersGroup( players=list( chain.from_iterable( players for players_spacing, players in players_by_roster_positions.items() if players_spacing in roster_orders)), min_from_group=self.size, parent=parent_group, )) stacks = [OptimizerStack(groups=groups)] if spacing_groups: stacks.append( OptimizerStack(groups=spacing_groups, can_intersect=True)) return stacks
def apply(self, solver): settings = self.optimizer.settings min_teams = self.optimizer.min_teams or settings.min_teams max_teams = self.optimizer.max_teams if not min_teams and not max_teams: return total_players = self.optimizer.settings.get_total_players() players_by_teams = get_players_grouped_by_teams( self.players_dict.keys(), for_positions=[ position for position in self.optimizer.player_pool.available_positions if position not in settings.total_teams_exclude_positions ]) teams_variables = [] for team, team_players in players_by_teams.items(): variable = solver.add_variable('total_teams_%s' % team) teams_variables.append(variable) variables = [self.players_dict[player] for player in team_players] solver.add_constraint(variables, None, SolverSign.LTE, variable * total_players) solver.add_constraint(variables, None, SolverSign.GTE, variable) if min_teams == max_teams: solver.add_constraint(teams_variables, None, SolverSign.EQ, min_teams, name='exact_teams') if min_teams: solver.add_constraint(teams_variables, None, SolverSign.GTE, min_teams, name='min_teams') if max_teams: solver.add_constraint(teams_variables, None, SolverSign.LTE, max_teams, name='max_teams')
def build_stacks(self, players: List[Player], optimizer: 'LineupOptimizer') -> List[OptimizerStack]: players_by_teams = get_players_grouped_by_teams( players, for_teams=self.for_teams, for_positions=self.for_positions) groups = [] # type: List[BaseGroup] for team, players in players_by_teams.items(): groups.append( PlayersGroup(players=players, min_from_group=self.size, max_exposure=self.max_exposure_per_team.get( team, self.max_exposure))) if self.spacing: sub_groups = [] players_by_roster_positions = defaultdict( list) # type: Dict[int, List[Player]] for player in players: if player.roster_order is None: continue players_by_roster_positions[player.roster_order].append( player) for roster_position, players in players_by_roster_positions.items( ): next_restricted_roster_position = roster_position + self.spacing restricted_players = chain.from_iterable( players for players_spacing, players in players_by_roster_positions.items() if players_spacing >= next_restricted_roster_position) for first_player in restricted_players: for second_player in players: sub_groups.append( PlayersGroup( players=[first_player, second_player], max_from_group=1, )) groups.append(NestedPlayersGroup(groups=sub_groups, )) return [OptimizerStack(groups=groups)]