Files
eolrb/scorer.py
2024-08-24 18:11:59 +03:00

138 lines
3.9 KiB
Python

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 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)
blacklisted_locations = finger_trick.grip_pre_blacklist.get(finger, [])
if current_location != desired_location:
# TODO: check the minimal regrip?
regrip = next(
(
regrip
for regrip in config.regrips
if regrip.finger == finger
and regrip.pre == current_location
and regrip.post == desired_location
and regrip.pre not in blacklisted_locations
),
None,
)
if regrip:
regrips.append(regrip)
return regrips
def generate_finger_tricks(
config: Config, moves: List[str]
) -> List[FingerTrickWithRegrip]:
grip = home_grip()
alg: List[FingerTrickWithRegrip] = []
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)
# 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.pre} to {regrip.post}")
elems.append(finger_trick_with_regrips.finger_trick.name)
return elems