mirror of
https://github.com/mwisnowski/mtg_python_deckbuilder.git
synced 2025-09-22 04:50:46 +02:00
90 lines
2.6 KiB
Python
90 lines
2.6 KiB
Python
![]() |
from __future__ import annotations
|
||
|
|
||
|
from dataclasses import dataclass
|
||
|
from pathlib import Path
|
||
|
from typing import Iterable, List, Optional
|
||
|
|
||
|
from tagging.combo_schema import (
|
||
|
load_and_validate_combos,
|
||
|
load_and_validate_synergies,
|
||
|
CombosListModel,
|
||
|
SynergiesListModel,
|
||
|
)
|
||
|
|
||
|
|
||
|
def _canonicalize(name: str) -> str:
|
||
|
s = str(name or "").strip()
|
||
|
s = s.replace("\u2019", "'").replace("\u2018", "'")
|
||
|
s = s.replace("\u201C", '"').replace("\u201D", '"')
|
||
|
s = s.replace("\u2013", "-").replace("\u2014", "-")
|
||
|
s = " ".join(s.split())
|
||
|
return s
|
||
|
|
||
|
|
||
|
@dataclass(frozen=True)
|
||
|
class DetectedCombo:
|
||
|
a: str
|
||
|
b: str
|
||
|
cheap_early: bool
|
||
|
setup_dependent: bool
|
||
|
tags: Optional[List[str]] = None
|
||
|
|
||
|
|
||
|
@dataclass(frozen=True)
|
||
|
class DetectedSynergy:
|
||
|
a: str
|
||
|
b: str
|
||
|
tags: Optional[List[str]] = None
|
||
|
|
||
|
|
||
|
def _detect_combos_from_model(names_norm: set[str], combos: CombosListModel) -> List[DetectedCombo]:
|
||
|
out: List[DetectedCombo] = []
|
||
|
for p in combos.pairs:
|
||
|
a = _canonicalize(p.a).casefold()
|
||
|
b = _canonicalize(p.b).casefold()
|
||
|
if a in names_norm and b in names_norm:
|
||
|
out.append(
|
||
|
DetectedCombo(
|
||
|
a=p.a,
|
||
|
b=p.b,
|
||
|
cheap_early=bool(p.cheap_early),
|
||
|
setup_dependent=bool(p.setup_dependent),
|
||
|
tags=list(p.tags or []),
|
||
|
)
|
||
|
)
|
||
|
return out
|
||
|
|
||
|
|
||
|
def detect_combos(names: Iterable[str], combos_path: str | Path = "config/card_lists/combos.json") -> List[DetectedCombo]:
|
||
|
names_norm = set()
|
||
|
for n in names:
|
||
|
c = _canonicalize(n).casefold()
|
||
|
if not c:
|
||
|
continue
|
||
|
names_norm.add(c)
|
||
|
|
||
|
if not names_norm:
|
||
|
return []
|
||
|
|
||
|
combos = load_and_validate_combos(combos_path)
|
||
|
return _detect_combos_from_model(names_norm, combos)
|
||
|
|
||
|
|
||
|
def _detect_synergies_from_model(names_norm: set[str], syn: SynergiesListModel) -> List[DetectedSynergy]:
|
||
|
out: List[DetectedSynergy] = []
|
||
|
for p in syn.pairs:
|
||
|
a = _canonicalize(p.a).casefold()
|
||
|
b = _canonicalize(p.b).casefold()
|
||
|
if a in names_norm and b in names_norm:
|
||
|
out.append(DetectedSynergy(a=p.a, b=p.b, tags=list(p.tags or [])))
|
||
|
return out
|
||
|
|
||
|
|
||
|
def detect_synergies(names: Iterable[str], synergies_path: str | Path = "config/card_lists/synergies.json") -> List[DetectedSynergy]:
|
||
|
names_norm = {_canonicalize(n).casefold() for n in names if str(n).strip()}
|
||
|
if not names_norm:
|
||
|
return []
|
||
|
syn = load_and_validate_synergies(synergies_path)
|
||
|
return _detect_synergies_from_model(names_norm, syn)
|
||
|
|