Files
ppse/HW4/hw4.py
T

237 lines
10 KiB
Python

from core import Trainer
import random
import copy
import game_data as gd
import pickle
import matplotlib.pyplot as plt
import numpy as np
import os
#if the results folder does not exist, create it
if not os.path.exists('results'):
os.makedirs('results')
if not os.path.exists('plots'):
os.makedirs('plots')
def RandomBattle(trainer,cpu_trainer):
#print(f"You are in battle against {cpu_trainer.name}!")
battle_active = True
active_pokemon = trainer.get_active_pokemon()
cpu_active_pokemon = cpu_trainer.get_active_pokemon()
#print(f"Your active Pokemon is {active_pokemon.name} and the CPU's active Pokemon is {cpu_active_pokemon.name}.")
did_player_won = False
battle_turns_num = 0
player_hp_evolution = []
player_selected_moves = []
player_damage_done = []
cpu_hp_evolution = []
cpu_selected_moves = []
cpu_damage_done = []
while battle_active:
player_move_name = random.choice(active_pokemon.get_moves())
player_selected_moves.append(player_move_name)
#print(f"{active_pokemon.name} selected {player_move_name} to use against {cpu_active_pokemon.name}:\n")
try:
player_damage_done_value = active_pokemon.useMove(player_move_name,cpu_active_pokemon)
player_damage_done.append(player_damage_done_value)
player_hp_evolution.append(active_pokemon.get_current_hp())
cpu_hp_evolution.append(cpu_active_pokemon.get_current_hp())
battle_turns_num += 1
#check if the opponent has been defeated
if not cpu_trainer.active_pokemon_can_battle():
#print(f"{cpu_trainer.get_active_pokemon().name} has been defeated! You win!")
did_player_won = True
battle_active = False
break
#if the opponent has not been defeated, then its the CPU turn to play
cpu_active_pokemon_selected_move_name = random.choice(cpu_active_pokemon.get_moves())
#print(f"CPU's {cpu_active_pokemon.name} is using {cpu_active_pokemon_selected_move_name} against your {active_pokemon.name}!")
cpu_selected_moves.append(cpu_active_pokemon_selected_move_name)
cpu_damage_done_value = cpu_active_pokemon.useMove(cpu_active_pokemon_selected_move_name, active_pokemon)
cpu_damage_done.append(cpu_damage_done_value)
player_hp_evolution.append(active_pokemon.get_current_hp())
cpu_hp_evolution.append(cpu_active_pokemon.get_current_hp())
battle_turns_num += 1
#update the player pokemon list
trainer.update_pokemon_list(active_pokemon)
#check if the player has been defeated
if not trainer.active_pokemon_can_battle():
#print(f"Your {active_pokemon.name} has been defeated!")
if not trainer.can_battle():
#print("You have no more Pokemons that can battle! You lose!")
did_player_won=False
battle_active = False
break
else:
#print("You have other Pokemons that can battle!")
continue
except ValueError as e:
print(e)
#manage those cases for which the player wins in the first turn and the cpu does not play any turn
if len(player_damage_done) == 0:
player_damage_done = [0]
if len(cpu_damage_done) == 0:
cpu_damage_done = [0]
player_avg_damage_done = np.mean(player_damage_done) #average damage done per turn
cpu_avg_damage_done = np.mean(cpu_damage_done) #average damage done per turn
player_residual_hp_percent = trainer.get_active_pokemon().get_current_hp_percent()
player_history = {'player_hp_evolution':player_hp_evolution,
'player_selected_moves':player_selected_moves,
'player_damage_done':player_damage_done,
'player_avg_damage_done':player_avg_damage_done
}
cpu_history = {'cpu_hp_evolution':cpu_hp_evolution,
'cpu_selected_moves':cpu_selected_moves,
'cpu_damage_done':cpu_damage_done,
'cpu_avg_damage_done':cpu_avg_damage_done
}
turn_history = {'player_history':player_history,
'cpu_history':cpu_history
}
battle_results = {
'player_pokemon':trainer.get_active_pokemon(),
'encountered_pokemon':cpu_trainer.get_active_pokemon(),
'result':did_player_won,
'battle_turns_num':battle_turns_num,
'player_residual_hp_percent':player_residual_hp_percent,
'turn_history':turn_history
}
return battle_results
def Main(starter_choice,Nbattles):
try:
starter_name = starter_choice
trainer = Trainer(name='edo', starter_name=starter_name)
#print(f"{trainer.name} has chosen {trainer.starter} as their starter Pokemon!")
#print("Adding potions and pokeballs to your inventory...")
trainer.items = {"potions": 10, "pokeball": 10}
#print("Your character is ready!")
#print(f"Welcome {trainer.name}! Your adventure begins now!")
except ValueError as e:
print(e)
print("Something went wrong!")
game_active_flag = True
while game_active_flag:
all_battle_results = []
for i in range(0,Nbattles):
#print("You entered the Random Battle mode")
#print("Battle #",i)
cpu_trainer = Trainer(name='CPU',starter_name=gd.pokemons_df.index[random.randint(0,len(gd.pokemons_df.index)-1)],is_CPU=True)
battle_results = RandomBattle(trainer,cpu_trainer)
all_battle_results.append(battle_results)
heal_flag = 'yes'
if heal_flag == 'yes':
for pokemon in trainer.pokemon_list:
pokemon.curr_hp = pokemon.baseStats['hp']
#print("All your Pokemon have been healed!")
game_active_flag = False
#save all battle results
return all_battle_results
def make_plots(Ngames,Nbattles):
files_to_analyze = os.listdir('results/')
avg_damage_per_level = dict()
for file_name in files_to_analyze:
pickle_in = open(f"results/{file_name}",'rb')
all_battle_results = pickle.load(pickle_in)
pickle_in.close()
for battle_result in all_battle_results:
player_pokemon = battle_result['player_pokemon']
player_pokemon_name = player_pokemon.name
player_pokemon_level = player_pokemon.level
player_avg_damage_done = battle_result['turn_history']['player_history']['player_avg_damage_done']
if player_pokemon_name not in avg_damage_per_level:
avg_damage_per_level[player_pokemon_name] = {}
if player_pokemon_level not in avg_damage_per_level[player_pokemon_name]:
avg_damage_per_level[player_pokemon_name][player_pokemon_level] = []
avg_damage_per_level[player_pokemon_name][player_pokemon_level].append(player_avg_damage_done)
for pokemon_name in avg_damage_per_level:
for level in avg_damage_per_level[pokemon_name]:
avg_damage_per_level[pokemon_name][level] = np.mean(avg_damage_per_level[pokemon_name][level])
for pokemon_name in avg_damage_per_level:
levels = list(avg_damage_per_level[pokemon_name].keys())
avg_damages = list(avg_damage_per_level[pokemon_name].values())
plt.figure(figsize=(12, 6))
plt.bar(levels, avg_damages)
plt.xlabel('Pokemon Level')
plt.ylabel('Average Damage Done')
plt.title(f'Average Damage Done per battle turn for {pokemon_name}')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig(f'plots/average_damage_per_turn_{pokemon_name}.pdf')
#pie chart
available_pokemon_type_distribution = {}
for pokemon_name in gd.pokemons_dict:
pokemon_types = gd.pokemons_dict[pokemon_name]['types']
for pokemon_type in pokemon_types:
if pokemon_type not in available_pokemon_type_distribution:
available_pokemon_type_distribution[pokemon_type] = 0
available_pokemon_type_distribution[pokemon_type] += 1
encountered_pokemon_types = {}
for file_name in files_to_analyze:
pickle_in = open(f"results/{file_name}",'rb')
all_battle_results = pickle.load(pickle_in)
pickle_in.close()
for battle_result in all_battle_results:
encountered_pokemon = battle_result['encountered_pokemon']
encountered_pokemon_types_list = encountered_pokemon.types
for pokemon_type in encountered_pokemon_types_list:
if pokemon_type not in encountered_pokemon_types:
encountered_pokemon_types[pokemon_type] = 0
encountered_pokemon_types[pokemon_type] += 1
quantities = list(encountered_pokemon_types.values())
labels = list(encountered_pokemon_types.keys())
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.pie(quantities, labels=labels, autopct='%1.1f%%', startangle=140)
plt.title('Distribution of Encountered Pokemon Types')
plt.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle
plt.subplot(1, 2, 2)
quantities_base = list(available_pokemon_type_distribution.values())
labels_base = list(available_pokemon_type_distribution.keys())
plt.pie(quantities_base, labels=labels_base, autopct='%1.1f%%', startangle=140)
plt.title('Distribution of Available Pokemon Types')
plt.axis('equal')
plt.savefig('plots/pokemon_types_distribution.pdf')
if __name__ == "__main__":
Ngames = 1000
Nbattles = 150
print("Generating data")
for i in range(Ngames):
#automatic player creation (choose a random starter pokemon)
starter_choice = random.choice(gd.available_starters)
print(f"Generating data for {starter_choice}, game {i}...")
results = Main(starter_choice = starter_choice, Nbattles=Nbattles)
pickle_out = open(f"results/{starter_choice}_game_{i}_{Nbattles}_battles.pickle",'wb')
pickle.dump(results,pickle_out)
pickle_out.close()
print("Generating plots")
make_plots(Ngames, Nbattles)
print("Finished!")