from typing import Dict, List import yaml import dacite from dataclasses import dataclass @dataclass class FingerTrick: name: str move: str grip_pre_blacklist: Dict[str, List[str]] grip_pre: Dict[str, str] grip_post: Dict[str, str] score: float @dataclass class Grip: finger: str pre: str post: str score: float @dataclass class Regrip: finger: str start: str end: str score: float @dataclass class Finger: name: str default_score: int home_grips: List[str] grips: Dict[str, List[str]] regrips: List[Regrip] @dataclass class Config: fingers: List[Finger] finger_tricks: List[FingerTrick] @dataclass class Definitions: fingers: List[Finger] finger_tricks: List[FingerTrick] finger_regrips: List[Regrip] def build_regrips_from_fingers(fingers: List[Finger]) -> List[Regrip]: regrips = [] for finger in fingers: finger_regrips = {} for grip_set in finger.grips.values(): # reate a dict with distances of every two elements in a list for i in range(len(grip_set)): for j in range(len(grip_set)): if i != j: finger_regrips[(grip_set[i], grip_set[j])] = Regrip( start=grip_set[i], end=grip_set[j], score=abs(j - i) * finger.default_score, finger=finger.name, ) for regrip in finger.regrips: finger_regrips[(regrip.start, regrip.end)] = regrip regrips.extend(finger_regrips.values()) return regrips def load_definitions(file_path: str) -> Definitions: with open(file_path, "r") as f: data_dict = yaml.safe_load(f.read()) config = dacite.from_dict(data_class=Config, data=data_dict) return Definitions( fingers=config.fingers, finger_tricks=config.finger_tricks, finger_regrips=build_regrips_from_fingers(config.fingers), ) 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 @dataclass class Algorithm: score: float finger_tricks_with_regrips: List[FingerTrickWithRegrip] def find_finger_trick_regrips( regrips: List[Regrip], finger_trick: FingerTrick, grip: Dict[str, str] ) -> List[Regrip]: alg_regrips = [] for finger in finger_trick.grip_pre.keys(): current_location = grip[finger] desired_location = finger_trick.grip_pre.get(finger) blacklisted_locations = finger_trick.grip_pre_blacklist.get(finger, []) if current_location != desired_location: # print("FINGA", finger) # print("CURRENT", current_location) # print("DESIRED", desired_location) # print("BLACK", blacklisted_locations) # __import__("pprint").pprint(regrips) alg_regrip = next( ( regrip for regrip in regrips if regrip.finger == finger and regrip.start == current_location and regrip.end == desired_location and regrip.start not in blacklisted_locations ), ) if alg_regrip: alg_regrips.append(alg_regrip) return alg_regrips def generate_home_grip(fingers: List[Finger]) -> Dict[str, str]: # TODO: make this smarter home_grip = {} for finger in fingers: home_grip[finger.name] = finger.home_grips[0] return home_grip def generate_finger_tricks( definitions: Definitions, moves: List[str] ) -> List[FingerTrickWithRegrip]: grip = generate_home_grip(definitions.fingers) alg: List[FingerTrickWithRegrip] = [] for move in moves: # print("current grip:", grip) # prit("current move:", move) possible_finger_tricks = [ finger_trick for finger_trick in definitions.finger_tricks if move == finger_trick.move ] # print("possible finger tricks:", possible_finger_tricks) finger_tricks_with_regrips = [ FingerTrickWithRegrip( finger_trick=finger_trick, regrips=find_finger_trick_regrips( definitions.finger_regrips, 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.end # apply move grip.update(best_finger_trick.finger_trick.grip_post) alg.append(best_finger_trick) # TODO: think about this # don't count the first regrip alg[0].finger_trick.score = 0 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.start} to {regrip.end}") elems.append(finger_trick_with_regrips.finger_trick.name) return elems