[1]
import pandas as pd
import numpy as np
import pulp
import math
import toolz as tz
from typing import List, Callable, Dict
[2]
def assign_split_col(df: pd.DataFrame, col: str, name_list: List[str], pat: str = None):
    df = df.copy()
    split_col = df[col].str.split(pat, expand=True)

    return df.assign(
        **dict(
            zip(name_list, [split_col.iloc[:, x] for x in range(split_col.shape[1])])
        )
    )


def create_position_constraint(
    df: pd.DataFrame,
    inlusion_dct: Dict[str, pulp.pulp.LpVariable],
    position: str,
    constraint: Callable,
) -> pulp.pulp.LpConstraint:

    pulp_sum = pulp.lpSum(
        tz.dicttoolz.keyfilter(
            lambda x: x in df.query(f"position == '{position}'")["name"].to_list(),
            inlusion_dct,
        )
    )
    return constraint(pulp_sum)


# create_position_constraint(edited, include, "QB", lambda x: x==3)


def create_flexible_position_constraint(
    df: pd.DataFrame,
    inlusion_dct: Dict[str, pulp.pulp.LpVariable],
    positions: List[str],
    constraint: Callable,
) -> pulp.pulp.LpConstraint:

    pulp_sum = pulp.lpSum(
        tz.dicttoolz.keyfilter(
            lambda x: x
            in df.loc[lambda y: y["position"].isin(positions), "name"].to_list(),
            inlusion_dct,
        )
    )
    return constraint(pulp_sum)


# create_flexible_position_constraint(edited, include,
#                                    ['RB', 'WR', 'TE'], lambda x: x==3)


def get_total_for_players(
    df: pd.DataFrame,
    inlusion_dct: Dict[str, pulp.pulp.LpVariable],
    col: str,
    multiplier: float = 1,
) -> pulp.pulp.LpAffineExpression:

    players = df["name"].to_list()

    ser = df.set_index("name")[col]

    return pulp.lpSum(
        [inlusion_dct[player] * ser[player] * multiplier for player in players]
    )


# get_total_for_players(edited, include, "salary")
# get_total_for_players(edited, ImTheCaptainNow, "salary", 1.5)


def nfl_single_game(df: pd.DataFrame, salary: int, best_value: int) -> List[str]:
    players = df["name"].to_list()
    include = pulp.LpVariable.dict(
        "include", [player for player in players], lowBound=0, upBound=1, cat="Integer"
    )

    ImTheCaptainNow = pulp.LpVariable.dict(
        "ImTheCaptainNow",
        [player for player in players],
        lowBound=0,
        upBound=1,
        cat="Integer",
    )

    prob = pulp.LpProblem("optimal_lineup", pulp.LpMaximize)

    prob += pulp.lpSum(
        get_total_for_players(df, include, "FPPG")
        + get_total_for_players(df, ImTheCaptainNow, "FPPG", 1.5)
    )

    prob += pulp.lpSum([include[player] for player in players]) == 4

    prob += pulp.lpSum([ImTheCaptainNow[player] for player in players]) == 1

    for player in players:
        prob += pulp.lpSum(include[player] + ImTheCaptainNow[player]) <= 1.0

    best_value = 1000.0

    prob += (
        pulp.lpSum(
            get_total_for_players(df, include, "salary")
            + get_total_for_players(df, ImTheCaptainNow, "salary")
        )
        <= salary
    )
    prob += (
        pulp.lpSum(
            get_total_for_players(df, include, "FPPG")
            + get_total_for_players(df, ImTheCaptainNow, "FPPG", 1.5)
        )
        <= best_value
    )

    prob.solve()

    return list(
        tz.itertoolz.concat(
            [
                tz.dicttoolz.itemfilter(
                    lambda item: item[1].varValue == 1, ImTheCaptainNow
                ).keys(),
                tz.dicttoolz.itemfilter(
                    lambda item: item[1].varValue == 1, include
                ).keys(),
            ]
        )
    )
[3]
filename ="FanDuel-NFL-2020-02-02-42874-players-list.csv"
df = pd.read_csv(filename)
[4]
edited = (
    df.loc[lambda x: x["Injury Indicator"].isna()]
    .pipe(assign_split_col, "Id", ["slate_id", "player_id"], pat="-")
    .assign(name=lambda x: x["First Name"] + " " + x["Last Name"])
    .rename(columns={"Position": "position", "Salary": "salary"})
    .loc[:, ["slate_id", "player_id", "salary", "position", "name", "FPPG"]]
)
[5]
lineups = [nfl_single_game(edited, 60000, 1000) for _ in range(5)]
lineups
[['Patrick Mahomes',
  'Jimmy Garoppolo',
  'Travis Kelce',
  'Tyreek Hill',
  'C.J. Beathard'],
 ['Patrick Mahomes',
  'Jimmy Garoppolo',
  'Travis Kelce',
  'Tyreek Hill',
  'C.J. Beathard'],
 ['Patrick Mahomes',
  'Jimmy Garoppolo',
  'Travis Kelce',
  'Tyreek Hill',
  'C.J. Beathard'],
 ['Patrick Mahomes',
  'Jimmy Garoppolo',
  'Travis Kelce',
  'Tyreek Hill',
  'C.J. Beathard'],
 ['Patrick Mahomes',
  'Jimmy Garoppolo',
  'Travis Kelce',
  'Tyreek Hill',
  'C.J. Beathard']]
[6]
edited.set_index("name").loc[lineups[0], "FPPG"].sum()
79.66350218454997
[7]
edited.set_index("name").loc[lineups[0], "salary"].sum()
59500
[8]
lineups = [nfl_single_game(edited, 60000, 1000) for _ in range(150)]
[9]
#Checking to see if they're all the same
scores = [edited.set_index("name").loc[lineup, "FPPG"].sum() for lineup in lineups]
[10]
set(scores)
{79.66350218454997}
[ ]