From eedea3ea19b4003a86a1aa85bd1b9379ad6979f8 Mon Sep 17 00:00:00 2001 From: Dominik Roth Date: Sun, 9 Aug 2026 15:50:55 +0200 Subject: [PATCH] OCR: fix destruction reports for ad-hoc 'Enemy X Y' installations _DESTROYED_RE requires a digit-shaped id ('SupplyCache#2 Destroyed'), but an Enemy installation's id (after squash_enemy_names()) is letters ('Enemy#SignalStation'), so 'Enemy Signal Station Destroyed' silently matched nothing and never marked the target dead. Same digit-vs-letter split every other Enemy-aware regex in this file already needed, just missed here. Added _ENEMY_DESTROYED_RE alongside it, verified through the real _merge_targets() flow for both an already-known target and one whose destruction is the first mention of it at all. --- src/fenigma/ocr.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/fenigma/ocr.py b/src/fenigma/ocr.py index 5c98e2e..aa27995 100644 --- a/src/fenigma/ocr.py +++ b/src/fenigma/ocr.py @@ -609,6 +609,11 @@ def parse_train_intel(text: str) -> list[dict]: _DESTROYED_RE = re.compile( rf"([A-Za-z]+)[^A-Za-z0-9\s]{{1,2}}({_DIGIT_CLASS}+)\s*Destroyed", re.IGNORECASE ) +# Same digit-vs-letter-id split as the header regexes: an ad-hoc "Enemy +# X Y" installation's id (after squash_enemy_names()) is letters, not +# digits, so it needs its own pattern, _DESTROYED_RE's digit class won't +# match it at all ("Enemy#SignalStation Destroyed" was silently dropped). +_ENEMY_DESTROYED_RE = re.compile(r"(Enemy)#([A-Za-z]+)\s*Destroyed", re.IGNORECASE) def parse_destroyed(text: str) -> set[tuple[TargetType, str]]: @@ -619,6 +624,12 @@ def parse_destroyed(text: str) -> set[tuple[TargetType, str]]: if target_type is None: continue destroyed.add((target_type, _fix_id_digits(num))) + for m in _ENEMY_DESTROYED_RE.finditer(text): + type_word, letter_id = m.groups() + target_type = _resolve_target_type(type_word) + if target_type is None: + continue + destroyed.add((target_type, letter_id)) return destroyed