From c2eba28f9e1814daccf64d7c5843317c5fa75197 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 20 Jun 2024 01:01:22 +0100 Subject: [PATCH] Precommit fixes --- clashroyalebuildabot/__init__.py | 20 +++++--- clashroyalebuildabot/bot/bot.py | 30 ++++++------ .../bot/example/custom_action.py | 22 ++++----- .../bot/example/custom_bot.py | 6 +-- .../two_six_hog_cycle_action.py | 22 ++++----- clashroyalebuildabot/constants.py | 27 ---------- clashroyalebuildabot/{state => }/debugger.py | 0 .../{state => detectors}/__init__.py | 2 - .../{state => detectors}/card_detector.py | 0 .../{state => detectors}/detector.py | 22 ++++----- .../{state => detectors}/number_detector.py | 2 +- .../{state => detectors}/onnx_detector.py | 0 .../detectors/screen_detector.py | 49 +++++++++++++++++++ .../{state => detectors}/side_detector.py | 2 +- .../{state => detectors}/unit_detector.py | 4 +- clashroyalebuildabot/namespaces/__init__.py | 4 +- clashroyalebuildabot/namespaces/cards.py | 5 +- clashroyalebuildabot/namespaces/screens.py | 2 +- clashroyalebuildabot/namespaces/state.py | 2 +- clashroyalebuildabot/namespaces/units.py | 2 +- clashroyalebuildabot/state/screen_detector.py | 49 ------------------- 21 files changed, 120 insertions(+), 152 deletions(-) rename clashroyalebuildabot/{state => }/debugger.py (100%) rename clashroyalebuildabot/{state => detectors}/__init__.py (89%) rename clashroyalebuildabot/{state => detectors}/card_detector.py (100%) rename clashroyalebuildabot/{state => detectors}/detector.py (63%) rename clashroyalebuildabot/{state => detectors}/number_detector.py (98%) rename clashroyalebuildabot/{state => detectors}/onnx_detector.py (100%) create mode 100644 clashroyalebuildabot/detectors/screen_detector.py rename clashroyalebuildabot/{state => detectors}/side_detector.py (89%) rename clashroyalebuildabot/{state => detectors}/unit_detector.py (95%) delete mode 100644 clashroyalebuildabot/state/screen_detector.py diff --git a/clashroyalebuildabot/__init__.py b/clashroyalebuildabot/__init__.py index 6c29d12..7478486 100644 --- a/clashroyalebuildabot/__init__.py +++ b/clashroyalebuildabot/__init__.py @@ -1,18 +1,21 @@ # Exports for clashroyalebuildabot from . import constants +from . import debugger from .bot import Action from .bot import Bot from .bot import RandomBot from .bot import TwoSixHogCycle +from .detectors import CardDetector +from .detectors import Detector +from .detectors import NumberDetector +from .detectors import OnnxDetector +from .detectors import ScreenDetector +from .detectors import UnitDetector +from .emulator import Emulator from .namespaces import Cards +from .namespaces import Screens +from .namespaces import State from .namespaces import Units -from .screen import Screen -from .state import CardDetector -from .state import Detector -from .state import NumberDetector -from .state import OnnxDetector -from .state import ScreenDetector -from .state import UnitDetector __all__ = [ "RandomBot", @@ -20,13 +23,14 @@ "constants", "Cards", "Units", + "State", "Detector", "OnnxDetector", "ScreenDetector", "NumberDetector", "UnitDetector", "CardDetector", - "Screen", + "Emulator", "Action", "Bot", ] diff --git a/clashroyalebuildabot/bot/bot.py b/clashroyalebuildabot/bot/bot.py index c8792a2..71a348c 100644 --- a/clashroyalebuildabot/bot/bot.py +++ b/clashroyalebuildabot/bot/bot.py @@ -12,13 +12,13 @@ from clashroyalebuildabot.constants import DISPLAY_HEIGHT from clashroyalebuildabot.constants import LEFT_PRINCESS_TILES from clashroyalebuildabot.constants import RIGHT_PRINCESS_TILES -from clashroyalebuildabot.constants import SCREEN_CONFIG from clashroyalebuildabot.constants import TILE_HEIGHT from clashroyalebuildabot.constants import TILE_INIT_X from clashroyalebuildabot.constants import TILE_INIT_Y from clashroyalebuildabot.constants import TILE_WIDTH -from clashroyalebuildabot.screen import Screen -from clashroyalebuildabot.state.detector import Detector +from clashroyalebuildabot.detectors.detector import Detector +from clashroyalebuildabot.emulator import Emulator +from clashroyalebuildabot.namespaces import Screens class Bot: @@ -29,7 +29,7 @@ def __init__( self.action_class = action_class self.auto_start = auto_start self.debug = debug - self.screen = Screen() + self.emulator = Emulator() self.detector = Detector(cards, debug=self.debug) self.state = None @@ -59,9 +59,9 @@ def _get_card_centre(card_n): def _get_valid_tiles(self): tiles = ALLY_TILES - if self.state["numbers"]["left_enemy_princess_hp"]["number"] == 0: + if self.state.numbers["left_enemy_princess_hp"]["number"] == 0: tiles += LEFT_PRINCESS_TILES - if self.state["numbers"]["right_enemy_princess_hp"]["number"] == 0: + if self.state.numbers["right_enemy_princess_hp"]["number"] == 0: tiles += RIGHT_PRINCESS_TILES return tiles @@ -71,9 +71,9 @@ def get_actions(self): all_tiles = ALLY_TILES + LEFT_PRINCESS_TILES + RIGHT_PRINCESS_TILES valid_tiles = self._get_valid_tiles() actions = [] - for i in self.state["ready"]: - card = self.state["cards"][i + 1] - if int(self.state["numbers"]["elixir"]["number"]) < card.cost: + for i in self.state.ready: + card = self.state.cards[i + 1] + if int(self.state.numbers["elixir"]["number"]) < card.cost: continue tiles = all_tiles if card.target_anywhere else valid_tiles @@ -85,12 +85,10 @@ def get_actions(self): def set_state(self): try: - screenshot = self.screen.take_screenshot() + screenshot = self.emulator.take_screenshot() self.state = self.detector.run(screenshot) - if self.auto_start and self.state["screen"] != "in_game": - self.screen.click( - *SCREEN_CONFIG[self.state["screen"]]["click_coordinates"] - ) + if self.auto_start and self.state.screen != Screens.IN_GAME: + self.emulator.click(*self.state.screen.click_xy) time.sleep(2) except Exception as e: logger.error(f"Error occurred while taking screenshot: {e}") @@ -98,5 +96,5 @@ def set_state(self): def play_action(self, action): card_centre = self._get_card_centre(action.index) tile_centre = self._get_tile_centre(action.tile_x, action.tile_y) - self.screen.click(*card_centre) - self.screen.click(*tile_centre) + self.emulator.click(*card_centre) + self.emulator.click(*tile_centre) diff --git a/clashroyalebuildabot/bot/example/custom_action.py b/clashroyalebuildabot/bot/example/custom_action.py index 486459e..02bcac8 100644 --- a/clashroyalebuildabot/bot/example/custom_action.py +++ b/clashroyalebuildabot/bot/example/custom_action.py @@ -30,10 +30,10 @@ def _calculate_spell_score(self, units, radius, min_to_hit): return [1 if hit_units >= min_to_hit else 0, hit_units, max_distance] def _calculate_unit_score(self, state, tile_x_conditions, score_if_met): - score = [0.5] if state["numbers"]["elixir"]["number"] == 10 else [0] + score = [0.5] if state.numbers["elixir"]["number"] == 10 else [0] for unit in ( unit - for v in state["units"]["enemy"].values() + for v in state.units["enemy"].values() for unit in v["positions"] ): tile_x, tile_y = unit["tile_xy"] @@ -54,10 +54,10 @@ def _calculate_knight_score(self, state): ) def _calculate_minions_score(self, state): - score = [0.5] if state["numbers"]["elixir"]["number"] == 10 else [0] + score = [0.5] if state.numbers["elixir"]["number"] == 10 else [0] for unit in ( unit - for v in state["units"]["enemy"].values() + for v in state.units["enemy"].values() for unit in v["positions"] ): tile_x, tile_y = unit["tile_xy"] @@ -70,13 +70,11 @@ def _calculate_minions_score(self, state): def _calculate_fireball_score(self, state): return self._calculate_spell_score( - state["units"], radius=2.5, min_to_hit=3 + state.units, radius=2.5, min_to_hit=3 ) def _calculate_arrows_score(self, state): - return self._calculate_spell_score( - state["units"], radius=4, min_to_hit=5 - ) + return self._calculate_spell_score(state.units, radius=4, min_to_hit=5) def _calculate_archers_score(self, state): return self._calculate_unit_score( @@ -91,10 +89,10 @@ def _calculate_archers_score(self, state): def _calculate_giant_score(self, state): score = [0] left_hp, right_hp = ( - state["numbers"][f"{direction}_enemy_princess_hp"]["number"] + state.numbers[f"{direction}_enemy_princess_hp"]["number"] for direction in ["left", "right"] ) - if state["numbers"]["elixir"]["number"] == 10: + if state.numbers["elixir"]["number"] == 10: if self.tile_x == 3: score = [1, self.tile_y, left_hp != -1, left_hp <= right_hp] elif self.tile_x == 14: @@ -103,7 +101,7 @@ def _calculate_giant_score(self, state): def _calculate_minipekka_score(self, state): left_hp, right_hp = ( - state["numbers"][f"{direction}_enemy_princess_hp"]["number"] + state.numbers[f"{direction}_enemy_princess_hp"]["number"] for direction in ["left", "right"] ) if self.tile_x in [3, 14]: @@ -117,7 +115,7 @@ def _calculate_minipekka_score(self, state): def _calculate_musketeer_score(self, state): for unit in ( unit - for v in state["units"]["enemy"].values() + for v in state.units["enemy"].values() for unit in v["positions"] ): distance = self._distance( diff --git a/clashroyalebuildabot/bot/example/custom_bot.py b/clashroyalebuildabot/bot/example/custom_bot.py index b876958..0fa0119 100644 --- a/clashroyalebuildabot/bot/example/custom_bot.py +++ b/clashroyalebuildabot/bot/example/custom_bot.py @@ -35,7 +35,7 @@ def __init__(self, cards, debug=False): def _preprocess(self): for side in ["ally", "enemy"]: - for k, v in self.state["units"][side].items(): + for k, v in self.state.units[side].items(): for unit in v["positions"]: bbox = unit["bounding_box"] bbox[0] *= self.scale_x @@ -76,9 +76,9 @@ def step(self): if self.end_of_game_clicked: self._end_of_game() - old_screen = self.state["screen"] if self.state is not None else None + old_screen = self.state.screen if self.state is not None else None self.set_state() - new_screen = self.state["screen"] + new_screen = self.state.screen if new_screen != old_screen: logger.debug(f"New screen state: {new_screen}") diff --git a/clashroyalebuildabot/bot/two_six_hog_cycle/two_six_hog_cycle_action.py b/clashroyalebuildabot/bot/two_six_hog_cycle/two_six_hog_cycle_action.py index 95144de..b716c05 100644 --- a/clashroyalebuildabot/bot/two_six_hog_cycle/two_six_hog_cycle_action.py +++ b/clashroyalebuildabot/bot/two_six_hog_cycle/two_six_hog_cycle_action.py @@ -16,7 +16,7 @@ def _calculate_hog_rider_score(self, state): Place hog rider on the bridge as high up as possible Try to target the lowest hp tower """ - for v in state["units"]["enemy"].values(): + for v in state.units["enemy"].values(): for unit in v["positions"]: tile_x, tile_y = unit["tile_xy"] if self.tile_y < tile_y <= 14: @@ -28,9 +28,9 @@ def _calculate_hog_rider_score(self, state): ): return [0] - if state["numbers"]["elixir"]["number"] >= 7: + if state.numbers["elixir"]["number"] >= 7: left_hp, right_hp = [ - state["numbers"][f"{direction}_enemy_princess_hp"]["number"] + state.numbers[f"{direction}_enemy_princess_hp"]["number"] for direction in ["left", "right"] ] if self.tile_x == 3: @@ -49,7 +49,7 @@ def _calculate_cannon_score(self, state): return [0] for side in ["ally", "enemy"]: - for v in state["units"][side].values(): + for v in state.units[side].values(): for unit in v["positions"]: tile_y = unit["tile_xy"][1] if v["transport"] == "ground" and tile_y >= 10: @@ -64,7 +64,7 @@ def _calculate_musketeer_score(self, state): That should be just within her range and not too close to the enemy """ for side in ["ally", "enemy"]: - for v in state["units"][side].values(): + for v in state.units[side].values(): for unit in v["positions"]: tile_y = unit["tile_xy"][1] if v["transport"] == "air" and self.tile_y == tile_y - 7: @@ -81,7 +81,7 @@ def _calculate_ice_golem_score(self, state): return [0] for side in ["ally", "enemy"]: - for v in state["units"][side].values(): + for v in state.units[side].values(): for unit in v["positions"]: tile_x, tile_y = unit["tile_xy"] if not (18 >= tile_y >= 15) or v["transport"] != "ground": @@ -102,7 +102,7 @@ def _calculate_ice_spirit_score(self, state): return [0] for side in ["ally", "enemy"]: - for v in state["units"][side].values(): + for v in state.units[side].values(): for unit in v["positions"]: tile_x, tile_y = unit["tile_xy"] if not (18 >= tile_y >= 15) or v["transport"] != "ground": @@ -149,9 +149,8 @@ def _calculate_log_score(self, state): """ Calculate the score for the log card """ - units = state["units"] score = [0] - for v in units["enemy"].values(): + for v in state.units["enemy"].values(): for unit in v["positions"]: tile_x, tile_y = unit["tile_xy"] if tile_y <= 8 and v["transport"] == "ground": @@ -164,8 +163,7 @@ def _calculate_fireball_score(self, state): """ Play the fireball card if it will hit flying units """ - units = state["units"] - for v in units["enemy"].values(): + for v in state.units["enemy"].values(): for unit in v["positions"]: tile_x, tile_y = unit["tile_xy"] if ( @@ -176,7 +174,7 @@ def _calculate_fireball_score(self, state): return [1] return self._calculate_spell_score( - state["units"], radius=2.5, min_to_hit=3 + state.units, radius=2.5, min_to_hit=3 ) def calculate_score(self, state): diff --git a/clashroyalebuildabot/constants.py b/clashroyalebuildabot/constants.py index 0cca8df..3b8a916 100644 --- a/clashroyalebuildabot/constants.py +++ b/clashroyalebuildabot/constants.py @@ -1,7 +1,5 @@ import os -from loguru import logger - from clashroyalebuildabot.namespaces import Units # Directories @@ -20,31 +18,6 @@ SCREENSHOT_WIDTH = 368 SCREENSHOT_HEIGHT = 652 -# Screen ID -CHEST_SIZE = 62 -CHEST_X = 0 -CHEST_Y = 590 -OK_X = 143 -OK_Y = 558 -OK_WIDTH = 82 -OK_HEIGHT = 30 -SCREEN_CONFIG = { - "lobby": { - "bbox": (CHEST_X, CHEST_Y, CHEST_X + CHEST_SIZE, CHEST_Y + CHEST_SIZE), - "click_coordinates": (220, 830), - }, - "end_of_game": { - "bbox": (OK_X, OK_Y, OK_X + OK_WIDTH, OK_Y + OK_HEIGHT), - "click_coordinates": (360, 1125), - }, -} - -# Log click coordinates for screen configurations -for screen, config in SCREEN_CONFIG.items(): - logger.info( - f"Screen: {screen}, Click coordinates: {config['click_coordinates']}" - ) - # Playable tiles TILE_HEIGHT = 27.6 TILE_WIDTH = 34 diff --git a/clashroyalebuildabot/state/debugger.py b/clashroyalebuildabot/debugger.py similarity index 100% rename from clashroyalebuildabot/state/debugger.py rename to clashroyalebuildabot/debugger.py diff --git a/clashroyalebuildabot/state/__init__.py b/clashroyalebuildabot/detectors/__init__.py similarity index 89% rename from clashroyalebuildabot/state/__init__.py rename to clashroyalebuildabot/detectors/__init__.py index 383afba..5ac1ea9 100644 --- a/clashroyalebuildabot/state/__init__.py +++ b/clashroyalebuildabot/detectors/__init__.py @@ -1,6 +1,5 @@ # Exports for state submodule from .card_detector import CardDetector -from .debugger import Debugger from .detector import Detector from .number_detector import NumberDetector from .onnx_detector import OnnxDetector @@ -14,5 +13,4 @@ "NumberDetector", "UnitDetector", "CardDetector", - "Debugger", ] diff --git a/clashroyalebuildabot/state/card_detector.py b/clashroyalebuildabot/detectors/card_detector.py similarity index 100% rename from clashroyalebuildabot/state/card_detector.py rename to clashroyalebuildabot/detectors/card_detector.py diff --git a/clashroyalebuildabot/state/detector.py b/clashroyalebuildabot/detectors/detector.py similarity index 63% rename from clashroyalebuildabot/state/detector.py rename to clashroyalebuildabot/detectors/detector.py index 68e9a35..e4e1abf 100644 --- a/clashroyalebuildabot/state/detector.py +++ b/clashroyalebuildabot/detectors/detector.py @@ -1,11 +1,12 @@ import os from clashroyalebuildabot.constants import MODELS_DIR -from clashroyalebuildabot.state.card_detector import CardDetector -from clashroyalebuildabot.state.debugger import Debugger -from clashroyalebuildabot.state.number_detector import NumberDetector -from clashroyalebuildabot.state.screen_detector import ScreenDetector -from clashroyalebuildabot.state.unit_detector import UnitDetector +from clashroyalebuildabot.debugger import Debugger +from clashroyalebuildabot.detectors.card_detector import CardDetector +from clashroyalebuildabot.detectors.number_detector import NumberDetector +from clashroyalebuildabot.detectors.screen_detector import ScreenDetector +from clashroyalebuildabot.detectors.unit_detector import UnitDetector +from clashroyalebuildabot.namespaces import State class Detector: @@ -35,14 +36,11 @@ def __init__(self, cards, debug=False): def run(self, image): cards, ready = self.card_detector.run(image) - state = { - "units": self.unit_detector.run(image), - "numbers": self.number_detector.run(image), - "cards": cards, - "ready": ready, - "screen": self.screen_detector.run(image), - } + units = self.unit_detector.run(image) + numbers = self.number_detector.run(image) + screen = self.screen_detector.run(image) + state = State(units, numbers, cards, ready, screen) if self.debugger is not None: self.debugger.run(image, state) diff --git a/clashroyalebuildabot/state/number_detector.py b/clashroyalebuildabot/detectors/number_detector.py similarity index 98% rename from clashroyalebuildabot/state/number_detector.py rename to clashroyalebuildabot/detectors/number_detector.py index dd26e8d..373a953 100644 --- a/clashroyalebuildabot/state/number_detector.py +++ b/clashroyalebuildabot/detectors/number_detector.py @@ -6,7 +6,7 @@ from clashroyalebuildabot.constants import NUMBER_CONFIG from clashroyalebuildabot.constants import NUMBER_HEIGHT from clashroyalebuildabot.constants import NUMBER_WIDTH -from clashroyalebuildabot.state.onnx_detector import OnnxDetector +from clashroyalebuildabot.detectors.onnx_detector import OnnxDetector class NumberDetector(OnnxDetector): diff --git a/clashroyalebuildabot/state/onnx_detector.py b/clashroyalebuildabot/detectors/onnx_detector.py similarity index 100% rename from clashroyalebuildabot/state/onnx_detector.py rename to clashroyalebuildabot/detectors/onnx_detector.py diff --git a/clashroyalebuildabot/detectors/screen_detector.py b/clashroyalebuildabot/detectors/screen_detector.py new file mode 100644 index 0000000..0aa8b31 --- /dev/null +++ b/clashroyalebuildabot/detectors/screen_detector.py @@ -0,0 +1,49 @@ +import os + +import numpy as np +from PIL import Image + +from clashroyalebuildabot.constants import IMAGES_DIR +from clashroyalebuildabot.namespaces import Screens + + +class ScreenDetector: + def __init__(self, hash_size=8, threshold=20): + self.hash_size = hash_size + self.threshold = threshold + self.screen_hashes = self._calculate_screen_hashes() + + def _image_hash(self, image): + crop = image.resize( + (self.hash_size, self.hash_size), Image.Resampling.BILINEAR + ) + hash_ = np.array(crop, dtype=np.float32).flatten() + return hash_ + + def _calculate_screen_hashes(self): + screen_hashes = {} + for screen in Screens.__dict__.values(): + if screen.ltrb is None: + continue + path = os.path.join(IMAGES_DIR, "screen", f"{screen.name}.jpg") + image = Image.open(path) + screen_hashes[screen] = self._image_hash(image) + return screen_hashes + + def run(self, image): + current_screen = Screens.IN_GAME + best_diff = self.threshold + + for screen in Screens.__dict__.values(): + if screen.ltrb is None: + continue + + hash_ = self._image_hash(image.crop(screen.ltrb)) + target_hash = self.screen_hashes[screen] + + diff = np.mean(np.abs(hash_ - target_hash)) + if diff < best_diff: + best_diff = diff + current_screen = screen + + return current_screen diff --git a/clashroyalebuildabot/state/side_detector.py b/clashroyalebuildabot/detectors/side_detector.py similarity index 89% rename from clashroyalebuildabot/state/side_detector.py rename to clashroyalebuildabot/detectors/side_detector.py index 5a56957..6b6d6ce 100644 --- a/clashroyalebuildabot/state/side_detector.py +++ b/clashroyalebuildabot/detectors/side_detector.py @@ -1,7 +1,7 @@ import numpy as np from PIL import Image -from clashroyalebuildabot.state.onnx_detector import OnnxDetector +from clashroyalebuildabot.detectors.onnx_detector import OnnxDetector class SideDetector(OnnxDetector): diff --git a/clashroyalebuildabot/state/unit_detector.py b/clashroyalebuildabot/detectors/unit_detector.py similarity index 95% rename from clashroyalebuildabot/state/unit_detector.py rename to clashroyalebuildabot/detectors/unit_detector.py index 4fa9d2a..45acd8a 100644 --- a/clashroyalebuildabot/state/unit_detector.py +++ b/clashroyalebuildabot/detectors/unit_detector.py @@ -4,8 +4,8 @@ from clashroyalebuildabot.constants import DETECTOR_UNITS from clashroyalebuildabot.constants import MODELS_DIR -from clashroyalebuildabot.state.onnx_detector import OnnxDetector -from clashroyalebuildabot.state.side_detector import SideDetector +from clashroyalebuildabot.detectors.onnx_detector import OnnxDetector +from clashroyalebuildabot.detectors.side_detector import SideDetector class UnitDetector(OnnxDetector): diff --git a/clashroyalebuildabot/namespaces/__init__.py b/clashroyalebuildabot/namespaces/__init__.py index 01edc9c..cb4f35e 100644 --- a/clashroyalebuildabot/namespaces/__init__.py +++ b/clashroyalebuildabot/namespaces/__init__.py @@ -1,7 +1,7 @@ # Exports for data submodule from .cards import Cards -from .units import Units -from .state import State from .screens import Screens +from .state import State +from .units import Units __all__ = ["Cards", "Units", "State", "Screens"] diff --git a/clashroyalebuildabot/namespaces/cards.py b/clashroyalebuildabot/namespaces/cards.py index 8529fd4..37b9afe 100644 --- a/clashroyalebuildabot/namespaces/cards.py +++ b/clashroyalebuildabot/namespaces/cards.py @@ -1,8 +1,9 @@ from dataclasses import asdict from dataclasses import dataclass -from typing import Optional, List +from typing import List, Optional -from clashroyalebuildabot.namespaces.units import Units, Unit +from clashroyalebuildabot.namespaces.units import Unit +from clashroyalebuildabot.namespaces.units import Units @dataclass(frozen=True) diff --git a/clashroyalebuildabot/namespaces/screens.py b/clashroyalebuildabot/namespaces/screens.py index 38d29de..cd81d1c 100644 --- a/clashroyalebuildabot/namespaces/screens.py +++ b/clashroyalebuildabot/namespaces/screens.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Tuple, Optional +from typing import Optional, Tuple CHEST_SIZE = 62 CHEST_X = 0 diff --git a/clashroyalebuildabot/namespaces/state.py b/clashroyalebuildabot/namespaces/state.py index bb813d6..eb24175 100644 --- a/clashroyalebuildabot/namespaces/state.py +++ b/clashroyalebuildabot/namespaces/state.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import List, Tuple, Any +from typing import Any, List, Tuple from clashroyalebuildabot.namespaces.cards import Card from clashroyalebuildabot.namespaces.screens import Screen diff --git a/clashroyalebuildabot/namespaces/units.py b/clashroyalebuildabot/namespaces/units.py index 2f82978..4212a2d 100644 --- a/clashroyalebuildabot/namespaces/units.py +++ b/clashroyalebuildabot/namespaces/units.py @@ -1,6 +1,6 @@ from dataclasses import asdict from dataclasses import dataclass -from typing import Optional, Literal +from typing import Literal, Optional @dataclass(frozen=True) diff --git a/clashroyalebuildabot/state/screen_detector.py b/clashroyalebuildabot/state/screen_detector.py deleted file mode 100644 index 6489663..0000000 --- a/clashroyalebuildabot/state/screen_detector.py +++ /dev/null @@ -1,49 +0,0 @@ -import os - -import numpy as np -from PIL import Image - -from clashroyalebuildabot.constants import IMAGES_DIR -from clashroyalebuildabot.constants import SCREEN_CONFIG - - -class ScreenDetector: - def __init__(self, hash_size=8, threshold=20): - self.hash_size = hash_size - self.threshold = threshold - self.screen_hashes = self._calculate_screen_hashes() - - def _calculate_screen_hashes(self): - screen_hashes = np.zeros( - (len(SCREEN_CONFIG), self.hash_size * self.hash_size * 3), - dtype=np.int32, - ) - for i, name in enumerate(SCREEN_CONFIG.keys()): - path = os.path.join(IMAGES_DIR, "screen", f"{name}.jpg") - image = Image.open(path) - hash_ = np.array( - image.resize( - (self.hash_size, self.hash_size), Image.Resampling.BILINEAR - ) - ).flatten() - screen_hashes[i] = hash_ - return screen_hashes - - def run(self, image): - crop_hashes = np.array( - [ - np.array( - image.crop(v["bbox"]).resize( - (self.hash_size, self.hash_size), - Image.Resampling.BILINEAR, - ) - ).flatten() - for v in SCREEN_CONFIG.values() - ] - ) - hash_diffs = np.mean(np.abs(crop_hashes - self.screen_hashes), axis=1) - return ( - "in_game" - if min(hash_diffs) > self.threshold - else list(SCREEN_CONFIG.keys())[np.argmin(hash_diffs)] - )