def set_total_teams(self, total_teams: Optional[int] = None, min_teams: Optional[int] = None, max_teams: Optional[int] = None): if not any((total_teams, min_teams, max_teams)): raise LineupOptimizerException('At least one parameter should be passed') if total_teams: min_teams = total_teams max_teams = total_teams show_deprecation_warning('total_teams parameter is replaced with min_teams/max_teams parameters and ' 'will be removed in version 3.7') available_teams = len(self.player_pool.available_teams) if min_teams is not None and max_teams is not None and min_teams > max_teams: raise LineupOptimizerException('min_teams can\'t be greater than max_teams') if (min_teams is not None and min_teams > available_teams) or \ (max_teams is not None and max_teams > available_teams): raise LineupOptimizerException('Only %d teams available' % available_teams) total_players = self.settings.get_total_players() settings_min_teams = self.settings.min_teams max_from_one_team = self.settings.max_from_one_team if not settings_min_teams and max_from_one_team: settings_min_teams = ceil(total_players / max_from_one_team) if settings_min_teams and (( max_teams is not None and max_teams < settings_min_teams ) or ( min_teams is not None and min_teams < settings_min_teams )): raise LineupOptimizerException('Minimum number of teams is %d' % settings_min_teams) if (min_teams is not None and min_teams > total_players) or \ (max_teams is not None and max_teams > total_players): raise LineupOptimizerException('Maximum number of teams is %d' % total_players) self.min_teams = min_teams self.max_teams = max_teams
def optimize( self, n: int, max_exposure: Optional[float] = None, randomness: bool = False, with_injured: bool = False, exposure_strategy: Type[BaseExposureStrategy] = TotalExposureStrategy, ) -> Generator[Lineup, None, None]: players = [player for player in self.players if player.max_exposure is None or player.max_exposure > 0] context = OptimizationContext( total_lineups=n, players=players, max_exposure=max_exposure, randomness=randomness, with_injured=with_injured, exposure_strategy=exposure_strategy, ) rules = self._rules.copy() rules.update(self.settings.extra_rules) if randomness: show_deprecation_warning('Randomness parameter is deprecated and will be removed in 3.6, ' 'use set_fantasy_points_strategy instead') self.set_fantasy_points_strategy(RandomFantasyPointsStrategy(self._min_deviation, self._max_deviation)) rules.add(Objective) if with_injured: rules.remove(RemoveInjuredRule) base_solver = self._solver_class() base_solver.setup_solver() players_dict = OrderedDict( [(player, base_solver.add_variable('Player_%d' % i)) for i, player in enumerate(players)]) variables_dict = {v: k for k, v in players_dict.items()} constraints = [constraint(self, players_dict, context) for constraint in rules] for constraint in constraints: constraint.apply(base_solver) previous_lineup = None for _ in range(n): solver = base_solver.copy() # type: Solver for constraint in constraints: constraint.apply_for_iteration(solver, previous_lineup) try: solved_variables = solver.solve() lineup_players = [] variables_names = [] for solved_variable in solved_variables: player = variables_dict.get(solved_variable) if player: lineup_players.append(player) variables_names.append(solved_variable.name) lineup = self._build_lineup(lineup_players, context) previous_lineup = lineup context.add_lineup(lineup) yield lineup if self.total_players and len(self.locked_players) == self.total_players: return for constraint in constraints: constraint.post_optimize(variables_names) except SolverInfeasibleSolutionException as solver_exception: raise GenerateLineupException(solver_exception.get_user_defined_constraints()) self.last_context = context
def set_deviation(self, min_deviation: float, max_deviation: float): """ Set deviation ranges for randomness mode """ show_deprecation_warning('set_deviation method is deprecated and will be removed in 3.6, ' 'set deviation in RandomFantasyPointsStrategy instead') self._min_deviation = min_deviation self._max_deviation = max_deviation
def find_players(self, name: str) -> List[Player]: """ Return list of players with similar name. """ show_deprecation_warning('find_players will be removed in version 3.7') player_pool = self.player_pool possibilities = [(player, ratio(name, player.full_name)) for player in player_pool.all_players] filtered_possibilities = filter(lambda pos: pos[1] >= player_pool.search_threshold, possibilities) players = sorted(filtered_possibilities, key=lambda pos: -pos[1]) return list(map(lambda p: p[0], players))
def optimize_lineups( self, lineups: List[Lineup], max_exposure: Optional[float] = None, randomness: bool = False, with_injured: bool = None, exposure_strategy: Type[BaseExposureStrategy] = TotalExposureStrategy ): if with_injured is not None: show_deprecation_warning('with_injured parameter is deprecated, use player_pool.with_injured instead') self.player_pool.with_injured = with_injured players = self.player_pool.filtered_players context = OptimizationContext( total_lineups=len(lineups), players=players, existed_lineups=lineups, max_exposure=max_exposure, randomness=randomness, exposure_strategy=exposure_strategy ) rules = self._rules.copy() rules.update(self.settings.extra_rules) if randomness: show_deprecation_warning('Randomness parameter is deprecated and will be removed in 3.6, ' 'use set_fantasy_points_strategy instead') self.set_fantasy_points_strategy(RandomFantasyPointsStrategy(self._min_deviation, self._max_deviation)) rules.add(Objective) rules.add(LateSwapRule) rules.remove(PositionsRule) base_solver = self._solver_class() base_solver.setup_solver() players_dict = OrderedDict( [(player, base_solver.add_variable(base_solver.build_player_var_name(player, str(i)))) for i, player in enumerate(players)]) variables_dict = {v: k for k, v in players_dict.items()} constraints = [constraint(self, players_dict, context) for constraint in rules] for constraint in constraints: constraint.apply(base_solver) previous_lineup = None for lineup in lineups: if len(lineup.get_unswappable_players()) == self.total_players: yield lineup continue solver = base_solver.copy() # type: Solver for constraint in constraints: constraint.apply_for_iteration(solver, previous_lineup) try: solved_variables = solver.solve() unswappable_players = lineup.get_unswappable_players() lineup_players = [] variables_names = [] for solved_variable in solved_variables: player = variables_dict.get(solved_variable) if player: lineup_players.append(player) variables_names.append(solved_variable.name) generated_lineup = self._build_lineup(lineup_players, context, unswappable_players) previous_lineup = generated_lineup context.add_lineup(generated_lineup) yield generated_lineup for constraint in constraints: constraint.post_optimize(variables_names) except SolverInfeasibleSolutionException as solver_exception: raise GenerateLineupException(solver_exception.get_user_defined_constraints()) self.last_context = context
def optimize( self, n: int, max_exposure: Optional[float] = None, randomness: bool = False, with_injured: Optional[bool] = None, exposure_strategy: Type[BaseExposureStrategy] = TotalExposureStrategy, exclude_lineups: Optional[Iterable[Lineup]] = None, ) -> Generator[Lineup, None, None]: start = time.time() if with_injured is not None: show_deprecation_warning('with_injured parameter is deprecated, use player_pool.with_injured instead') self.player_pool.with_injured = with_injured players = self.player_pool.filtered_players context = OptimizationContext( total_lineups=n, players=players, max_exposure=max_exposure, randomness=randomness, exposure_strategy=exposure_strategy, exclude_lineups=exclude_lineups or [], ) rules = self._rules.copy() rules.update(self.settings.extra_rules) if randomness: show_deprecation_warning('Randomness parameter is deprecated and will be removed in 3.6, ' 'use set_fantasy_points_strategy instead') self.set_fantasy_points_strategy(RandomFantasyPointsStrategy(self._min_deviation, self._max_deviation)) rules.add(Objective) base_solver = self._solver_class() base_solver.setup_solver() players_dict = OrderedDict( [(player, base_solver.add_variable(base_solver.build_player_var_name(player, str(i)))) for i, player in enumerate(players)]) variables_dict = {v: k for k, v in players_dict.items()} constraints = [constraint(self, players_dict, context) for constraint in rules] for constraint in constraints: constraint.apply(base_solver) previous_lineup = None print(f'setup took {time.time() - start}s') for i in range(n): iter_start = time.time() solver = base_solver.copy() # type: Solver for constraint in constraints: constraint.apply_for_iteration(solver, previous_lineup) try: sub_iter_start = time.time() solved_variables = solver.solve() print(f'\tsolving took {time.time() - sub_iter_start}s') sub_iter_start = time.time() lineup_players = [] variables_names = [] for solved_variable in solved_variables: player = variables_dict.get(solved_variable) if player: lineup_players.append(player) variables_names.append(solved_variable.name) lineup = self._build_lineup(lineup_players, context) previous_lineup = lineup context.add_lineup(lineup) yield lineup total_players = self.player_pool.total_players if total_players and len(self.player_pool.locked_players) == total_players: return for constraint in constraints: constraint.post_optimize(variables_names) print(f'iteration {i+1} took {time.time() - iter_start}s') except SolverInfeasibleSolutionException as solver_exception: raise GenerateLineupException(solver_exception.get_user_defined_constraints()) self.last_context = context
def remove_player_from_lineup(self, player: Player): show_deprecation_warning('remove_player_from_lineup will be removed in version 3.7, ' 'use player_pool.unlock_player instead') self.player_pool.unlock_player(player)
def add_player_to_lineup(self, player: Player): show_deprecation_warning('add_player_to_lineup will be removed in version 3.7, ' 'use player_pool.lock_player instead') self.player_pool.lock_player(player)
def players(self) -> List[Player]: show_deprecation_warning('players will be removed in version 3.7, ' 'use player_pool.filtered_players instead') return self.player_pool.filtered_players
def remaining_players(self) -> int: show_deprecation_warning('remaining_players will be removed in version 3.7, ' 'use player_pool.remaining_players instead') return self.player_pool.remaining_players
def restore_player(self, player: Player): show_deprecation_warning('restore_player will be removed in version 3.7, use player_pool.restore_player instead') self.player_pool.restore_player(player)
def extend_players(self, players: List[Player]): show_deprecation_warning('extend_players will be removed in version 3.7, use player_pool.extend_players instead') self.player_pool.extend_players(players)
def reset_lineup(self): show_deprecation_warning('reset_lineup will be removed in version 3.7, use player_pool.reset_locked instead') self.player_pool.reset_locked()
def games(self) -> FrozenSet[GameInfo]: show_deprecation_warning('games will be removed in version 3.7, use player_pool.games instead') return self.player_pool.games
def locked_players(self) -> List[Player]: show_deprecation_warning('locked_players will be removed in version 3.7, use player_pool.locked_players instead') return self.player_pool.locked_players
def total_players(self) -> int: show_deprecation_warning('total_players will be removed in version 3.7, use player_pool.total_players instead') return self.player_pool.total_players
def remaining_budget(self) -> Optional[float]: show_deprecation_warning('remaining_budget will be removed in version 3.7, ' 'use player_pool.remaining_budget instead') return self.player_pool.remaining_budget
def get_player_by_name(self, name: str) -> Optional[Player]: show_deprecation_warning('get_player_by_name will be removed in version 3.7, ' 'use player_pool.get_player_by_name instead') return self.player_pool.get_player_by_name(name)
def available_positions(self) -> FrozenSet[str]: show_deprecation_warning('available_positions will be removed in version 3.7, ' 'use player_pool.available_positions instead') return self.player_pool.available_positions
def get_player_by_id(self, player_id: str) -> Optional[Player]: show_deprecation_warning('get_player_by_id will be removed in version 3.7, ' 'use player_pool.get_player_by_id instead') return self.player_pool.get_player_by_id(player_id)