Files
ppse/HW5/core.py
T
2026-08-24 13:49:19 +02:00

235 lines
8.5 KiB
Python

import random
import math
import copy
import game_data as gd
class Pokemon:
def __init__(self, input_series):
self.national_pokedex_number = input_series['national_pokedex_number']
self.name = input_series['name']
self.level = random.randint(1,20)
self.types = input_series['types']
self.baseStats = input_series['baseStats']
self.moves_dict = {}
moves = input_series['moves']
if len(moves) > 4:
raise ValueError("A Pokemon can only have 4 moves.")
else:
for move in moves:
#check if the move is in the available_moves dataframe
if move not in gd.available_moves_df.index:
raise ValueError(f"{move} is not an available move.")
else:
self.moves_dict[move] = copy.deepcopy(gd.available_moves_df.loc[move])
self.ActStats = self._compute_ActStats()
self.curr_hp = self.ActStats['hp']
def _compute_ActStats(self):
ActStats = {}
for baseKey in self.baseStats.keys():
if baseKey == 'hp':
ActStats[baseKey] = math.floor(self.baseStats[baseKey] * 2 * self.level / 100) + self.level + 10
else:
ActStats[baseKey] = math.floor(self.baseStats[baseKey] * 2 * self.level / 100) + 5
return ActStats
def _get_baseStats(self):
return self.baseStats
def get_current_hp(self):
return self.curr_hp
def get_current_hp_percent(self):
return self.curr_hp / self.baseStats['hp']
def can_battle(self):
condition1 = self.curr_hp > 0
condition2 = False
for move in self.moves_dict:
move_usage_avail = True #disregard pp in random battle
#move_usage_avail = self.moves_dict[move]['pp'] > 0
if move_usage_avail:
condition2 = True
break
else:
condition2 = False
return condition1 and condition2
def learnMove(self, move):
if len(self.moves_dict) >= 4:
raise ValueError("A Pokemon can only have 4 moves.")
else:
self.moves_dict[move] = copy.deepcopy(gd.available_moves_df[move])
def _compute_effect(self, move, opponent):
#check the move type (attack) and the defending
#pokemon type (defend) and look at effectiveness list.
#this should be done for all type of the defending pokemon
attack_move_type = move['type']
defending_types = opponent.get_types()
effect = 1
for def_t in defending_types:
for effectiveness_dataset in gd.type_effectiveness:
if effectiveness_dataset['attack'] == attack_move_type and effectiveness_dataset['defend'] == def_t:
effect = effect * effectiveness_dataset['effectiveness']
break
return effect
def _useMove(self, move, opponent):
if random.random() < move['accuracy']:
if move['category'] == 'physical':
attack = self.ActStats['attack']
defense = opponent.ActStats['defense']
assert defense>0
else:
attack = self.ActStats['special']
defense = opponent.ActStats['special']
assert defense>0
stability = 1.5 if move['type'] in self.types else 1
effect = self._compute_effect(move,opponent)
critical = 2 if random.random() < self.ActStats['speed']/512 else 1
luck = random.uniform(0.85, 1.0)
modifier = stability * effect * critical * luck
damage = math.floor(((2*self.level+10)/250 * (attack/defense) * move['power'] + 2) * modifier)
opponent.curr_hp -= damage
if opponent.curr_hp < 0:
opponent.curr_hp = 0
#print(f"{self.name} used {move['name']} and dealt {damage} damage to {opponent.name}!")
else:
damage = 0
#print(f"{self.name}'s attack missed!")
return damage
def useMove(self, move_name, opponent):
if move_name not in self.moves_dict:
raise ValueError(f"{self.name} does not know the move {move_name}.")
else:
return self._useMove(self.moves_dict[move_name], opponent)
def print_move(self,move):
print(f"Move: {self.moves_dict[move]['name']}")
print(f"Type: {self.moves_dict[move]['type']}")
print(f"Category: {self.moves_dict[move]['category']}")
print(f"Power: {self.moves_dict[move]['power']}")
print(f"Accuracy: {self.moves_dict[move]['accuracy']}")
print(f"PP: {self.moves_dict[move]['pp']}")
def get_moves(self):
return list(self.moves_dict.keys())
def get_types(self):
return self.types
def checkout_move(self, move_name):
if move_name not in self.moves_dict:
raise ValueError(f"{self.name} does not know the move {move_name}.")
else:
self.print_move(move_name)
def _status(self):
print(f"Pokemon: {self.name}")
print(f"Level: {self.level}")
print(f"Types: {self.types}")
print(f"Base Stats: {self.baseStats}")
print(f"Current HP: {self.curr_hp}")
print(f"Moves: {self.moves_dict}")
def print_pokemon_info(self):
self._status()
class Trainer:
def __init__(self, name, starter_name, items = {"potions": 0, "pokeball": 0}, is_CPU = False):
self.name = name
self.starter = starter_name
self.active_pokemon = Pokemon(gd.pokemons_df.loc[starter_name])
self.pokemon_list = []
self.add_pokemon(self.active_pokemon)
self.items = items
self.is_CPU = is_CPU
def add_pokemon(self, pokemon):
if len(self.pokemon_list) >= 6:
raise ValueError("A trainer can only have 6 Pokemon.")
else:
self.pokemon_list.append(pokemon)
def get_pokemon_list(self):
return [pok.name for pok in self.pokemon_list]
def get_pokemon(self, name):
for pokemon in self.pokemon_list:
if pokemon.name == name:
return pokemon
raise ValueError(f"{name} is not in the trainer's Pokemon list.")
def can_battle(self):
for pokemon in self.pokemon_list:
if pokemon.can_battle():
return True
return False
def active_pokemon_can_battle(self):
return self.active_pokemon.can_battle()
def _change_active_pokemon(self,new_pokemon):
self.active_pokemon = new_pokemon
def get_active_pokemon(self):
return self.active_pokemon
def change_active_pokemon(self,pokemon_name):
try:
new_pokemon = self.get_pokemon(pokemon_name)
self._change_active_pokemon(new_pokemon)
print("Pokemon change successfull!")
except ValueError as e:
raise e
def print_items(self):
print(f"1) Potions: {self.items['potions']}")
print(f"2) Pokeballs: {self.items['pokeball']}")
def use_item(self, item_name):
if item_name not in self.items:
raise ValueError(f"{item_name} is not an available item.")
else:
if self.items[item_name] > 0:
self.items[item_name] -= 1 #use the item
print(f"Used {item_name}. Remaining: {self.items[item_name]}")
if item_name == "potions":
self.active_pokemon.curr_hp += 20
if self.active_pokemon.curr_hp > self.active_pokemon.baseStats['hp']:
self.active_pokemon.curr_hp = self.active_pokemon.baseStats['hp']
print(f"{self.active_pokemon.name} has been healed by 20 HP!")
return False
elif item_name == "pokeball":
return True
else:
raise ValueError(f"You have no {item_name} left.")
def update_pokemon_list(self, pokemon):
pass
def _status(self):
print('='*30)
print(f"Trainer name: {self.name}")
print(f"Starter Pokemon: {self.starter}")
print(f"Pokemon List: {[pok.name for pok in self.pokemon_list]}")
print("Active Pokemon info:")
self.active_pokemon.print_pokemon_info()
print("Detailed info of Pokemons in your list:")
print("-"*30)
for pokemon in self.pokemon_list:
pokemon.print_pokemon_info()
print("-"*30)
print(f"Items: {self.items}")
print('='*30)
def print_trainer_info(self):
self._status()