# -*- coding: utf-8 -*-
"""Pokemon_Unova

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1K9Hys_QjJ-0PWv8G-uQBmfyoAz6zo_Qg
"""

# Commented out IPython magic to ensure Python compatibility.
# %pip install conda
# %pip install pulp
import numpy as np
import pandas as pd
from google.colab import files
from pulp import *
uploaded = files.upload()



poke_df = pd.read_csv("Pokemon.csv")

poke_df = poke_df.rename(columns={"#": "No"})
poke_df.head()

unova = list(range(494,649))

unova = list(range(494,649))
genV_dex = unova

unova_df = poke_df[poke_df.No.isin(genV_dex)]

unova_dex = unova_df.drop_duplicates(subset=['No'])
unova_dex

unova_dex = unova_dex[unova_dex.Legendary == False]
unova_dex
unova_dex = unova_dex.rename(columns={'Type 1':'Type1','Type 2': 'Type2'})
unova_dex

typeChart = pd.read_csv("Pokemon Type Chart.csv", index_col = [0])
typeChart

types = ['Water', 'Normal', 'Bug', 'Electric', 'Ground', 'Flying',
         'Ice', 'Dragon', 'Ghost', 'Dark', 'Psychic', 'Fighting']
gymEliteFour = typeChart[[c for c in typeChart.columns if c in types]]
gymEliteFour

strengths = []
numbers = []
names = []
totalStats = []
i = 0
for row in unova_dex.itertuples(index=True, name='Pandas'):
    numbers.append(row.No)
    names.append(row.Name)
    
    # Check what types the Pokemon is strong against
    strengths.append([1 if s >= 2.0 else 0 for s in list(gymEliteFour.loc[row.Type1])])
    totalStats.append(row.Total)
    
    # Accounting for any secondary typings, and adding onto any advantages conferred
    try:
        strengths[i] = list(np.add(strengths[i], [1 if s >= 2.0 else 0 for s in list(gymEliteFour.loc[row.Type2])]))
        
    except:
        KeyError
        
    i += 1
    
# Equals 1 if the Pokemon is strong against the type indicated; 0 otherwise --> 145 by 13 matrix
advantage = [[1 if r >= 1 else 0 for r in strengths[i]] for i in range(145)]

# Create the set of starter Pokemon
starterNames = ['Snivy', 'Servine', 'Serperior',
                'Tepig', 'Pignite', 'Emboar',
                'Oshawott','Dewott', 'Samurott']

starterIndices = []
for pkmn in starterNames:
    starterIndices.append(names.index(pkmn))

# This initializes the model with the name and whether we want to maximize or minimize our objective function
best_team = LpProblem("Optimal_Pokemon_Team", LpMaximize)

# Define a binary variable for Pokemon
P = LpVariable.dicts("P", range(145), cat=LpBinary) # we have 145 Pokemon to consider

# Define the objective function to maximize
best_team += lpSum([totalStats[pkmn] * P[pkmn] for pkmn in range(145)])

# Constraint that we need 6 Pokemon on the team
best_team += lpSum([P[pkmn] for pkmn in range(145)]) == 6

# Constraint that we need 1 starter Pokemon
best_team += lpSum([P[pkmn] for pkmn in starterIndices]) == 1

# Constraint that we should have a Pokemon strong against at least one of the gym leaders/Elite Four
for i in range(12):
    best_team += lpSum([advantage[pkmn][i] * P[pkmn] for pkmn in range(145)]) >= 1

# Solve the optimization problem under the given constraints
best_team.solve()

for i in range(145):
    if P[i].value() == 1:
        print(names[i])

mythicalandlategameNames = ['KeldeoOrdinary Forme', 'MeloettaAria Forme', 'Volcarona','Victini', 'Larvesta', 'Hydreigon','Zweilous', 'Deino', 'Durant', 'Heatmor','Mandibuzz', 'Vullaby', 'Braviary', 'Rufflet', 'Bouffalant']

mythicalandlategameIndices = []
for pkmn in mythicalNames:
    mythicalandlategameIndices.append(names.index(pkmn))

