diff --git a/shenzhen_solitaire/clicker/__init__.py b/shenzhen_solitaire/clicker/__init__.py index 2a73aa8..9c6923f 100644 --- a/shenzhen_solitaire/clicker/__init__.py +++ b/shenzhen_solitaire/clicker/__init__.py @@ -1,5 +1,5 @@ import time -from typing import List, Tuple, Dict, Any +from typing import List, Tuple, Dict, Any, Union import pyautogui import shenzhen_solitaire.board as board @@ -8,6 +8,10 @@ import shenzhen_solitaire.card_detection.configuration as configuration import warnings from dataclasses import dataclass +from shenzhen_solitaire.board import SpecialCard + +DRAG_DURATION = 0.4 +CLICK_DURATION = 0.5 def drag( @@ -18,39 +22,18 @@ def drag( pyautogui.dragTo( x=dst[0] + offset[0], y=dst[1] + offset[1], - duration=0.4, + duration=DRAG_DURATION, tween=lambda x: 0 if x < 0.5 else 1, ) -def dragSquare( - src: Tuple[int, int, int, int], - dst: Tuple[int, int, int, int], - offset: Tuple[int, int] = (0, 0), -) -> None: - drag( - (src[0] + (src[2] - src[0]) // 2, src[1] + (src[3] - src[1]) // 2), - (dst[0] + (dst[2] - dst[0]) // 2, dst[1] + (dst[3] - dst[1]) // 2), - offset, - ) - - def click(point: Tuple[int, int], offset: Tuple[int, int] = (0, 0)) -> None: pyautogui.moveTo(x=point[0] + offset[0], y=point[1] + offset[1]) pyautogui.mouseDown() - time.sleep(0.2) + time.sleep(CLICK_DURATION) pyautogui.mouseUp() -def clickSquare( - field: Tuple[int, int, int, int], offset: Tuple[int, int] = (0, 0) -) -> None: - click( - (field[0] + (field[2] - field[0]) // 2, field[1] + (field[3] - field[1]) // 2), - offset, - ) - - @dataclass class DragAction: source: Tuple[int, int] @@ -70,12 +53,20 @@ def _parse_field( field: Dict[str, Any], conf: configuration.Configuration ) -> Tuple[int, int]: return ( - int(field["column"]) * conf.field_adjustment.dx + conf.field_adjustment.x, - int(field["row"]) * conf.field_adjustment.dy + conf.field_adjustment.y, + int(field["column"]) * conf.field_adjustment.dx + + conf.field_adjustment.x + + conf.field_adjustment.w // 2, + int(field["row"]) * conf.field_adjustment.dy + + conf.field_adjustment.y + + conf.field_adjustment.h // 2, ) -def parse_action(action: Dict[str, Any], conf: configuration.Configuration): +def parse_action( + action: Dict[str, Any], + conf: configuration.Configuration, + goal_values: Dict[str, int], +) -> Union[DragAction, ClickAction, WaitAction]: assert len(action) == 1 action_name, info = next(iter(action.items())) action_name = action_name.lower() @@ -83,8 +74,9 @@ def parse_action(action: Dict[str, Any], conf: configuration.Configuration): field = _parse_field(info["field_position"], conf) bunker = ( int(info["bunker_slot_index"]) * conf.bunker_adjustment.dx - + conf.bunker_adjustment.x, - conf.bunker_adjustment.y, + + conf.bunker_adjustment.x + + conf.bunker_adjustment.w // 2, + conf.bunker_adjustment.y + conf.bunker_adjustment.h // 2, ) if str(info["to_bunker"]).lower() == "true": return DragAction(source=field, destination=bunker) @@ -93,23 +85,50 @@ def parse_action(action: Dict[str, Any], conf: configuration.Configuration): elif action_name == "move": return DragAction( source=_parse_field(info["source"], conf), - destination=_parse_field(info["source"], conf), + destination=_parse_field(info["destination"], conf), ) elif action_name == "dragonkill": - return ClickAction() + dragon_sequence = [SpecialCard.Zhong, SpecialCard.Fa, SpecialCard.Bai] + dragon_name_map = { + "zhong": SpecialCard.Zhong, + "fa": SpecialCard.Fa, + "bai": SpecialCard.Bai, + } + card_type = dragon_name_map[info["card"].lower()] + dragon_id = dragon_sequence.index(card_type) + return ClickAction( + destination=( + conf.special_button_adjustment.x + + conf.special_button_adjustment.w // 2, + conf.special_button_adjustment.y + + dragon_id * conf.special_button_adjustment.dy + + conf.special_button_adjustment.h // 2, + ) + ) elif action_name == "goal": + obvious = ( + goal_values[info["card"]["suit"].lower()] <= min(goal_values.values()) + 1 + ) + assert (goal_values[info["card"]["suit"].lower()] == 0) or ( + goal_values[info["card"]["suit"].lower()] + 1 == info["card"]["value"] + ) + goal_values[info["card"]["suit"].lower()] = info["card"]["value"] + if obvious: + return WaitAction() goal = ( int(info["goal_slot_index"]) * conf.goal_adjustment.dx - + conf.goal_adjustment.x, - conf.goal_adjustment.y, + + conf.goal_adjustment.x + + conf.goal_adjustment.w // 2, + conf.goal_adjustment.y + conf.goal_adjustment.h // 2, ) if "Field" in info["source"]: source = _parse_field(info["source"]["Field"], conf) else: source = ( int(info["source"]["Bunker"]["slot_index"]) * conf.bunker_adjustment.dx - + conf.bunker_adjustment.x, - conf.bunker_adjustment.y, + + conf.bunker_adjustment.x + + conf.bunker_adjustment.w // 2, + conf.bunker_adjustment.y + conf.bunker_adjustment.h // 2, ) return DragAction(source=source, destination=goal) elif action_name == "huakill": @@ -121,13 +140,15 @@ def handle_actions( offset: Tuple[int, int], conf: configuration.Configuration, ) -> None: - automatic_count = 0 - for action in actions: - print(action) - if isinstance(action, board_actions.HuaKillAction): - automatic_count += 1 - else: - time.sleep(0.5 * automatic_count) - automatic_count = 0 - handle_action(action, offset, conf) - time.sleep(0.5 * automatic_count) + goal_values = {"red": 0, "black": 0, "green": 0} + action_tuples = [ + (action, parse_action(action, conf, goal_values)) for action in actions + ] + for name, action in action_tuples: + print(name) + if isinstance(action, DragAction): + drag(action.source, action.destination, offset) + elif isinstance(action, ClickAction): + click(action.destination, offset) + elif isinstance(action, WaitAction): + time.sleep(2) diff --git a/tools/assistant.py b/tools/assistant.py index 07d6c62..46a0da4 100644 --- a/tools/assistant.py +++ b/tools/assistant.py @@ -42,7 +42,7 @@ def solve(conf: configuration.Configuration) -> None: board = parse_start_board(image, conf) assert board.check_correct() actions = extern_solve(board) - assert 0 + print(actions) print(f"Solved in {len(actions)} steps") clicker.handle_actions(actions, OFFSET, conf) print("Solved") diff --git a/tools/generate/all_borders.py b/tools/generate/all_borders.py index 5831281..f9d7fe7 100644 --- a/tools/generate/all_borders.py +++ b/tools/generate/all_borders.py @@ -75,6 +75,10 @@ def main() -> None: conf.hua_adjustment = adjustment.adjust_squares( image, count_x=1, count_y=1, adjustment=copy.deepcopy(conf.hua_adjustment) ) + print("Special button") + conf.special_button_adjustment = adjustment.adjust_squares( + image, count_x=1, count_y=3, adjustment=copy.deepcopy(conf.special_button_adjustment) + ) configuration.save(conf, args.config)