from typing import Dict, List import yaml import dacite from dataclasses import dataclass @dataclass class FingerTrick: name: str move: str grip_pre: Dict[str, str] grip_post: Dict[str, str] score: float @dataclass class Regrip: finger: str pre: str post: str score: float @dataclass class Config: finger_tricks: List[FingerTrick] regrips: List[Regrip] def home_grip() -> Dict[str, str]: return { "index": "B", # this could also be BL "ring": "B", "pinky": "BD", } def load_config(file_path: str) -> Config: with open(file_path, "r") as f: data_dict = yaml.safe_load(f.read()) return dacite.from_dict(data_class=Config, data=data_dict) def grip_correct(current_grip: Dict[str, str], required_grip: Dict[str, str]): return all(item in current_grip.items() for item in required_grip.items()) @dataclass class FingerTrickWithRegrip: finger_trick: FingerTrick regrips: List[Regrip] def score(self) -> float: score = 0.0 score += self.finger_trick.score if self.regrips: longest_regrip = max(self.regrips, key=lambda regrip: regrip.score) score += longest_regrip.score return score def calculate_finger_trick_regrips( config: Config, finger_trick: FingerTrick, grip: Dict[str, str] ) -> List[Regrip]: regrips = [] for finger in finger_trick.grip_pre.keys(): current_location = grip[finger] desired_location = finger_trick.grip_pre.get(finger) if current_location != desired_location: regrip = next( ( regrip for regrip in config.regrips if regrip.finger == finger and regrip.pre == current_location and regrip.post == desired_location ), None, ) if regrip: regrips.append(regrip) return regrips def generate_finger_tricks( config: Config, moves: List[str] ) -> List[FingerTrickWithRegrip]: grip = home_grip() alg = [] for move in moves: # print("current grip:", grip) # prit("current move:", move) possible_finger_tricks = [ finger_trick for finger_trick in config.finger_tricks if move == finger_trick.move ] # print("possible finger tricks:", possible_finger_tricks) finger_tricks_with_regrips = [ FingerTrickWithRegrip( finger_trick=finger_trick, regrips=calculate_finger_trick_regrips(config, finger_trick, grip), ) for finger_trick in possible_finger_tricks ] best_finger_trick = min( finger_tricks_with_regrips, key=lambda item: item.score() ) # print("best finger trick:", best_finger_trick) # apply regrips for regrip in best_finger_trick.regrips: grip[regrip.finger] = regrip.post # apply move grip.update(best_finger_trick.finger_trick.grip_post) alg.append(best_finger_trick) return alg def build_pretty_string_from_finger_tricks_with_regrips( finger_tricks_with_regrips: List[FingerTrickWithRegrip], ) -> List[str]: elems = [] for finger_trick_with_regrips in finger_tricks_with_regrips: for regrip in finger_trick_with_regrips.regrips: elems.append(f"regrip {regrip.finger} from {regrip.pre} to {regrip.post}") elems.append(finger_trick_with_regrips.finger_trick.name) return elems