def make_decision(self, player_name: str, game_state: GameState) -> CharacterDecision: """ Parameters: player_name (string): The name of your player game_state (GameState): The current game state """ self.api = API(game_state, player_name) self.my_player = game_state.get_all_players()[player_name] self.board = game_state.get_pvp_board() self.curr_pos = self.my_player.get_position() self.logger.info("In make_decision") last_action, type = self.memory.get_value("last_action", str) if last_action is not None and last_action == "PICKUP": self.memory.set_value("last_action", "EQUIP") return CharacterDecision( decision_type="EQUIP", action_position=None, action_index=self.my_player.get_free_inventory_index()) tile_items = self.board.get_tile_at(self.curr_pos).items if tile_items is not None or len(tile_items) > 0: self.memory.set_value("last_action", "PICKUP") return CharacterDecision(decision_type="PICKUP", action_position=None, action_index=0) weapon = self.my_player.get_weapon() enemies = self.api.find_enemies(self.curr_pos) if enemies is None or len(enemies) > 0: self.memory.set_value("last_action", "MOVE") return CharacterDecision( decision_type="MOVE", action_position=self.my_player.get_spawn_point(), action_index=None) enemy_pos = enemies[0].get_position() if self.curr_pos.manhattan_distance(enemy_pos) <= weapon.get_range(): self.memory.set_value("last_action", "ATTACK") return CharacterDecision(decision_type="ATTACK", action_position=enemy_pos, action_index=None) self.memory.set_value("last_action", "MOVE") decision = CharacterDecision(decision_type="MOVE", action_position=find_position_to_move( self.my_player, enemy_pos), action_index=None) return decision
class Strategy: def __init__(self, memory): self.memory = memory self.logger = logging.getLogger('strategy') self.logger.setLevel(logging.DEBUG) def make_decision(self, player_name: str, game_state: GameState) -> CharacterDecision: """ Parameters: player_name (string): The name of your player game_state (GameState): The current game state """ self.api = API(game_state, player_name) self.my_player = game_state.get_all_players()[player_name] self.board = game_state.get_pvp_board() self.curr_pos = self.my_player.get_position() self.logger.info("In make_decision") last_action, type = self.memory.get_value("last_action", str) if last_action is not None and last_action == "PICKUP": self.memory.set_value("last_action", "EQUIP") return CharacterDecision( decision_type="EQUIP", action_position=None, action_index=self.my_player.get_free_inventory_index()) tile_items = self.board.get_tile_at(self.curr_pos).items if tile_items is not None or len(tile_items) > 0: self.memory.set_value("last_action", "PICKUP") return CharacterDecision(decision_type="PICKUP", action_position=None, action_index=0) weapon = self.my_player.get_weapon() enemies = self.api.find_enemies(self.curr_pos) if enemies is None or len(enemies) > 0: self.memory.set_value("last_action", "MOVE") return CharacterDecision( decision_type="MOVE", action_position=self.my_player.get_spawn_point(), action_index=None) enemy_pos = enemies[0].get_position() if self.curr_pos.manhattan_distance(enemy_pos) <= weapon.get_range(): self.memory.set_value("last_action", "ATTACK") return CharacterDecision(decision_type="ATTACK", action_position=enemy_pos, action_index=None) self.memory.set_value("last_action", "MOVE") decision = CharacterDecision(decision_type="MOVE", action_position=find_position_to_move( self.my_player, enemy_pos), action_index=None) return decision # feel free to write as many helper functions as you need! def find_position_to_move(self, player: Position, destination: Position) -> Position: path = self.api.find_path(player.get_position(), destination) pos = None if len(path) < player.get_speed(): pos = path[-1] else: pos = path[player.get_speed() - 1] return pos
class Strategy: def __init__(self, memory): self.memory = memory self.logger = logging.getLogger('strategy') self.logger.setLevel(logging.DEBUG) logging.basicConfig(level=logging.INFO) def make_decision(self, player_name: str, game_state: GameState) -> CharacterDecision: """ Parameters: player_name (string): The name of your player game_state (GameState): The current game state """ self.api = API(game_state, player_name) self.my_player = game_state.get_all_players()[player_name] self.board = game_state.get_pvp_board() self.curr_pos = self.my_player.get_position() self.logger.info("In make_decision") self.logger.info( f"Currently at position: ({self.curr_pos.x},{self.curr_pos.y}) on board '{self.curr_pos.board_id}'" ) last_action, type = self.memory.get_value("last_action", str) self.logger.info(f"last_action: '{last_action}'") if last_action is not None and last_action == "PICKUP": self.logger.info( "Last action was picking up, equipping picked up object") self.memory.set_value("last_action", "EQUIP") return CharacterDecision( decision_type="EQUIP", action_position=None, action_index=0 # self.my_player.get_free_inventory_index() ) tile_items = self.board.get_tile_at(self.curr_pos).get_items() if tile_items is not None and len(tile_items) > 0: self.logger.info("There are items on my tile, picking up item") self.memory.set_value("last_action", "PICKUP") return CharacterDecision(decision_type="PICKUP", action_position=None, action_index=0) weapon = self.my_player.get_weapon() enemies = self.api.find_enemies_by_distance(self.curr_pos) if enemies is None or len(enemies) == 0: self.logger.info( "There is no enemies in range, moving to spawn point") self.memory.set_value("last_action", "MOVE") return CharacterDecision( decision_type="MOVE", action_position=self.my_player.get_spawn_point(), action_index=None) enemy_pos = enemies[0].get_position() if self.curr_pos.manhattan_distance(enemy_pos) <= weapon.get_range(): self.logger.info( "There is an enemy within weapon range, attacking") self.memory.set_value("last_action", "ATTACK") return CharacterDecision(decision_type="ATTACK", action_position=enemy_pos, action_index=None) self.memory.set_value("last_action", "MOVE") self.logger.info("Moving towards the nearest enemy") decision = CharacterDecision( decision_type="MOVE", action_position=self.find_position_to_move(self.my_player, enemy_pos), action_index=None) return decision # feel free to write as many helper functions as you need! def find_position_to_move(self, player: Player, destination: Position) -> Position: path = self.api.find_path(player.get_position(), destination) # path can be empty if player.get_position() == destination if len(path) == 0: return player.get_position() pos = None if len(path) < player.get_speed(): pos = path[-1] else: pos = path[player.get_speed() - 1] return pos
def make_decision(self, player_name: str, game_state: GameState) -> CharacterDecision: """ Parameters: player_name (string): The name of your player game_state (GameState): The current game state """ ######################## Initialize ######################## self.api = API(game_state, player_name) self.my_player = game_state.get_all_players()[player_name] self.current_board = game_state.get_board( self.my_player.get_position().board_id) self.curr_pos = self.my_player.get_position() self.monsters_on_board = { name: monster for name, monster in game_state.get_all_monsters().items() if monster.get_position().board_id == self.curr_pos.board_id } target_monster = None self.searching_graph = search.Graph( self.current_board, self.my_player.get_position().board_id) self.logger.info("In make_decision") # self.logger.info(helpers.TELL_ME_ME(self.my_player)) ######################## TAKE TURN HERE ######################## # self.logger.info(f"All monsters: {game_state.get_all_monsters()}") #decision = CharacterDecision( # decision_type="MOVE", # action_position=Position(self.curr_pos.x+2, self.curr_pos.y, "tb_tbdt_dt"), # action_index=None) # Combine nearby items with inventory items available_items_tiles = helpers.non_api_find_items( self.my_player, self.current_board, self.my_player.get_speed(), self.logger) available_items = self.my_player.inventory + [ tup[0] for tup in available_items_tiles ] self.logger.info(f"My Player: {self.my_player.__dict__}") self.logger.info(f"Current position: {self.curr_pos.__dict__}") self.logger.info(f"Available items around: {available_items_tiles}") self.logger.info(f"Our inventory: {self.my_player.inventory}") self.logger.info( f"Our weapon actual: {self.my_player.get_weapon().__dict__}") self.logger.info( f"Our weapon: {self.my_player.get_weapon().stats.__dict__}") self.logger.info( f"Our clothes: {self.my_player.get_clothes().stats.__dict__}") self.logger.info( f"Our shoes: {self.my_player.get_shoes().stats.__dict__}") self.logger.info(f"Our hat: {self.my_player.get_hat().stats.__dict__}") self.logger.info( f"Our accessory: {self.my_player.get_accessory().stats.__dict__}") # best item to equip here! item_index = helpers.should_we_equip(self.my_player, available_items, self.logger) self.logger.info(f"Item index: {item_index}") # Find non-consumable items droppable_items = [ (index, item) for index, item in enumerate(self.my_player.inventory) if type(item) in [Weapon, Clothes, Shoes, Hat, Accessory] ] nearby_monsters = helpers.monsters_in_range( self.my_player, list(self.monsters_on_board.values())) if item_index != -1 and item_index >= len(self.my_player.inventory): target_item, x, y = available_items_tiles[ item_index - len(self.my_player.inventory)] if x != self.curr_pos.x or y != self.curr_pos.y: pos = Position.create(x, y, self.curr_pos.board_id) decision = decision_maker.head_to(pos) else: if len(self.my_player.inventory) >= 16: self.logger.warning( "==================INVENTORY FULL??? pOG================" ) else: decision = decision_maker.pickup(self.my_player, target_item, self.current_board) elif item_index != -1: decision = decision_maker.equip_given_item(item_index) elif nearby_monsters: decision, target_monster = decision_maker.make_our_combat_decision( self.api, self.my_player, self.logger, self.monsters_on_board, self.searching_graph) elif droppable_items: index, item = droppable_items[0] decision = decision_maker.drop_item(index) #elif available_items_tiles: # decision = decision_maker.loot_items(self.api, self.my_player, self.logger, self.current_board, available_items_tiles) else: decision, target_monster = decision_maker.make_our_combat_decision( self.api, self.my_player, self.logger, self.monsters_on_board, self.searching_graph) #decision = decision_maker.make_our_weapon_decision(self.api, self.my_player, self.logger) #decision = decision_maker.head_to_portal_decision(self.api, self.my_player, self.logger) # decision_maker.head_to_portal_decision(self.api, self.my_player, self.logger) self.logger.info(f"We are doing {decision.__dict__}") try: self.logger.info( f"Position is: {decision.action_position.__dict__}") except: pass self.logger.info( f"Player experience: {self.my_player.get_total_experience()}") #try: # self.logger.info(f"====near target monsters=== {[mon.__dict__ for mon in list(self.monsters_on_board.values()) if abs(self.my_player.get_level() - mon.get_level()) < 4][:9]}") #except: # self.logger.info(f"======================log failed") ######################## Logging ######################## self.memory.set_value("last_decision", decision) self.memory.set_value("last_target_monster", target_monster) self.logger.info( f"{target_monster.__dict__ if target_monster else 'None'}") self.memory.set_value("last_current_health", self.my_player.current_health) ######################## END TURN ######################## return decision """
def make_decision(self, player_name: str, game_state: GameState) -> CharacterDecision: """ Parameters: player_name (string): The name of your player game_state (GameState): The current game state """ self.api = API(game_state, player_name) self.my_player = game_state.get_all_players()[player_name] self.board = game_state.get_pvp_board() self.curr_pos = self.my_player.get_position() self.logger.info("In make_decision") self.logger.info( f"Currently at position: ({self.curr_pos.x},{self.curr_pos.y}) on board '{self.curr_pos.board_id}'" ) last_action, type = self.memory.get_value("last_action", str) self.logger.info(f"last_action: '{last_action}'") if last_action is not None and last_action == "PICKUP": self.logger.info( "Last action was picking up, equipping picked up object") self.memory.set_value("last_action", "EQUIP") return CharacterDecision( decision_type="EQUIP", action_position=None, action_index=0 # self.my_player.get_free_inventory_index() ) tile_items = self.board.get_tile_at(self.curr_pos).get_items() if tile_items is not None and len(tile_items) > 0: self.logger.info("There are items on my tile, picking up item") self.memory.set_value("last_action", "PICKUP") return CharacterDecision(decision_type="PICKUP", action_position=None, action_index=0) weapon = self.my_player.get_weapon() enemies = self.api.find_enemies_by_distance(self.curr_pos) if enemies is None or len(enemies) == 0: self.logger.info( "There is no enemies in range, moving to spawn point") self.memory.set_value("last_action", "MOVE") return CharacterDecision( decision_type="MOVE", action_position=self.my_player.get_spawn_point(), action_index=None) enemy_pos = enemies[0].get_position() if self.curr_pos.manhattan_distance(enemy_pos) <= weapon.get_range(): self.logger.info( "There is an enemy within weapon range, attacking") self.memory.set_value("last_action", "ATTACK") return CharacterDecision(decision_type="ATTACK", action_position=enemy_pos, action_index=None) self.memory.set_value("last_action", "MOVE") self.logger.info("Moving towards the nearest enemy") decision = CharacterDecision( decision_type="MOVE", action_position=self.find_position_to_move(self.my_player, enemy_pos), action_index=None) return decision
def make_decision(self, player_name: str, game_state: GameState) -> CharacterDecision: """ Parameters: player_name (string): The name of your player game_state (GameState): The current game state """ self.logger.info( "==========================NEW TURN==========================") self.api = API(game_state, player_name) self.character = game_state.get_character(player_name) self.my_player = game_state.get_all_players()[player_name] #self.pvpboard = game_state.get_pvp_board() self.board = game_state.get_board(self.board_id) self.curr_pos = self.my_player.get_position() self.monsters = game_state.get_monsters_on_board(self.board_id) self.obstacles = self.get_obstacles(game_state) self.bad_monster_squares = self.get_monsters(game_state, self.board_id) # cycle through items items = self.my_player.get_inventory() self.logger.info("items: {}".format(items)) cur_weapon = self.my_player.get_weapon self.logger.info('performing inventory check') try: if self.character.clothes is not None: self.print_stats(self.character.clothes) except: self.logger.info("no clothes to print") pass try: if self.character.hat is not None: self.print_stats(self.character.hat) except: self.logger.info("no hat to print") pass try: if self.character.weapon is not None: self.print_stats(self.character.weapon) except: self.logger.info("no weapon to print") pass try: if self.character.shoes is not None: self.print_stats(self.character.shoes) except: self.logger.info("no shoes to print") pass try: if self.character.accessory is not None: self.print_stats(self.character.accessory) except: self.logger.info("no accessory to print") pass for i, item in reversed(list(enumerate(items))): # self.logger.info('exp change: {}, {}'.format(item.get_flat_experience_change(), item.get_percent_experience_change())) # self.logger.info('atk change: {}, {}'.format(item.get_flat_attack_change(), item.get_percent_attack_change())) # if item.get_flat_attack_change() > cur_weapon.get_flat_attack_change(): # self.logger.info('equiping item') # return CharacterDecision( # decision_type="EQUIP", # action_position=None, # action_index=i # ) try: self.logger.info("grading index {} in the inventory".format(i)) # self.logger.info(type(item)) item_type = item.__class__.__name__ # self.logger.info(item_type) if "Consumable" in item_type: #idk do we equip the consumable before we fite the guy #but also if its a health potion do it now self.logger.info( 'index {} is a consumable, eating!'.format(i)) #actually drop consumables f**k em (no wee eat them right there) return CharacterDecision(decision_type="EQUIP", action_position=None, action_index=i) # continue self.logger.info(self.print_stats(item)) stat_mod = item.get_stats() new_stats = 0 try: new_stats += stat_mod.get_flat_speed_change() * 0 except: new_stats += 0 try: new_stats += stat_mod.get_percent_speed_change() * 0 except: new_stats += 0 try: new_stats += stat_mod.get_flat_health_change() * .1 except: new_stats += 0 try: new_stats += stat_mod.get_percent_health_change() * 30 except: new_stats += 0 try: new_stats += stat_mod.get_flat_experience_change() * 10 except: new_stats += 0 try: new_stats += stat_mod.get_percent_experience_change() * 200 except: new_stats += 0 try: new_stats += stat_mod.get_flat_attack_change() * 10 except: new_stats += 0 try: new_stats += stat_mod.get_percent_attack_change() * 70 except: new_stats += 0 try: new_stats += stat_mod.get_flat_defense_change() * 2 except: new_stats += 0 try: new_stats += stat_mod.get_percent_defense_change() * 30 except: new_stats += 0 try: new_stats += stat_mod.get_flat_regen_per_turn() * 0 except: new_stats += 0 self.logger.info("got stats for index {}".format(i)) # new_stats = stat_mods.get_flat_speed_change() + stat_mods.get_percent_speed_change() + stat_mods.get_flat_health_change() + stat_mods.get_percent_health_change() + stat_mods.get_flat_defense_change() + stat_mods.get_flat_attack_change() + stat_mods.get_percent_attack_change() self.logger.info("stat check for index {} is {}".format( i, new_stats)) for typ in ["Clothes", "Hat", "Shoes", "Weapon", "Accessory"]: if typ in item_type: self.logger.info('index {} is a {}'.format(i, typ)) current_stats = self.stats[typ] self.logger.info( 'old stats: {} , new stats: {}'.format( current_stats, new_stats)) if new_stats > current_stats: self.logger.info("equipping") self.stats[typ] = new_stats return CharacterDecision(decision_type="EQUIP", action_position=None, action_index=i) else: self.logger.info( "this {} sucks, dropping it".format(typ)) return CharacterDecision(decision_type="DROP", action_position=None, action_index=i) except Exception as e: self.logger.error(e) return CharacterDecision(decision_type="DROP", action_position=None, action_index=0) # item pick up tile_items = self.board.get_tile_at(self.curr_pos).items if len(tile_items) > 0: self.memory.set_value("last_action", "PICKUP") self.logger.info("picking up item: {}".format(tile_items)) try: for i in range(len(tile_items)): self.logger.info("grading new item index {}".format(i)) if "Consumable" in tile_items[i].__class__.__name__: return CharacterDecision(decision_type="PICKUP", action_position=self.curr_pos, action_index=i) stat_mods = tile_items[i].get_stats() stat_sum = stat_mods.get_flat_speed_change( ) * 0 + stat_mods.get_percent_speed_change( ) * 0 + stat_mods.get_flat_health_change( ) * .1 + stat_mods.get_percent_health_change( ) * 30 + stat_mods.get_flat_defense_change( ) * 2 + stat_mods.get_flat_attack_change( ) * 10 + stat_mods.get_percent_attack_change( ) * 70 + stat_mods.get_percent_defense_change( ) * 30 + stat_mods.get_flat_regen_per_turn( ) * 0 + stat_mods.get_flat_experience_change( ) * 10 + stat_mods.get_percent_experience_change() * 200 self.logger.info("new item stat: " + str(stat_sum)) self.logger.info( "curr stat item: " + str(self.stats[tile_items[i].__class__.__name__])) if stat_sum > self.stats[tile_items[i].__class__.__name__]: self.logger.info( "picking up item at index {}".format(i)) return CharacterDecision(decision_type="PICKUP", action_position=self.curr_pos, action_index=i) else: self.logger.info( "skipping index {}, shitty item".format(i)) except Exception as e: self.logger.error(e) self.logger.info("picking up item at index 0") return CharacterDecision(decision_type="PICKUP", action_position=self.curr_pos, action_index=i) for d in [(1, 0), (-1, 0), (0, 1), (0, -1)]: target_pos = Position.create(self.curr_pos.x + d[0], self.curr_pos.y + d[1], self.curr_pos.get_board_id()) tile_items = self.board.get_tile_at(target_pos).items if len(tile_items) > 0: for i in range(len(tile_items)): self.logger.info("grading new item index {}".format(i)) if "Consumable" in tile_items[i].__class__.__name__: self.memory.set_value("last_action", "MOVE") self.logger.info("moving to item") return CharacterDecision(decision_type="MOVE", action_position=target_pos, action_index=0) stat_mods = tile_items[i].get_stats() stat_sum = stat_mods.get_flat_speed_change( ) * 0 + stat_mods.get_percent_speed_change( ) * 0 + stat_mods.get_flat_health_change( ) * .1 + stat_mods.get_percent_health_change( ) * 30 + stat_mods.get_flat_defense_change( ) * 2 + stat_mods.get_flat_attack_change( ) * 10 + stat_mods.get_percent_attack_change( ) * 70 + stat_mods.get_percent_defense_change( ) * 30 + stat_mods.get_flat_regen_per_turn( ) * 0 + stat_mods.get_flat_experience_change( ) * 10 + stat_mods.get_percent_experience_change() * 200 self.logger.info("new item stat: " + str(stat_sum)) self.logger.info( "curr stat item: " + str(self.stats[tile_items[i].__class__.__name__])) if stat_sum > self.stats[tile_items[i].__class__.__name__]: self.memory.set_value("last_action", "MOVE") self.logger.info("moving to item") return CharacterDecision(decision_type="MOVE", action_position=target_pos, action_index=0) else: self.logger.info( "skipping index {}, shitty item".format(i)) ## Choose weakest monster weakestMonster = self.findWeakest(self.monsters, self.curr_pos) weapon = self.my_player.get_weapon() ## Check if weakest monster is in attack range if self.curr_pos.manhattan_distance( weakestMonster.position) <= weapon.get_range(): self.logger.info("Attacking monster: " + str(weakestMonster.get_name()) + " with health " + str(weakestMonster.get_current_health()) + "/" + str(weakestMonster.get_max_health())) return CharacterDecision( decision_type="ATTACK", action_position=weakestMonster.get_position(), action_index=0) ## Move to weakest monster! self.logger.info("Chosen weakest monster: " + str(weakestMonster.get_name()) + " || location: (" + str(weakestMonster.get_position().x) + "," + str(weakestMonster.get_position().y) + ")") positionToMove = self.zhou_astar_path_to_move( self.my_player, weakestMonster.get_position()) # hard code walk back if positionToMove[0] >= 6: positionToMove[0] = 4 positionObjectToMove = self.curr_pos newPos = positionObjectToMove.create(positionToMove[0], positionToMove[1], self.board_id) self.logger.info("Location to move now: (" + str(newPos.x) + ", " + str(newPos.y) + ")") return CharacterDecision(decision_type="MOVE", action_position=newPos, action_index=0)
class Strategy: def __init__(self, memory): self.buffoon = 0 self.memory = memory self.logger = logging.getLogger('strategy') self.logger.setLevel(logging.DEBUG) logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s') self.board_id = "buffoon" self.stats = collections.defaultdict(int) def make_decision(self, player_name: str, game_state: GameState) -> CharacterDecision: """ Parameters: player_name (string): The name of your player game_state (GameState): The current game state """ self.logger.info( "==========================NEW TURN==========================") self.api = API(game_state, player_name) self.character = game_state.get_character(player_name) self.my_player = game_state.get_all_players()[player_name] #self.pvpboard = game_state.get_pvp_board() self.board = game_state.get_board(self.board_id) self.curr_pos = self.my_player.get_position() self.monsters = game_state.get_monsters_on_board(self.board_id) self.obstacles = self.get_obstacles(game_state) self.bad_monster_squares = self.get_monsters(game_state, self.board_id) # cycle through items items = self.my_player.get_inventory() self.logger.info("items: {}".format(items)) cur_weapon = self.my_player.get_weapon self.logger.info('performing inventory check') try: if self.character.clothes is not None: self.print_stats(self.character.clothes) except: self.logger.info("no clothes to print") pass try: if self.character.hat is not None: self.print_stats(self.character.hat) except: self.logger.info("no hat to print") pass try: if self.character.weapon is not None: self.print_stats(self.character.weapon) except: self.logger.info("no weapon to print") pass try: if self.character.shoes is not None: self.print_stats(self.character.shoes) except: self.logger.info("no shoes to print") pass try: if self.character.accessory is not None: self.print_stats(self.character.accessory) except: self.logger.info("no accessory to print") pass for i, item in reversed(list(enumerate(items))): # self.logger.info('exp change: {}, {}'.format(item.get_flat_experience_change(), item.get_percent_experience_change())) # self.logger.info('atk change: {}, {}'.format(item.get_flat_attack_change(), item.get_percent_attack_change())) # if item.get_flat_attack_change() > cur_weapon.get_flat_attack_change(): # self.logger.info('equiping item') # return CharacterDecision( # decision_type="EQUIP", # action_position=None, # action_index=i # ) try: self.logger.info("grading index {} in the inventory".format(i)) # self.logger.info(type(item)) item_type = item.__class__.__name__ # self.logger.info(item_type) if "Consumable" in item_type: #idk do we equip the consumable before we fite the guy #but also if its a health potion do it now self.logger.info( 'index {} is a consumable, eating!'.format(i)) #actually drop consumables f**k em (no wee eat them right there) return CharacterDecision(decision_type="EQUIP", action_position=None, action_index=i) # continue self.logger.info(self.print_stats(item)) stat_mod = item.get_stats() new_stats = 0 try: new_stats += stat_mod.get_flat_speed_change() * 0 except: new_stats += 0 try: new_stats += stat_mod.get_percent_speed_change() * 0 except: new_stats += 0 try: new_stats += stat_mod.get_flat_health_change() * .1 except: new_stats += 0 try: new_stats += stat_mod.get_percent_health_change() * 30 except: new_stats += 0 try: new_stats += stat_mod.get_flat_experience_change() * 10 except: new_stats += 0 try: new_stats += stat_mod.get_percent_experience_change() * 200 except: new_stats += 0 try: new_stats += stat_mod.get_flat_attack_change() * 10 except: new_stats += 0 try: new_stats += stat_mod.get_percent_attack_change() * 70 except: new_stats += 0 try: new_stats += stat_mod.get_flat_defense_change() * 2 except: new_stats += 0 try: new_stats += stat_mod.get_percent_defense_change() * 30 except: new_stats += 0 try: new_stats += stat_mod.get_flat_regen_per_turn() * 0 except: new_stats += 0 self.logger.info("got stats for index {}".format(i)) # new_stats = stat_mods.get_flat_speed_change() + stat_mods.get_percent_speed_change() + stat_mods.get_flat_health_change() + stat_mods.get_percent_health_change() + stat_mods.get_flat_defense_change() + stat_mods.get_flat_attack_change() + stat_mods.get_percent_attack_change() self.logger.info("stat check for index {} is {}".format( i, new_stats)) for typ in ["Clothes", "Hat", "Shoes", "Weapon", "Accessory"]: if typ in item_type: self.logger.info('index {} is a {}'.format(i, typ)) current_stats = self.stats[typ] self.logger.info( 'old stats: {} , new stats: {}'.format( current_stats, new_stats)) if new_stats > current_stats: self.logger.info("equipping") self.stats[typ] = new_stats return CharacterDecision(decision_type="EQUIP", action_position=None, action_index=i) else: self.logger.info( "this {} sucks, dropping it".format(typ)) return CharacterDecision(decision_type="DROP", action_position=None, action_index=i) except Exception as e: self.logger.error(e) return CharacterDecision(decision_type="DROP", action_position=None, action_index=0) # item pick up tile_items = self.board.get_tile_at(self.curr_pos).items if len(tile_items) > 0: self.memory.set_value("last_action", "PICKUP") self.logger.info("picking up item: {}".format(tile_items)) try: for i in range(len(tile_items)): self.logger.info("grading new item index {}".format(i)) if "Consumable" in tile_items[i].__class__.__name__: return CharacterDecision(decision_type="PICKUP", action_position=self.curr_pos, action_index=i) stat_mods = tile_items[i].get_stats() stat_sum = stat_mods.get_flat_speed_change( ) * 0 + stat_mods.get_percent_speed_change( ) * 0 + stat_mods.get_flat_health_change( ) * .1 + stat_mods.get_percent_health_change( ) * 30 + stat_mods.get_flat_defense_change( ) * 2 + stat_mods.get_flat_attack_change( ) * 10 + stat_mods.get_percent_attack_change( ) * 70 + stat_mods.get_percent_defense_change( ) * 30 + stat_mods.get_flat_regen_per_turn( ) * 0 + stat_mods.get_flat_experience_change( ) * 10 + stat_mods.get_percent_experience_change() * 200 self.logger.info("new item stat: " + str(stat_sum)) self.logger.info( "curr stat item: " + str(self.stats[tile_items[i].__class__.__name__])) if stat_sum > self.stats[tile_items[i].__class__.__name__]: self.logger.info( "picking up item at index {}".format(i)) return CharacterDecision(decision_type="PICKUP", action_position=self.curr_pos, action_index=i) else: self.logger.info( "skipping index {}, shitty item".format(i)) except Exception as e: self.logger.error(e) self.logger.info("picking up item at index 0") return CharacterDecision(decision_type="PICKUP", action_position=self.curr_pos, action_index=i) for d in [(1, 0), (-1, 0), (0, 1), (0, -1)]: target_pos = Position.create(self.curr_pos.x + d[0], self.curr_pos.y + d[1], self.curr_pos.get_board_id()) tile_items = self.board.get_tile_at(target_pos).items if len(tile_items) > 0: for i in range(len(tile_items)): self.logger.info("grading new item index {}".format(i)) if "Consumable" in tile_items[i].__class__.__name__: self.memory.set_value("last_action", "MOVE") self.logger.info("moving to item") return CharacterDecision(decision_type="MOVE", action_position=target_pos, action_index=0) stat_mods = tile_items[i].get_stats() stat_sum = stat_mods.get_flat_speed_change( ) * 0 + stat_mods.get_percent_speed_change( ) * 0 + stat_mods.get_flat_health_change( ) * .1 + stat_mods.get_percent_health_change( ) * 30 + stat_mods.get_flat_defense_change( ) * 2 + stat_mods.get_flat_attack_change( ) * 10 + stat_mods.get_percent_attack_change( ) * 70 + stat_mods.get_percent_defense_change( ) * 30 + stat_mods.get_flat_regen_per_turn( ) * 0 + stat_mods.get_flat_experience_change( ) * 10 + stat_mods.get_percent_experience_change() * 200 self.logger.info("new item stat: " + str(stat_sum)) self.logger.info( "curr stat item: " + str(self.stats[tile_items[i].__class__.__name__])) if stat_sum > self.stats[tile_items[i].__class__.__name__]: self.memory.set_value("last_action", "MOVE") self.logger.info("moving to item") return CharacterDecision(decision_type="MOVE", action_position=target_pos, action_index=0) else: self.logger.info( "skipping index {}, shitty item".format(i)) ## Choose weakest monster weakestMonster = self.findWeakest(self.monsters, self.curr_pos) weapon = self.my_player.get_weapon() ## Check if weakest monster is in attack range if self.curr_pos.manhattan_distance( weakestMonster.position) <= weapon.get_range(): self.logger.info("Attacking monster: " + str(weakestMonster.get_name()) + " with health " + str(weakestMonster.get_current_health()) + "/" + str(weakestMonster.get_max_health())) return CharacterDecision( decision_type="ATTACK", action_position=weakestMonster.get_position(), action_index=0) ## Move to weakest monster! self.logger.info("Chosen weakest monster: " + str(weakestMonster.get_name()) + " || location: (" + str(weakestMonster.get_position().x) + "," + str(weakestMonster.get_position().y) + ")") positionToMove = self.zhou_astar_path_to_move( self.my_player, weakestMonster.get_position()) # hard code walk back if positionToMove[0] >= 6: positionToMove[0] = 4 positionObjectToMove = self.curr_pos newPos = positionObjectToMove.create(positionToMove[0], positionToMove[1], self.board_id) self.logger.info("Location to move now: (" + str(newPos.x) + ", " + str(newPos.y) + ")") return CharacterDecision(decision_type="MOVE", action_position=newPos, action_index=0) # Find position to move using API def find_position_to_move(self, player: Position, destination: Position) -> Position: path = self.api.find_path(player.get_position(), destination) pos = None if len(path) < player.get_speed(): pos = path[-1] else: pos = path[player.get_speed() - 1] return pos # Just moving down def move_down_position(self): target_pos = self.curr_pos target_pos.create(target_pos.x, target_pos.y, target_pos.get_board_id()) self.logger.info("yes2") return target_pos # Use astar to find path that doesn't aggro to target destination def zhou_astar_path_to_move(self, player: Position, destination: Position): frontier = [] path = [] pp = player.get_position() heapq.heapify(frontier) start = Node(0, None, (pp.x, pp.y)) heapq.heappush(frontier, (0, (pp.x, pp.y), start)) visited = set() visited.add((pp.x, pp.y)) while frontier: curr = heapq.heappop(frontier)[2] if curr.coord == (destination.x, destination.y): while curr: path.append(curr.coord) self.logger.info(str(curr.coord)) curr = curr.prev path.reverse() break neighbors = self.getNeighbors(curr.coord[0], curr.coord[1]) for n in neighbors: if n not in visited: dist = abs(destination.y - n[1]) + abs(destination.x - n[0]) newNode = Node(curr.cost + 1, curr, n) heapq.heappush( frontier, (newNode.cost + dist, newNode.coord, newNode)) visited.add(n) return path[1] # Find valid neighbors given coordinates def getNeighbors(self, getx, gety): neighbors = [] for n in [(0, 1), (0, -1), (-1, 0), (1, 0)]: coord = (getx + n[0], gety + n[1]) # if coord in self.obstacles or coord in self.bad_monster_squares: if coord in self.obstacles: continue else: neighbors.append(coord) return neighbors # Get coords of obstacles def get_obstacles(self, game_state): grid = self.board.get_grid() obstacles = set() for x_idx in range(len(grid)): for y_idx in range(len(grid[x_idx])): curr_position = self.curr_pos newPos = curr_position.create(x_idx, y_idx, self.board_id) tile = self.board.get_tile_at(newPos) if tile.type == "VOID" or tile.type == "IMPASSIBLE": obstacles.add((x_idx, y_idx)) return obstacles # Get coords of monster aggro squares def get_monsters(self, game_state, board_id): monsters = game_state.get_monsters_on_board(board_id) bad_monster_squares = set() weakest = self.findWeakest(self.monsters, self.curr_pos) weakest_position = weakest.get_position() for monster in monsters: m_p = monster.get_position() # skip over weakest monster if m_p.x == weakest_position.x and m_p.y == weakest_position.y: continue for direction in [(0, 1), (0, -1), (-1, 0), (1, 0)]: for step in range(monster.aggro_range): bad_monster_squares.add((direction[0] * step + m_p.x, direction[1] * step + m_p.y)) return bad_monster_squares # Find weakest monster def findWeakest(self, monsters, curr_pos): sortedM = sorted(monsters, key=lambda x: x.get_level()) minLevel = 5 #self.my_player.get_level() sameLevel = [] j = 0 while sortedM[j].get_level() <= minLevel: dist = curr_pos.manhattan_distance(sortedM[j].get_position()) sameLevel.append((dist, sortedM[j])) j = j + 1 nextMonster = sorted(sameLevel, key=lambda x: x[0]) i = 0 while nextMonster[i][1].get_current_health() <= 0: i = i + 1 return nextMonster[i][1] def print_stats(self, item): stat_mods = item.get_stats() self.logger.info("item class: {}".format(item.__class__.__name__)) try: self.logger.info("speed: {}, {}".format( stat_mods.get_flat_speed_change(), stat_mods.get_percent_speed_change())) except Exception as e: self.logger.error(e) self.logger.info("default speed: {}, {}".format(0, 0)) try: self.logger.info("health: {}, {}".format( stat_mods.get_flat_health_change(), stat_mods.get_percent_health_change())) except Exception as e: self.logger.error(e) self.logger.info("defaulthealth: {}, {}".format(0, 0)) try: self.logger.info("def: {}, {}".format( stat_mods.get_flat_defense_change(), stat_mods.get_percent_defense_change())) except Exception as e: self.logger.error(e) self.logger.info("default def: {}, {}".format(0, 0)) try: self.logger.info("exp: {}, {}".format( stat_mods.get_flat_experience_change(), stat_mods.get_percent_experience_change())) except Exception as e: self.logger.error(e) self.logger.info("default exp: {}, {}".format(0, 0)) try: self.logger.info("atk: {}, {}".format( stat_mods.get_flat_attack_change(), stat_mods.get_percent_attack_change())) except Exception as e: self.logger.error(e) self.logger.info("default atk: {}, {}".format(0, 0)) def get_stat_num(self, new_item): new_stats = 0 try: new_stats += stat_mod.get_flat_speed_change() except: new_stats += 0 try: new_stats += stat_mod.get_percent_speed_change() except: new_stats += 0 try: new_stats += stat_mod.get_flat_health_change() except: new_stats += 0 try: new_stats += stat_mod.get_percent_health_change() except: new_stats += 0 try: new_stats += stat_mod.get_flat_experience_change() except: new_stats += 0 try: new_stats += stat_mod.get_percent_experience_change() except: new_stats += 0 try: new_stats += stat_mod.get_flat_attack_change() except: new_stats += 0 try: new_stats += stat_mod.get_percent_attack_change() except: new_stats += 0 try: new_stats += stat_mod.get_flat_defense_change() except: new_stats += 0 try: new_stats += stat_mod.get_percent_defense_change() except: new_stats += 0 try: new_stats += stat_mod.get_flat_regen_per_turn() except: new_stats += 0 return new_stats
def make_decision(self, player_name: str, game_state: GameState) -> CharacterDecision: """ Parameters: player_name (string): The name of your player game_state (GameState): The current game state """ self.api = API(game_state, player_name) self.game_state = game_state self.my_player = game_state.get_all_players()[player_name] # self.board = game_state.get_pvp_board() self.player_board = game_state.get_board(player_name) self.curr_pos = self.my_player.get_position() self.logger.info("Version: 4.0") # Figure out role my_health = self.my_player.get_current_health() spawn_point = self.my_player.get_spawn_point() if my_health <= 10 or ( self.equal_pos(self.curr_pos, spawn_point) and my_health <= self.my_player.get_max_health() - 10): self.role = roles.GAIN_XP else: self.role = roles.GAIN_XP self.logger.info("Player at " + self.get_position_str(self.curr_pos) + " | Health: " + str(my_health) + " | XP: " + str(self.my_player.get_experience()) + " | Total XP: " + str(self.my_player.get_total_experience())) self.logger.info("ATK: {}, SPD: {}, DEF: {}".format( self.my_player.get_attack(), self.my_player.get_speed(), self.my_player.get_defense())) last_action, type = self.memory.get_value("last_action", str) last_role, type = self.memory.get_value("role", str) self.memory.set_value("role", "test_val") self.logger.info("last action " + str(last_action)) self.logger.info("last role " + str(last_role)) ### store our current stats and inven ### weapon: Weapon = self.my_player.get_weapon( ) # should always be index 0 hat: Hat = self.my_player.get_hat() # always index 1 shoes: Shoes = self.my_player.get_shoes() clothes: Clothes = self.my_player.get_clothes() # always index 2 accessory: Accessory = self.my_player.get_accessory() self.logger.info("Curr Weapon: {}".format( self.get_item_stats_str(weapon))) self.logger.info("Curr Clothes: {}".format( self.get_item_stats_str(clothes))) self.logger.info("Curr Hat: {}".format(self.get_item_stats_str(hat))) self.logger.info("Curr Shoes: {}".format( self.get_item_stats_str(shoes))) self.logger.info("Curr Accessory: {}".format( self.get_item_stats_str(accessory))) # if inventory has better weapon, equip it inven: list[Item] = self.my_player.get_inventory() self.logger.info("Have {} inventory items".format(len(inven))) best_wep_to_equip: Weapon = None best_wep_to_equip_index: int = None best_gear_to_equip: Wearable = None best_gear_to_equip_index: int = None for i, item in enumerate(inven): self.logger.info("Inven {} - {} - stats: {}".format( i, item, self.get_item_stats_str(item))) if isinstance(item, Consumable): self.logger.info("Equipping consumable") return decisions.equip_item(i) elif isinstance(item, Weapon): item_val = self.value_of_wearable(item) if item_val > self.value_of_wearable(weapon): self.logger.info( "Equipping weapon at index {} with stats: {}".format( i, self.get_item_stats_str(item))) return decisions.equip_item(i) elif item_val < self.value_of_wearable(weapon): self.logger.info("Dropping weapon at {}".format(i)) return decisions.drop_item(i) elif isinstance(item, Clothes): item_val = self.value_of_wearable(item) if (item_val > self.value_of_wearable(clothes)): self.logger.info( "Equipping clothes at index {} with stats: {}".format( i, self.get_item_stats_str(item))) return decisions.equip_item(i) elif item_val < self.value_of_wearable(clothes): self.logger.info("Dropping clothes at {}".format(i)) return decisions.drop_item(i) elif isinstance(item, Hat): item_val = self.value_of_wearable(item) if (item_val > self.value_of_wearable(hat)): self.logger.info( "Equipping hat at index {} with stats: {}".format( i, self.get_item_stats_str(item))) return decisions.equip_item(i) elif item_val < self.value_of_wearable(hat): self.logger.info("Dropping hat at {}".format(i)) return decisions.drop_item(i) elif isinstance(item, Shoes): item_val = self.value_of_wearable(item) if (item_val > self.value_of_wearable(shoes)): self.logger.info( "Equipping shoes at index {} with stats: {}".format( i, self.get_item_stats_str(item))) return decisions.equip_item(i) elif item_val < self.value_of_wearable(shoes): self.logger.info("Dropping shoes at {}".format(i)) return decisions.drop_item(i) elif isinstance(item, Accessory): item_val = self.value_of_wearable(item) if (item_val > self.value_of_wearable(accessory)): self.logger.info( "Equipping accessory at index {} with stats: {}". format(i, self.get_item_stats_str(item))) return decisions.equip_item(i) elif item_val < self.value_of_wearable(accessory): self.logger.info("Dropping accessory at {}".format(i)) return decisions.drop_item(i) # BFS search around for stuff deltas_128 = bfs_deltas[128] best_gears_found: dict[str, Wearable] = { 'weapon': None, 'clothes': None, 'shoes': None, 'hat': None, 'accessory': None, 'con': None, } best_gears_found_pos: dict[str, Position] = { 'weapon': None, 'clothes': None, 'shoes': None, 'hat': None, 'accessory': None, 'con': None, } best_gears_found_index: dict[str, Position] = { 'weapon': None, 'clothes': None, 'shoes': None, 'hat': None, 'accessory': None, 'con': None, } for delta in deltas_128: dx = delta[0] dy = delta[1] check_pos = self.create_pos(self.curr_pos.x + dx, self.curr_pos.y + dy) # self.logger.info("Checking " + self.get_position_str(check_pos)) if (check_pos.x >= self.player_board.width or check_pos.x < 0 or check_pos.y < 0 or check_pos.y >= self.player_board.height): continue # self.logger.info("in map") tile: Tile = self.player_board.get_tile_at(check_pos) items_on_tile = tile.get_items() # search for better items for i, item in enumerate(items_on_tile): self.logger.info("At " + self.get_position_str(check_pos) + ", item - " + self.get_item_stats_str(item)) if isinstance(item, Consumable): con: Consumable = item if (con.effect.turns_left > 4): best_gears_found['con'] = con best_gears_found_index['con'] = i best_gears_found_pos['con'] = check_pos elif isinstance(item, Wearable): time_to_delete = item.turns_to_deletion if (self.curr_pos.manhattan_distance(check_pos) >= time_to_delete - 2): continue if isinstance(item, Weapon): self.logger.info("Found weapon") # dont pick up weapons that take too long to retrieve # best weapon to pickup is one that deals more damage, and more damage than all weapons on map that are found item_val = self.value_of_wearable(item) if (item_val > self.value_of_wearable(weapon)): if (best_gears_found['weapon'] == None or item_val > self.value_of_wearable( best_gears_found['weapon'])): best_gears_found['weapon'] = item best_gears_found_pos['weapon'] = check_pos best_gears_found_index['weapon'] = i elif isinstance(item, Clothes): item_val = self.value_of_wearable(item) if item_val > self.value_of_wearable(clothes): if (best_gears_found['clothes'] == None or item_val > self.value_of_wearable( best_gears_found['clothes'])): best_gears_found['clothes'] = item best_gears_found_pos['clothes'] = check_pos best_gears_found_index['clothes'] = i elif isinstance(item, Shoes): item_val = self.value_of_wearable(item) if item_val > self.value_of_wearable(shoes): if (best_gears_found['shoes'] == None or item_val > self.value_of_wearable( best_gears_found['shoes'])): best_gears_found['shoes'] = item best_gears_found_pos['shoes'] = check_pos best_gears_found_index['shoes'] = i elif isinstance(item, Hat): item_val = self.value_of_wearable(item) if item_val > self.value_of_wearable(hat): if (best_gears_found['hat'] == None or item_val > self.value_of_wearable( best_gears_found['hat'])): best_gears_found['hat'] = item best_gears_found_pos['hat'] = check_pos best_gears_found_index['hat'] = i elif isinstance(item, Accessory): item_val = self.value_of_wearable(item) if item_val > self.value_of_wearable(accessory): if (best_gears_found['accessory'] == None or item_val > self.value_of_wearable( best_gears_found['accessory'])): best_gears_found['accessory'] = item best_gears_found_pos['accessory'] = check_pos best_gears_found_index['accessory'] = i gears_to_pickup = 0 for i, (k, v) in enumerate(best_gears_found.items()): item: Wearable = v if item != None: gears_to_pickup += 1 if isinstance(item, Weapon): self.logger.info("best gear: weapon, ATK {}".format( item.attack)) else: self.logger.info("best gear: {}".format( self.get_item_stats_str(item))) # analyze enemies, remove those that would kill us sorted_difficulty_enemies: list[Monster] = self.get_all_enemies( self.curr_pos) enemies: list[Monster] = [] dangerous_pos_hashes: set[int] = set() for enemy in sorted_difficulty_enemies: m_health = enemy.get_current_health() m_attack = enemy.get_attack() m_wep_attack = enemy.get_weapon().get_attack() m_defence = enemy.get_defense() p_wep_attack = weapon.get_attack() p_attack = self.my_player.get_attack() p_defence = self.my_player.get_defense() p_health = self.my_player.get_current_health() m_damage_per_turn = m_wep_attack * ((25 + m_attack) / 100) m_actual_damage_per_turn = math.ceil(m_damage_per_turn - min(p_defence, 0.8 * m_damage_per_turn)) p_damage_per_turn = p_wep_attack * ((75 + p_attack) / 100) p_actual_damage_per_turn = math.ceil(p_damage_per_turn - min(m_defence, 0.8 * p_damage_per_turn)) # self.logger.info("Monster at {} deals {} dmg/turn; atk:{}, p_def:".format(self.get_position_str(enemy.get_position()), m_actual_damage_per_turn, m_attack, p_defence)) # self.logger.info("Player deals {} dmg/turn".format(p_actual_damage_per_turn)) enemy_turns_to_win = p_health / m_actual_damage_per_turn my_turns_to_win = m_health / p_actual_damage_per_turn if (my_turns_to_win < enemy_turns_to_win - 1): enemies.append(enemy) else: if (enemy.position.manhattan_distance(self.curr_pos) > 2): dangerous_pos_hashes.add(self.hash_pos(enemy.position)) deltas = [(0, 1), (-1, 0), (0, -1), (1, 0)] # TODO: dont hardcode aggro range and the deltas to use if enemy.get_aggro_range() > 1: deltas = bfs_deltas[4] else: deltas = bfs_deltas[1] for delta in deltas: dx = delta[0] dy = delta[1] check_pos: Position = self.create_pos( enemy.position.x + dx, enemy.position.y + dy) # tile: Tile = self.player_board.get_tile_at(check_pos) dangerous_pos_hashes.add(self.hash_pos(check_pos)) if (len(enemies) == 0): self.logger.info("no killable enemies found, resting") self.role = roles.REST if (gears_to_pickup > 0): self.role = roles.PICK_UP_GEAR pass # if last_action is not None and last_action == "PICKUP": # self.memory.set_value("last_action", "EQUIP") # self.logger.info("Equipping item") # return CharacterDecision( # decision_type="EQUIP", # action_position=0, # action_index=self.my_player.get_free_inventory_index() # ) self.logger.info("Picking up maybe") tile_items = self.player_board.get_tile_at(self.curr_pos).items self.logger.info("Items on position: " + str(len(tile_items))) # if tile_items is not None or len(tile_items) > 0: # self.logger.info("Picking up item") # self.memory.set_value("last_action", "PICKUP") # return CharacterDecision( # decision_type="PICKUP", # action_position=None, # action_index=0 # ) self.logger.info("====ROLE " + self.role + "====") if (self.role == roles.REST): sp = self.my_player.get_spawn_point() path = self.get_path(self.curr_pos, sp, dangerous_pos_hashes) self.logger.info("Moving to " + self.get_position_str(path[0]) + " to get to spawn point to rest at " + self.get_position_str(sp)) path_index = min( max(self.my_player.get_speed(), 1) - 1, len(path) - 1) decision = decisions.move(path[path_index]) self.logger.info("Moving!") return decision elif (self.role == roles.PICK_UP_GEAR): target_pos = self.curr_pos target_index = 0 for i, (k, v) in enumerate(best_gears_found.items()): item: Wearable = v if item != None: target_pos = best_gears_found_pos[k] target_index = best_gears_found_index[k] break if (self.equal_pos(target_pos, self.curr_pos)): self.logger.info( "Picking up gear under player with index {}".format( target_index)) decision = decisions.pick_up_item(target_index) return decision self.logger.info("Moving to pick up gear at " + self.get_position_str(target_pos) + ", index: " + str(target_index)) path = self.get_path(self.curr_pos, target_pos, dangerous_pos_hashes) path_index = min( max(self.my_player.get_speed(), 1) - 1, len(path) - 1) decision = decisions.move(path[path_index]) return decision elif (self.role == roles.GAIN_XP): self.logger.info("Moving to enemy maybe") self.logger.info("Found " + str(len(enemies)) + " enemies") if enemies is None or len(enemies) > 0: enemy_pos = enemies[0].position self.logger.info("Closest enemy at " + self.get_position_str(enemy_pos)) if weapon.get_range() >= self.curr_pos.manhattan_distance( enemy_pos): self.logger.info("Enemy at " + self.get_position_str(enemy_pos) + " within range to attack") return decisions.attack_monster(enemies[0]) path = self.get_path(self.curr_pos, enemies[0].position, dangerous_pos_hashes) path_index = min( max(self.my_player.get_speed(), 1) - 1, len(path) - 1) next_pos = path[path_index] self.logger.info("Moving to enemy " + str(self.get_position_str(next_pos))) return decisions.move(next_pos) self.logger.info("Moving maybe") self.memory.set_value("last_action", "MOVE") move_pos = self.pick_open_spot_to_move() self.logger.info("MovePos: " + self.get_position_str(move_pos)) decision = decisions.move(move_pos) self.logger.info("Moving!") return decision
class Strategy: logger: Logger board: Board curr_pos: Position player_board: Board my_player: Player api: API game_state: GameState role: str def __init__(self, memory): self.memory = memory self.logger = logging.getLogger('strategy') self.logger.setLevel(logging.DEBUG) logging.basicConfig(level=logging.INFO) self.role = roles.GAIN_XP def make_decision(self, player_name: str, game_state: GameState) -> CharacterDecision: """ Parameters: player_name (string): The name of your player game_state (GameState): The current game state """ self.api = API(game_state, player_name) self.game_state = game_state self.my_player = game_state.get_all_players()[player_name] # self.board = game_state.get_pvp_board() self.player_board = game_state.get_board(player_name) self.curr_pos = self.my_player.get_position() self.logger.info("Version: 4.0") # Figure out role my_health = self.my_player.get_current_health() spawn_point = self.my_player.get_spawn_point() if my_health <= 10 or ( self.equal_pos(self.curr_pos, spawn_point) and my_health <= self.my_player.get_max_health() - 10): self.role = roles.GAIN_XP else: self.role = roles.GAIN_XP self.logger.info("Player at " + self.get_position_str(self.curr_pos) + " | Health: " + str(my_health) + " | XP: " + str(self.my_player.get_experience()) + " | Total XP: " + str(self.my_player.get_total_experience())) self.logger.info("ATK: {}, SPD: {}, DEF: {}".format( self.my_player.get_attack(), self.my_player.get_speed(), self.my_player.get_defense())) last_action, type = self.memory.get_value("last_action", str) last_role, type = self.memory.get_value("role", str) self.memory.set_value("role", "test_val") self.logger.info("last action " + str(last_action)) self.logger.info("last role " + str(last_role)) ### store our current stats and inven ### weapon: Weapon = self.my_player.get_weapon( ) # should always be index 0 hat: Hat = self.my_player.get_hat() # always index 1 shoes: Shoes = self.my_player.get_shoes() clothes: Clothes = self.my_player.get_clothes() # always index 2 accessory: Accessory = self.my_player.get_accessory() self.logger.info("Curr Weapon: {}".format( self.get_item_stats_str(weapon))) self.logger.info("Curr Clothes: {}".format( self.get_item_stats_str(clothes))) self.logger.info("Curr Hat: {}".format(self.get_item_stats_str(hat))) self.logger.info("Curr Shoes: {}".format( self.get_item_stats_str(shoes))) self.logger.info("Curr Accessory: {}".format( self.get_item_stats_str(accessory))) # if inventory has better weapon, equip it inven: list[Item] = self.my_player.get_inventory() self.logger.info("Have {} inventory items".format(len(inven))) best_wep_to_equip: Weapon = None best_wep_to_equip_index: int = None best_gear_to_equip: Wearable = None best_gear_to_equip_index: int = None for i, item in enumerate(inven): self.logger.info("Inven {} - {} - stats: {}".format( i, item, self.get_item_stats_str(item))) if isinstance(item, Consumable): self.logger.info("Equipping consumable") return decisions.equip_item(i) elif isinstance(item, Weapon): item_val = self.value_of_wearable(item) if item_val > self.value_of_wearable(weapon): self.logger.info( "Equipping weapon at index {} with stats: {}".format( i, self.get_item_stats_str(item))) return decisions.equip_item(i) elif item_val < self.value_of_wearable(weapon): self.logger.info("Dropping weapon at {}".format(i)) return decisions.drop_item(i) elif isinstance(item, Clothes): item_val = self.value_of_wearable(item) if (item_val > self.value_of_wearable(clothes)): self.logger.info( "Equipping clothes at index {} with stats: {}".format( i, self.get_item_stats_str(item))) return decisions.equip_item(i) elif item_val < self.value_of_wearable(clothes): self.logger.info("Dropping clothes at {}".format(i)) return decisions.drop_item(i) elif isinstance(item, Hat): item_val = self.value_of_wearable(item) if (item_val > self.value_of_wearable(hat)): self.logger.info( "Equipping hat at index {} with stats: {}".format( i, self.get_item_stats_str(item))) return decisions.equip_item(i) elif item_val < self.value_of_wearable(hat): self.logger.info("Dropping hat at {}".format(i)) return decisions.drop_item(i) elif isinstance(item, Shoes): item_val = self.value_of_wearable(item) if (item_val > self.value_of_wearable(shoes)): self.logger.info( "Equipping shoes at index {} with stats: {}".format( i, self.get_item_stats_str(item))) return decisions.equip_item(i) elif item_val < self.value_of_wearable(shoes): self.logger.info("Dropping shoes at {}".format(i)) return decisions.drop_item(i) elif isinstance(item, Accessory): item_val = self.value_of_wearable(item) if (item_val > self.value_of_wearable(accessory)): self.logger.info( "Equipping accessory at index {} with stats: {}". format(i, self.get_item_stats_str(item))) return decisions.equip_item(i) elif item_val < self.value_of_wearable(accessory): self.logger.info("Dropping accessory at {}".format(i)) return decisions.drop_item(i) # BFS search around for stuff deltas_128 = bfs_deltas[128] best_gears_found: dict[str, Wearable] = { 'weapon': None, 'clothes': None, 'shoes': None, 'hat': None, 'accessory': None, 'con': None, } best_gears_found_pos: dict[str, Position] = { 'weapon': None, 'clothes': None, 'shoes': None, 'hat': None, 'accessory': None, 'con': None, } best_gears_found_index: dict[str, Position] = { 'weapon': None, 'clothes': None, 'shoes': None, 'hat': None, 'accessory': None, 'con': None, } for delta in deltas_128: dx = delta[0] dy = delta[1] check_pos = self.create_pos(self.curr_pos.x + dx, self.curr_pos.y + dy) # self.logger.info("Checking " + self.get_position_str(check_pos)) if (check_pos.x >= self.player_board.width or check_pos.x < 0 or check_pos.y < 0 or check_pos.y >= self.player_board.height): continue # self.logger.info("in map") tile: Tile = self.player_board.get_tile_at(check_pos) items_on_tile = tile.get_items() # search for better items for i, item in enumerate(items_on_tile): self.logger.info("At " + self.get_position_str(check_pos) + ", item - " + self.get_item_stats_str(item)) if isinstance(item, Consumable): con: Consumable = item if (con.effect.turns_left > 4): best_gears_found['con'] = con best_gears_found_index['con'] = i best_gears_found_pos['con'] = check_pos elif isinstance(item, Wearable): time_to_delete = item.turns_to_deletion if (self.curr_pos.manhattan_distance(check_pos) >= time_to_delete - 2): continue if isinstance(item, Weapon): self.logger.info("Found weapon") # dont pick up weapons that take too long to retrieve # best weapon to pickup is one that deals more damage, and more damage than all weapons on map that are found item_val = self.value_of_wearable(item) if (item_val > self.value_of_wearable(weapon)): if (best_gears_found['weapon'] == None or item_val > self.value_of_wearable( best_gears_found['weapon'])): best_gears_found['weapon'] = item best_gears_found_pos['weapon'] = check_pos best_gears_found_index['weapon'] = i elif isinstance(item, Clothes): item_val = self.value_of_wearable(item) if item_val > self.value_of_wearable(clothes): if (best_gears_found['clothes'] == None or item_val > self.value_of_wearable( best_gears_found['clothes'])): best_gears_found['clothes'] = item best_gears_found_pos['clothes'] = check_pos best_gears_found_index['clothes'] = i elif isinstance(item, Shoes): item_val = self.value_of_wearable(item) if item_val > self.value_of_wearable(shoes): if (best_gears_found['shoes'] == None or item_val > self.value_of_wearable( best_gears_found['shoes'])): best_gears_found['shoes'] = item best_gears_found_pos['shoes'] = check_pos best_gears_found_index['shoes'] = i elif isinstance(item, Hat): item_val = self.value_of_wearable(item) if item_val > self.value_of_wearable(hat): if (best_gears_found['hat'] == None or item_val > self.value_of_wearable( best_gears_found['hat'])): best_gears_found['hat'] = item best_gears_found_pos['hat'] = check_pos best_gears_found_index['hat'] = i elif isinstance(item, Accessory): item_val = self.value_of_wearable(item) if item_val > self.value_of_wearable(accessory): if (best_gears_found['accessory'] == None or item_val > self.value_of_wearable( best_gears_found['accessory'])): best_gears_found['accessory'] = item best_gears_found_pos['accessory'] = check_pos best_gears_found_index['accessory'] = i gears_to_pickup = 0 for i, (k, v) in enumerate(best_gears_found.items()): item: Wearable = v if item != None: gears_to_pickup += 1 if isinstance(item, Weapon): self.logger.info("best gear: weapon, ATK {}".format( item.attack)) else: self.logger.info("best gear: {}".format( self.get_item_stats_str(item))) # analyze enemies, remove those that would kill us sorted_difficulty_enemies: list[Monster] = self.get_all_enemies( self.curr_pos) enemies: list[Monster] = [] dangerous_pos_hashes: set[int] = set() for enemy in sorted_difficulty_enemies: m_health = enemy.get_current_health() m_attack = enemy.get_attack() m_wep_attack = enemy.get_weapon().get_attack() m_defence = enemy.get_defense() p_wep_attack = weapon.get_attack() p_attack = self.my_player.get_attack() p_defence = self.my_player.get_defense() p_health = self.my_player.get_current_health() m_damage_per_turn = m_wep_attack * ((25 + m_attack) / 100) m_actual_damage_per_turn = math.ceil(m_damage_per_turn - min(p_defence, 0.8 * m_damage_per_turn)) p_damage_per_turn = p_wep_attack * ((75 + p_attack) / 100) p_actual_damage_per_turn = math.ceil(p_damage_per_turn - min(m_defence, 0.8 * p_damage_per_turn)) # self.logger.info("Monster at {} deals {} dmg/turn; atk:{}, p_def:".format(self.get_position_str(enemy.get_position()), m_actual_damage_per_turn, m_attack, p_defence)) # self.logger.info("Player deals {} dmg/turn".format(p_actual_damage_per_turn)) enemy_turns_to_win = p_health / m_actual_damage_per_turn my_turns_to_win = m_health / p_actual_damage_per_turn if (my_turns_to_win < enemy_turns_to_win - 1): enemies.append(enemy) else: if (enemy.position.manhattan_distance(self.curr_pos) > 2): dangerous_pos_hashes.add(self.hash_pos(enemy.position)) deltas = [(0, 1), (-1, 0), (0, -1), (1, 0)] # TODO: dont hardcode aggro range and the deltas to use if enemy.get_aggro_range() > 1: deltas = bfs_deltas[4] else: deltas = bfs_deltas[1] for delta in deltas: dx = delta[0] dy = delta[1] check_pos: Position = self.create_pos( enemy.position.x + dx, enemy.position.y + dy) # tile: Tile = self.player_board.get_tile_at(check_pos) dangerous_pos_hashes.add(self.hash_pos(check_pos)) if (len(enemies) == 0): self.logger.info("no killable enemies found, resting") self.role = roles.REST if (gears_to_pickup > 0): self.role = roles.PICK_UP_GEAR pass # if last_action is not None and last_action == "PICKUP": # self.memory.set_value("last_action", "EQUIP") # self.logger.info("Equipping item") # return CharacterDecision( # decision_type="EQUIP", # action_position=0, # action_index=self.my_player.get_free_inventory_index() # ) self.logger.info("Picking up maybe") tile_items = self.player_board.get_tile_at(self.curr_pos).items self.logger.info("Items on position: " + str(len(tile_items))) # if tile_items is not None or len(tile_items) > 0: # self.logger.info("Picking up item") # self.memory.set_value("last_action", "PICKUP") # return CharacterDecision( # decision_type="PICKUP", # action_position=None, # action_index=0 # ) self.logger.info("====ROLE " + self.role + "====") if (self.role == roles.REST): sp = self.my_player.get_spawn_point() path = self.get_path(self.curr_pos, sp, dangerous_pos_hashes) self.logger.info("Moving to " + self.get_position_str(path[0]) + " to get to spawn point to rest at " + self.get_position_str(sp)) path_index = min( max(self.my_player.get_speed(), 1) - 1, len(path) - 1) decision = decisions.move(path[path_index]) self.logger.info("Moving!") return decision elif (self.role == roles.PICK_UP_GEAR): target_pos = self.curr_pos target_index = 0 for i, (k, v) in enumerate(best_gears_found.items()): item: Wearable = v if item != None: target_pos = best_gears_found_pos[k] target_index = best_gears_found_index[k] break if (self.equal_pos(target_pos, self.curr_pos)): self.logger.info( "Picking up gear under player with index {}".format( target_index)) decision = decisions.pick_up_item(target_index) return decision self.logger.info("Moving to pick up gear at " + self.get_position_str(target_pos) + ", index: " + str(target_index)) path = self.get_path(self.curr_pos, target_pos, dangerous_pos_hashes) path_index = min( max(self.my_player.get_speed(), 1) - 1, len(path) - 1) decision = decisions.move(path[path_index]) return decision elif (self.role == roles.GAIN_XP): self.logger.info("Moving to enemy maybe") self.logger.info("Found " + str(len(enemies)) + " enemies") if enemies is None or len(enemies) > 0: enemy_pos = enemies[0].position self.logger.info("Closest enemy at " + self.get_position_str(enemy_pos)) if weapon.get_range() >= self.curr_pos.manhattan_distance( enemy_pos): self.logger.info("Enemy at " + self.get_position_str(enemy_pos) + " within range to attack") return decisions.attack_monster(enemies[0]) path = self.get_path(self.curr_pos, enemies[0].position, dangerous_pos_hashes) path_index = min( max(self.my_player.get_speed(), 1) - 1, len(path) - 1) next_pos = path[path_index] self.logger.info("Moving to enemy " + str(self.get_position_str(next_pos))) return decisions.move(next_pos) self.logger.info("Moving maybe") self.memory.set_value("last_action", "MOVE") move_pos = self.pick_open_spot_to_move() self.logger.info("MovePos: " + self.get_position_str(move_pos)) decision = decisions.move(move_pos) self.logger.info("Moving!") return decision def get_all_enemies(self, pos: Position): enemies = [] # player: Player = self.my_player # for k in game_state.monster_names: # monster: Monster = game_state.monster_names[k] # enemies.append(monster) all_monsters: list[Monster] = self.game_state.get_monsters_on_board( self.curr_pos.get_board_id()) for monster in all_monsters: if monster.get_current_health() > 0: enemies.append(monster) # sort by level then distance enemies = sorted( enemies, key=lambda m: (m.position.manhattan_distance(pos), 9999999 - m.get_level())) return enemies # for delta in deltas: # check_pos = pos.create(pos.x + delta[0], pos.y + delta[1], pos.get_board_id()) # tile: Tile = self.player_board.get_tile_at(check_pos) # feel free to write as many helper functions as you need! def find_position_to_move(self, player: Player, destination: Position) -> Position: path = self.api.find_path(player.get_position(), destination) # path can be empty if player.get_position() == destination if len(path) == 0: return player.get_position() pos = None if len(path) < player.get_speed(): pos = path[-1] else: pos = path[player.get_speed() - 1] return pos def get_position_str(self, pos: Position): return str(pos.get_board_id()) + " | " + str(pos.get_x()) + ", " + str( pos.get_y()) # greedy for now def get_path(self, start: Position, end: Position, avoid_hashes): deltas = [(0, 1), (-1, 0), (0, -1), (1, 0)] # deltas = bfs_deltas[1024] lowest = start.manhattan_distance(end) path = [start] queue = deque([start]) visited = { } # map node to its next node, so start maps to next_node, 2nd to last node maps to end start_hash = self.hash_pos(start) visited[start_hash] = None while (len(queue) > 0): pos = queue.popleft() # reach end, return next node curr_hash = self.hash_pos(pos) if self.equal_pos(pos, end): # backtrack bt_hash = self.hash_pos(pos) bt_path = deque([]) while bt_hash in visited: prev_node_hash = visited[bt_hash] next_node = self.read_pos_hash(bt_hash) bt_path.appendleft(next_node) if prev_node_hash == self.hash_pos(start): self.logger.info( "Bfs path start {} next {} end {}".format( self.get_position_str(start), self.get_position_str(next_node), self.get_position_str(end))) return bt_path bt_hash = prev_node_hash break for delta in deltas: dx = delta[0] dy = delta[1] check_pos: Position = self.create_pos(pos.x + dx, pos.y + dy) tile: Tile = self.player_board.get_tile_at(check_pos) if tile.type == "BLANK": check_hash = self.hash_pos(check_pos) if check_hash not in visited and check_hash not in avoid_hashes: queue.append(check_pos) visited[check_hash] = curr_hash else: pass # dist = check_pos.manhattan_distance(end) # if dist < lowest: # path[0] = check_pos # lowest = dist self.logger.info("exhausted bfs...") return path def read_pos_hash(self, hash: int): return self.create_pos(hash // 10000, hash % 10000) def hash_pos(self, pos: Position): return pos.x * 10000 + pos.y def pick_open_spot_to_move(self) -> Position: deltas = [(0, 1), (-1, 0), (0, -1), (1, 0)] movable_deltas = [] for delta in deltas: dx = delta[0] dy = delta[1] pos: Position = self.create_pos(self.curr_pos.x + dx, self.curr_pos.y + dy) tile: Tile = self.player_board.get_tile_at(pos) if tile.type == "BLANK": movable_deltas.append(delta) if (len(movable_deltas) == 0): return self.curr_pos f_delta = movable_deltas[random.randint(0, len(movable_deltas) - 1)] return self.curr_pos.create(self.curr_pos.x + f_delta[0], self.curr_pos.y + f_delta[1], self.curr_pos.get_board_id()) def create_pos(self, x, y): pos: Position = self.curr_pos.create(x, y, self.curr_pos.get_board_id()) return pos def equal_pos(self, pos1: Position, pos2: Position): return pos1.x == pos2.x and pos1.y == pos2.y and pos1.get_board_id( ) == pos2.get_board_id() def get_item_stats_str(self, item: Item): if (isinstance(item, Weapon)): return "Weapon: ATK {atk}, RANGE: {range}, SPLASH: {splash}, {sts}".format( atk=item.get_attack(), range=item.get_range(), splash=item.get_splash_radius(), sts=self.stats_str(item)) elif (isinstance(item, Clothes)): # item.stats.percent_speed_change = kwargs['percent_speed_change'] # item.stats.percent_health_change = kwargs['percent_health_change'] # item.stats.percent_experience_change = kwargs['percent_experience_change'] # item.stats.percent_attack_change = kwargs['percent_attack_change'] # item.stats.percent_defense_change = kwargs['percent_defense_change'] return "Clothes: Stats {}".format(self.stats_str(item)) elif (isinstance(item, Accessory)): return "Accessory: Stats {}".format(self.stats_str(item)) elif (isinstance(item, Hat)): return "Hat: Stats {}".format(self.stats_str(item)) elif (isinstance(item, Shoes)): return "Shoes: Stats {}".format(self.stats_str(item)) elif (isinstance(item, Consumable)): return "Con: Stats {}".format( self.stats_str_consumable(item.effect)) return "smth else" def stats_str(self, item: Item): return 'fgpt {}, spd {}, hp {}, xp {}, atk {}, def {}, %atk {}, %def {}, %hp {}'.format( item.stats.flat_regen_per_turn, item.stats.flat_speed_change, item.stats.flat_health_change, item.stats.flat_experience_change, item.stats.flat_attack_change, item.stats.flat_defense_change, item.stats.percent_attack_change, item.stats.percent_defense_change, item.stats.percent_health_change) def stats_str_consumable(self, stats: TempStatusModifier): return 'fgpt {}, spd {}, hp {}, xp {}, atk {}, def {}, %atk {}, %def {}, %hp {}, turns left {}'.format( stats.flat_regen_per_turn, stats.flat_speed_change, stats.flat_health_change, stats.flat_experience_change, stats.flat_attack_change, stats.flat_defense_change, stats.percent_attack_change, stats.percent_defense_change, stats.percent_health_change, stats.turns_left) def value_of_wearable(self, item: Item): if isinstance(item, Wearable): replacedItem = None if (isinstance(item, Weapon)): return item.get_attack() * item.stats.percent_attack_change elif (isinstance(item, Clothes)): replacedItem = self.my_player.get_clothes() elif (isinstance(item, Accessory)): replacedItem = self.my_player.get_accessory() elif (isinstance(item, Hat)): replacedItem = self.my_player.get_hat() elif (isinstance(item, Shoes)): replacedItem = self.my_player.get_shoes() stats = item.stats # p_health_change = stats.percent_health_change * (self.my_player.get_max_health() - replacedItem.stats.flat_health_change) return stats.flat_defense_change * 30 + stats.flat_experience_change * 10 + stats.flat_health_change + stats.flat_regen_per_turn * 45 + stats.percent_attack_change * 5 + stats.flat_speed_change * 60 return 0