Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1v1 experiment code #31

Merged
merged 8 commits into from
Jun 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,5 @@ venv-pokemon/
# showdown
pokemon-showdown/

# Outputs
# Outputs
outputs/*

3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
[submodule "showdown"]
path = showdown
url = [email protected]:phinate/showdown.git
[submodule "poke-env"]
path = poke-env
url = [email protected]:AoifeHughes/poke-env.git
File renamed without changes.
Empty file added poke_stats/__init__.py
Empty file.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import os
import pickle
import re

# Directory path where the files are located
directory = "/Users/lfrance/OneDrive - The Alan Turing Institute/002_Projects/Pokemon/poke-images/pokesprite/pokemon-gen8/regular"
Expand All @@ -25,4 +26,4 @@
if pokemon_name not in pokemon_names:
# Delete the file
os.remove(file_path)
print(f"Deleted file: {filename}")
print(f"Deleted file: {filename}")
166 changes: 166 additions & 0 deletions poke_stats/poke_1v1_fighter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# 1v1 fights for the pokemon for stats.
# Author: Edmund Dable-Heath
"""
Setting each of the 150 pokemon to fight each other pokemon until either a cutoff is
reached or the variation of the win ratio over a history of s fights falls below a
threshold.
"""

# Imports include reference to potential scripts
# import pop_gen
# import fight_sim
from __future__ import annotations

import asyncio
import pickle
from itertools import combinations_with_replacement as cwr
from pathlib import Path
from typing import TYPE_CHECKING

import numpy as np
from poke_env import PlayerConfiguration
from poke_env.player import SimpleHeuristicsPlayer
from run import generate_gen_1_teams, import_pool, run_battles

from p2lab.gen_data import gen_1_pokemon

if TYPE_CHECKING:
from p2lab.team import Team

# Actual code ==========================================================================


def gen_pop() -> list[Team]:
"""Generate the population of 151 pokemon objects ready to fight.

NB: This can be done more explicity here, i.e. implement the rejection sampling
in this script, but I will simplify away from that for now.
"""
pool = import_pool(team_string=gen_1_pokemon())
return generate_gen_1_teams(pool)


async def duel(poke_1, poke_2, player_1, player_2) -> bool:
"""Simulate a fight between a pair of pokemon, with a result of True if poke_1
wins.

Args:
poke_1 (poke_object): pokemon_1 (IN THE RED CORNER)
poke_2 (poke_object): pokemon_2 (IN THE BLUE CORNER)

Returns:
bool: True if pokemon 1 is victorious.
"""
return await run_battles([[0, 1]], [poke_1, poke_2], player_1, player_2, 1)


async def duel_to_convergence(
poke_1,
poke_2,
p1,
p2,
cutoff: int,
) -> tuple(float, float):
"""DUEL TO THE DEATH! (or at least a converged win ratio.....)

For two pokemon, duel until the win ration converges or cutoff is reached.
Return ratios scaled by number of fights.

TODO: make lookback function of number of fights?

Args:
poke_1 (poke_object): pokemon_1 (GLADIATOR, READY!)
poke_2 (poke_object): pokemon_2 (GLADIATOR, READY!)
var_threshold (float): threshold for convergence of win ratio variance.
look_back: how man previous ratio values to consider.
cutoff: max iters to run this.

Returns:
(poke_wins_1, poke_wins_2) tuple(float, float):
poke_wins_i = (no wins of poke_i) / (no of duels) f
"""
count = 0
poke_win_1 = 0
poke_win_2 = 0
while count < cutoff:
count += 1
res = await duel(poke_1, poke_2, p1, p2)
if bool(res[0][0]):
poke_win_1 += 1
else:
poke_win_2 += 1
return poke_win_1 / count, poke_win_2 / count


async def main(**kwargs):
# Generate a population
pokemons = gen_pop()
poke_num = len(pokemons)

# Read the poke_dict for results
with Path.open("poke_base_stats.pkl", "rb") as f:
poke_dict = pickle.load(f)

conversion_dict = {
"mr-mime": "mr. mime",
"farfetchd": "farfetch'd",
"nidoran-m": "nidoran♂",
"nidoran-f": "nidoran♀",
}
# flip the dict
conversion_dict = {v: k for k, v in conversion_dict.items()}
poke_names = []
for poke in pokemons:
if poke.first_name.lower() in conversion_dict:
print("sgewrojoiwjhgnwil")
poke_names.append(conversion_dict[poke.first_name.lower()])
else:
poke_names.append(poke.first_name.lower())

# print(poke_names)
# print(poke_dict.keys())
assert set(poke_names) == set(poke_dict.keys())

# Instantiate results matrix (we know n = 151)
res_arr = np.zeros((poke_num, poke_num))

# Instantiate players
player_1 = SimpleHeuristicsPlayer(
PlayerConfiguration("Player 1", None), battle_format="gen7anythinggoes"
)
player_2 = SimpleHeuristicsPlayer(
PlayerConfiguration("Player 2", None), battle_format="gen7anythinggoes"
)
# Duel to convergence to get stats
for dueling_partners_id in cwr(list(range(len(pokemons))), 2):
i, j = dueling_partners_id
# print(f"IN THE RED CORNER: {poke_names[i]}")
# print(f"IN THE BLUE CORNER: {poke_names[j]}")
poke_ratio_1, poke_ratio_2 = await duel_to_convergence(
pokemons[i],
pokemons[j],
player_1,
player_2,
kwargs["cutoff"],
)
if i == j:
res_arr[i, i] += poke_ratio_1
res_arr[i, j] += poke_ratio_1
res_arr[j, i] += poke_ratio_2

# Average over to get stats
avg_win_ratio = np.mean(res_arr, axis=0)
for i in range(len(poke_names)):
poke_dict[poke_names[i]]["average_win_ratio"] = avg_win_ratio[i]

# Write poke dict to storage
with Path.open("poke_fight_results.pkl", "wb") as fp:
pickle.dump(poke_dict, fp)
return poke_dict


if __name__ == "__main__":
# Pars hardcoded in for now as should be single run.
pars = {"cutoff": 10}

asyncio.get_event_loop().run_until_complete(main(**pars))
Binary file not shown.
Binary file added poke_stats/poke_fight_results.pkl
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
},
{
"cell_type": "code",
"execution_count": 107,
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -30,7 +30,7 @@
},
{
"cell_type": "code",
"execution_count": 108,
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
Expand Down Expand Up @@ -65,7 +65,7 @@
},
{
"cell_type": "code",
"execution_count": 109,
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -77,26 +77,26 @@
},
{
"cell_type": "code",
"execution_count": 110,
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'tier': 'D',\n",
" 'type': ['Normal', 'Flying'],\n",
" 'stats': {'hp': 52, 'atk': 65, 'def': 55, 'spa': 58, 'spd': 58, 'spe': 60},\n",
" 'base_stat_total': 348}"
"{'tier': 'F',\n",
" 'type': ['Bug', 'Poison'],\n",
" 'stats': {'hp': 40, 'atk': 35, 'def': 30, 'spa': 20, 'spd': 20, 'spe': 50},\n",
" 'base_stat_total': 195}"
]
},
"execution_count": 110,
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Test with the obligatory snorlax\n",
"poke_dict[\"farfetchd\"]"
"poke_dict[\"weedle\"]"
]
},
{
Expand Down
27 changes: 15 additions & 12 deletions src/p2lab/poke_stats/poke_stats.py → poke_stats/poke_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@
},
},
{
"name": "Mr. Mime",
"name": "Mr-Mime",
"hp": 40,
"atk": 45,
"def": 65,
Expand Down Expand Up @@ -2799,7 +2799,7 @@
},
},
{
"name": "Farfetch'd",
"name": "Farfetchd",
"hp": 52,
"atk": 65,
"def": 55,
Expand Down Expand Up @@ -3182,9 +3182,21 @@

poke_stats = {}

format_to_tier = {
"Uber": "S",
"OU": "A",
"UUBL": "B+",
"UU": "B",
"NUBL": "C+",
"NU": "C",
"PU": "D",
"NFE": "E",
"LC": "F",
}

for d in list_of_poke_dicts:
poke_stats[d["name"].lower()] = {
"tier": d["formats"],
"tier": format_to_tier[d["formats"][0]],
"type": d["types"],
"stats": {
"hp": d["hp"],
Expand All @@ -3195,18 +3207,9 @@
"spe": d["spe"],
},
}
# print(f'some poke_stats {poke_stats}')
# print(poke_stats[d['name'].lower()])
poke_stats[d["name"].lower()]["base_stat_total"] = sum(
poke_stats[d["name"].lower()]["stats"].values()
)

# poke_choice = input("Which pokemon you wanna know about?")

# print(type(poke_choice))

# print(f"stats for {str(poke_choice)}: {poke_stats[str(poke_choice)]}")

with open("poke_base_stats.pkl", "wb") as fp:
pickle.dump(poke_stats, fp)

6 changes: 4 additions & 2 deletions run.py → poke_stats/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,9 @@ async def run_battles(
player_2.reset_battles()
return np.array(results)


def generate_gen_1_teams(pool):
return [Team([pkmn]) for pkmn in pool]
return [Team([pkmn]) for pkmn in pool]


async def main(
Expand All @@ -131,12 +132,13 @@ async def main(
# pool = generate_pool(pool_size, export=True)
# new_pool = import_pool(filename="pool.txt")
pool = import_pool(team_string=gen_1_pokemon())
print(f"pool: {pool}")
# print(f"pool: {pool}")
print(f"pool shape: {pool.shape}")
# print(f"new pool: {new_pool}")
# print(f"new pool shape: {new_pool.shape}")
# teams = generate_teams(pool, num_teams=num_teams, team_size=team_size)
teams = generate_gen_1_teams(pool)
print(teams[0].pokemon)
matches = dense(teams)
print(f"matches: {matches}")
print(f"matches shape: {matches.shape}")
Expand Down
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
8 changes: 8 additions & 0 deletions pool.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Bronzong @ Light Clay
Ability: Levitate
Level: 84
EVs: 85 HP / 85 Atk / 85 Def / 85 SpA / 85 SpD / 85 Spe
- Light Screen
- Reflect
- Toxic
- Iron Head
Loading