# This initializes the model with the name and whether we want to maximize or minimize our objective function
best_team = LpProblem("Optimal_Pokemon_Team", LpMaximize)

# Define a binary variable for Pokemon
P = LpVariable.dicts("P", range(145), cat=LpBinary) # we have 145 Pokemon to consider

# Define the objective function to maximize
best_team += lpSum([totalStats[pkmn] * P[pkmn] for pkmn in range(145)])

# Constraint that we need 6 Pokemon on the team
best_team += lpSum([P[pkmn] for pkmn in range(145)]) == 6

# Constraint that we need 1 starter Pokemon
best_team += lpSum([P[pkmn] for pkmn in starterIndices]) == 1


best_team += lpSum([P[pkmn] for pkmn in mythicalIndices]) == 0

# Constraint that we should have a Pokemon strong against at least one of the gym leaders/Elite Four
for i in range(12):
    best_team += lpSum([advantage[pkmn][i] * P[pkmn] for pkmn in range(145)]) >= 1

best_team.solve()

for i in range(145):
    if P[i].value() == 1:
        print(names[i])

print(unova_dex)

# Indices of Oshawott and its evolved forms, Dewott and Samurott
OshawottIndices = [7, 8, 9]

# The other starters
notOshawottIndices = list(set(starterIndices) - set(OshawottIndices))

# This initializes the model with the name and whether we want to maximize or minimize our objective function
best_team = LpProblem("Optimal_Pokemon_Team", LpMaximize)

# Define a binary variable for Pokemon
P = LpVariable.dicts("P", range(145), cat=LpBinary) # we have 206 Pokemon to consider

# Define the objective function to maximize
best_team += lpSum([totalStats[pkmn] * P[pkmn] for pkmn in range(145)])

# Constraint that we need 6 Pokemon on the team
best_team += lpSum([P[pkmn] for pkmn in range(145)]) == 6

# Constraint that we must have the Oshawott family
best_team += lpSum([P[pkmn] for pkmn in OshawottIndices]) == 1

# Constraint that we can't have any other starters
best_team += lpSum([P[pkmn] for pkmn in notOshawottIndices]) == 0

# Constraint that we can't use mythical or late game pokemonm (8th gym or later)
best_team += lpSum([P[pkmn] for pkmn in mythicalandlategameIndices]) == 0

# Constraint that we should have some Pokemon strong against at least one of the gym leaders/Elite Four
for i in range(12):
    best_team += lpSum([advantage[pkmn][i] * P[pkmn] for pkmn in range(145)]) >= 1

best_team.solve()

for i in range(145):
    if P[i].value() == 1:
        print(names[i])

# Indices of Snivy and its evolved forms, Servine and Serperior
snivyIndices = [1, 2, 3]

# The other starters
notSnivyIndices = list(set(starterIndices) - set(snivyIndices))

# This initializes the model with the name and whether we want to maximize or minimize our objective function
best_team = LpProblem("Optimal_Pokemon_Team", LpMaximize)

# Define a binary variable for Pokemon
P = LpVariable.dicts("P", range(145), cat=LpBinary) # we have 145 Pokemon to consider

# Define the objective function to maximize
best_team += lpSum([totalStats[pkmn] * P[pkmn] for pkmn in range(145)])

# Constraint that we need 6 Pokemon on the team
best_team += lpSum([P[pkmn] for pkmn in range(145)]) == 6

# Constraint that we must have the Snivy family
best_team += lpSum([P[pkmn] for pkmn in snivyIndices]) == 1

# Constraint that we can't have any other starters
best_team += lpSum([P[pkmn] for pkmn in notSnivyIndices]) == 0

# Constraint that we can't use mythical or late game pokemonm (8th gym or later)
best_team += lpSum([P[pkmn] for pkmn in mythicalIndices]) == 0

# Constraint that some Pokemon should be strong against at least one of the gym leaders/Elite Four
for i in range(12):
    best_team += lpSum([advantage[pkmn][i] * P[pkmn] for pkmn in range(145)]) >= 1

best_team.solve()

for i in range(145):
    if P[i].value() == 1:
        print(names[i])





