def make_new_squad_iter( gw_range, tag, budget=1000, season=CURRENT_SEASON, num_iterations=100, update_func_and_args=None, verbose=False, bench_boost_gw=None, triple_captain_gw=None, **kwargs, ): """ Make a squad from scratch, i.e. for gameweek 1, or for wildcard, or free hit, by selecting high scoring players and then iteratively replacing them with cheaper options until we have a valid squad. """ transfer_gw = min(gw_range) # the gw we're making the new squad best_score = 0.0 best_squad = None for iteration in range(num_iterations): if verbose: print("Choosing new squad: iteration {}".format(iteration)) if update_func_and_args: # call function to update progress bar. # this was passed as a tuple (func, increment, pid) update_func_and_args[0](update_func_and_args[1], update_func_and_args[2]) predicted_points = {} t = Squad(budget, season=season) # first iteration - fill up from the front for pos in positions: predicted_points[pos] = get_predicted_points(gameweek=gw_range, position=pos, tag=tag, season=season) for pp in predicted_points[pos]: t.add_player(pp[0], gameweek=transfer_gw) if t.num_position[pos] == TOTAL_PER_POSITION[pos]: break # presumably we didn't get a complete squad now excluded_player_ids = [] while not t.is_complete(): # randomly swap out a player and replace with a cheaper one in the # same position player_to_remove = t.players[random.randint(0, len(t.players) - 1)] remove_cost = player_to_remove.purchase_price t.remove_player(player_to_remove.player_id, gameweek=transfer_gw) excluded_player_ids.append(player_to_remove.player_id) for pp in predicted_points[player_to_remove.position]: if (pp[0] not in excluded_player_ids or random.random() < 0.3): # some chance to put player back cp = CandidatePlayer(pp[0], gameweek=transfer_gw, season=season) if cp.purchase_price >= remove_cost: continue else: t.add_player(pp[0], gameweek=transfer_gw) # now try again to fill up the rest of the squad for pos in positions: num_missing = TOTAL_PER_POSITION[pos] - t.num_position[pos] if num_missing == 0: continue for pp in predicted_points[pos]: if pp[0] in excluded_player_ids: continue t.add_player(pp[0], gameweek=transfer_gw) if t.num_position[pos] == TOTAL_PER_POSITION[pos]: break # we have a complete squad score = 0.0 for gw in gw_range: if gw == bench_boost_gw: score += t.get_expected_points( gw, tag, bench_boost=True) * get_discount_factor( gw_range[0], gw) elif gw == triple_captain_gw: score += t.get_expected_points( gw, tag, triple_captain=True) * get_discount_factor( gw_range[0], gw) else: score += t.get_expected_points(gw, tag) * get_discount_factor( gw_range[0], gw) if score > best_score: best_score = score best_squad = t if verbose: print("====================================\n") print(best_squad) print(best_score) return best_squad
def make_optimum_double_transfer( squad, tag, gameweek_range=None, season=CURRENT_SEASON, update_func_and_args=None, verbose=False, bench_boost_gw=None, triple_captain_gw=None, ): """ If we want to just make two transfers, it's not unfeasible to try all possibilities in turn. We will order the list of potential subs via the sum of expected points over a specified range of gameweeks. """ if not gameweek_range: gameweek_range = [NEXT_GAMEWEEK] transfer_gw = min(gameweek_range) # the week we're making the transfer best_score = 0.0 best_pid_out, best_pid_in = 0, 0 ordered_player_lists = {} for pos in ["GK", "DEF", "MID", "FWD"]: ordered_player_lists[pos] = get_predicted_points( gameweek=gameweek_range, position=pos, tag=tag) for i in range(len(squad.players) - 1): positions_needed = [] pout_1 = squad.players[i] new_squad_remove_1 = fastcopy(squad) new_squad_remove_1.remove_player(pout_1.player_id, season=season, gameweek=transfer_gw) for j in range(i + 1, len(squad.players)): if update_func_and_args: ## call function to update progress bar. ## this was passed as a tuple (func, increment, pid) update_func_and_args[0](update_func_and_args[1], update_func_and_args[2]) pout_2 = squad.players[j] new_squad_remove_2 = fastcopy(new_squad_remove_1) new_squad_remove_2.remove_player(pout_2.player_id, season=season, gameweek=transfer_gw) if verbose: print("Removing players {} {}".format(i, j)) ## what positions do we need to fill? positions_needed = [pout_1.position, pout_2.position] # now loop over lists of players and add players back in for pin_1 in ordered_player_lists[positions_needed[0]]: if (pin_1[0].player_id == pout_1.player_id or pin_1[0].player_id == pout_2.player_id): continue ## no point in adding same player back in new_squad_add_1 = fastcopy(new_squad_remove_2) added_1_ok = new_squad_add_1.add_player(pin_1[0], season=season, gameweek=transfer_gw) if not added_1_ok: continue for pin_2 in ordered_player_lists[positions_needed[1]]: new_squad_add_2 = fastcopy(new_squad_add_1) if (pin_2[0] == pin_1[0] or pin_2[0].player_id == pout_1.player_id or pin_2[0].player_id == pout_2.player_id): continue ## no point in adding same player back in added_2_ok = new_squad_add_2.add_player( pin_2[0], season=season, gameweek=transfer_gw) if added_2_ok: # calculate the score total_points = 0.0 for gw in gameweek_range: if gw == bench_boost_gw: total_points += new_squad_add_2.get_expected_points( gw, tag, bench_boost=True) elif gw == triple_captain_gw: total_points += new_squad_add_2.get_expected_points( gw, tag, triple_captain=True) else: total_points += new_squad_add_2.get_expected_points( gw, tag) if total_points > best_score: best_score = total_points best_pid_out = [pout_1.player_id, pout_2.player_id] best_pid_in = [ pin_1[0].player_id, pin_2[0].player_id ] best_squad = new_squad_add_2 break return best_squad, best_pid_out, best_pid_in
def make_random_transfers( squad, tag, nsubs=1, gw_range=None, num_iter=1, update_func_and_args=None, season=CURRENT_SEASON, bench_boost_gw=None, triple_captain_gw=None, ): """ choose nsubs random players to sub out, and then select players using a triangular PDF to preferentially select the replacements with the best expected score to fill their place. Do this num_iter times and choose the best total score over gw_range gameweeks. """ best_score = 0.0 best_squad = None best_pid_out = [] best_pid_in = [] max_tries = 100 for i in range(num_iter): if update_func_and_args: ## call function to update progress bar. ## this was passed as a tuple (func, increment, pid) update_func_and_args[0](update_func_and_args[1], update_func_and_args[2]) new_squad = fastcopy(squad) if not gw_range: gw_range = [NEXT_GAMEWEEK] transfer_gw = min(gw_range) # the week we're making the transfer players_to_remove = [] # this is the index within the squad removed_players = [] # this is the player_ids ## order the players in the squad by predicted_points - least-to-most player_list = [] for p in squad.players: p.calc_predicted_points(tag) player_list.append( (p.player_id, p.predicted_points[tag][gw_range[0]])) player_list.sort(key=itemgetter(1), reverse=False) while len(players_to_remove) < nsubs: index = int(random.triangular(0, len(player_list), 0)) if not index in players_to_remove: players_to_remove.append(index) positions_needed = [] for p in players_to_remove: positions_needed.append(squad.players[p].position) removed_players.append(squad.players[p].player_id) new_squad.remove_player(removed_players[-1], season=season, gameweek=transfer_gw) budget = new_squad.budget predicted_points = {} for pos in set(positions_needed): predicted_points[pos] = get_predicted_points(position=pos, gameweek=gw_range, tag=tag) complete_squad = False added_players = [] attempt = 0 while not complete_squad: ## sample with a triangular PDF - preferentially select players near ## the start added_players = [] for pos in positions_needed: index = int(random.triangular(0, len(predicted_points[pos]), 0)) pid_to_add = predicted_points[pos][index][0] added_ok = new_squad.add_player(pid_to_add, season=season, gameweek=transfer_gw) if added_ok: added_players.append(pid_to_add) complete_squad = new_squad.is_complete() if not complete_squad: # try to avoid getting stuck in a loop attempt += 1 if attempt > max_tries: new_squad = fastcopy(squad) break # take those players out again. for ap in added_players: removed_ok = new_squad.remove_player(ap.player_id, season=season, gameweek=transfer_gw) if not removed_ok: print("Problem removing {}".format(ap.name)) added_players = [] ## calculate the score total_points = 0.0 for gw in gw_range: if gw == bench_boost_gw: total_points += new_squad.get_expected_points(gw, tag, bench_boost=True) elif gw == triple_captain_gw: total_points += new_squad.get_expected_points( gw, tag, triple_captain=True) else: total_points += new_squad.get_expected_points(gw, tag) if total_points > best_score: best_score = total_points best_pid_out = removed_players best_pid_in = [ap.player_id for ap in added_players] best_squad = new_squad ## end of loop over n_iter return best_squad, best_pid_out, best_pid_in
def make_optimum_transfer( squad, tag, gameweek_range=None, season=CURRENT_SEASON, update_func_and_args=None, bench_boost_gw=None, triple_captain_gw=None, ): """ If we want to just make one transfer, it's not unfeasible to try all possibilities in turn. We will order the list of potential transfers via the sum of expected points over a specified range of gameweeks. """ if not gameweek_range: gameweek_range = [NEXT_GAMEWEEK] transfer_gw = min(gameweek_range) # the week we're making the transfer best_score = 0.0 best_pid_out, best_pid_in = 0, 0 ordered_player_lists = {} for pos in ["GK", "DEF", "MID", "FWD"]: ordered_player_lists[pos] = get_predicted_points( gameweek=gameweek_range, position=pos, tag=tag) for p_out in squad.players: if update_func_and_args: ## call function to update progress bar. ## this was passed as a tuple (func, increment, pid) update_func_and_args[0](update_func_and_args[1], update_func_and_args[2]) new_squad = fastcopy(squad) position = p_out.position new_squad.remove_player(p_out.player_id, season=season, gameweek=transfer_gw) for p_in in ordered_player_lists[position]: if p_in[0].player_id == p_out.player_id: continue # no point in adding the same player back in added_ok = new_squad.add_player(p_in[0], season=season, gameweek=transfer_gw) if added_ok: break total_points = 0.0 for gw in gameweek_range: if gw == bench_boost_gw: total_points += new_squad.get_expected_points(gw, tag, bench_boost=True) elif gw == triple_captain_gw: total_points += new_squad.get_expected_points( gw, tag, triple_captain=True) else: total_points += new_squad.get_expected_points(gw, tag) if total_points > best_score: best_score = total_points best_pid_out = p_out.player_id best_pid_in = p_in[0].player_id best_squad = new_squad return best_squad, [best_pid_out], [best_pid_in]