Esempio n. 1
0
    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
Esempio n. 2
0
        def send_decision():
            payload = request.get_data()

            player_turn = player_pb2.PlayerTurn()
            player_turn.ParseFromString(payload)

            app.logger.info(
                f"Received playerTurn for player: {player_turn.player_name}, turn: {player_turn.game_state.state_id}"
            )

            game_state = GameState(player_turn.game_state)
            player_name = player_turn.player_name

            response_msg = character_pb2.CharacterDecision()

            try:
                decision = self.strategy.make_decision(player_name, game_state)
            except Exception as err:
                app.logger.info("Exception making decision:")
                traceback.print_exc()
                decision = None

            if decision is not None:
                response_msg = decision.build_proto_class_character_decision()
            else:
                # Build NONE decision if contestant code failed
                response_msg.decision_type = character_pb2.NONE
                response_msg.index = -1

            if self.debug:
                self.atomicInt.increment()

            app.logger.info("Sending playerDecision")

            return response_msg.SerializeToString()
    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
        """
Esempio n. 4
0
    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
Esempio n. 5
0
    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)
Esempio n. 6
0
    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