Skip to content

Commit e35e02b

Browse files
committed
feat: update parse linking & regex for new improved links
1 parent 760e63d commit e35e02b

File tree

1 file changed

+61
-12
lines changed

1 file changed

+61
-12
lines changed

coc/utils.py

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434

3535

3636
TAG_VALIDATOR = re.compile(r"^#?[PYLQGRJCUV0289]+$")
37-
ARMY_LINK_SEPERATOR = re.compile(r"u(?P<units>[\d+x-]+)|s(?P<spells>[\d+x-]+)")
3837

3938
T = TypeVar('T')
4039
T_co = TypeVar('T_co', covariant=True)
@@ -186,12 +185,13 @@ def wrapper(*args, **kwargs) -> T:
186185
return deco
187186

188187

189-
def parse_army_link(link: str) -> Tuple[List[Tuple[int, int]], List[Tuple[int, int]]]:
190-
"""Parse an army link into (Troop ID, Quantity) pairs for troops and spells.
188+
def parse_army_link(link: str) -> Tuple[List[Tuple[int, int | None, int | None, int | None]],
189+
List[Tuple[int, int]], List[Tuple[int, int]], List[Tuple[int, int]], List[Tuple[int, int]]]:
190+
"""Parse an army link into hero, equipment & pet id combos, clan castle combinations, and troops and spells.
191191
192-
.. note::
192+
. note::
193193
194-
For general usage, consider :meth:`Client.parse_army_link` instead, as it will return Troop and Spell objects.
194+
For general usage, consider :meth:`Client.parse_army_link` instead, as it will return Hero, Pet, Equipment, Troop and Spell objects.
195195
196196
Parameters
197197
----------
@@ -200,15 +200,62 @@ def parse_army_link(link: str) -> Tuple[List[Tuple[int, int]], List[Tuple[int, i
200200
201201
Returns
202202
-------
203-
List[Tuple[int, int]], List[Tuple[int, int]]
204-
2 lists containing (troop_id, quantity) pairs. See :meth:`Client.parse_army_link` for a detailed example.
203+
Tuple[List[Tuple[int, int | None, int | None, int | None]],
204+
List[Tuple[int, int]], List[Tuple[int, int]], List[Tuple[int, int]], List[Tuple[int, int]]]
205+
5 lists containing hero, equipment and pet id combos plus (troop_id, quantity) pairs for army and clan castle.
206+
See :meth:`Client.parse_army_link` for a detailed example.
205207
206208
"""
207-
matches = ARMY_LINK_SEPERATOR.finditer(link)
208209

209-
units, spells = [], []
210-
for match in matches:
211-
if match.group("units"):
210+
ARMY_LINK_SEPARATOR = re.compile(
211+
r"h(?P<heroes>[^idus]+)"
212+
r"|i(?P<castle_troops>[\d+x-]+)"
213+
r"|d(?P<castle_spells>[\d+x-]+)"
214+
r"|u(?P<units>[\d+x-]+)"
215+
r"|s(?P<spells>[\d+x-]+)"
216+
)
217+
218+
# Regex to parse an individual hero entry.
219+
# - hero_id is required.
220+
# - pet_id (prefixed by "p") is optional.
221+
# - Equipment (prefixed by "e") is optional; if present, eq1 is required, eq2 (after an underscore) is optional.
222+
hero_pattern = re.compile(
223+
r"(?P<hero_id>\d+)"
224+
r"(?:m\d+)?"
225+
r"(?:p(?P<pet_id>\d+))?"
226+
r"(?:e(?P<eq1>\d+)(?:_(?P<eq2>\d+))?)?"
227+
)
228+
229+
230+
heroes = []
231+
castle_troops = []
232+
castle_spells = []
233+
units = []
234+
spells = []
235+
236+
# Iterate over all section matches.
237+
for match in ARMY_LINK_SEPARATOR.finditer(link):
238+
if match.group("heroes"):
239+
hero_entries = match.group("heroes").split('-')
240+
for hero in hero_entries:
241+
m = hero_pattern.fullmatch(hero)
242+
if m:
243+
hero_id = int(m.group("hero_id"))
244+
pet_id = int(m.group("pet_id")) if m.group("pet_id") else None
245+
eq1 = int(m.group("eq1")) if m.group("eq1") else None
246+
eq2 = int(m.group("eq2")) if m.group("eq2") else None
247+
heroes.append((hero_id, pet_id, eq1, eq2))
248+
elif match.group("castle_troops"):
249+
castle_troops = [
250+
(int(split[1]), int(split[0]))
251+
for split in (troop.split('x') for troop in match.group("castle_troops").split('-'))
252+
]
253+
elif match.group("castle_spells"):
254+
castle_spells = [
255+
(int(split[1]), int(split[0]))
256+
for split in (spell.split('x') for spell in match.group("castle_spells").split('-'))
257+
]
258+
elif match.group("units"):
212259
units = [
213260
(int(split[1]), int(split[0]))
214261
for split in (troop.split('x') for troop in match.group("units").split('-'))
@@ -219,7 +266,9 @@ def parse_army_link(link: str) -> Tuple[List[Tuple[int, int]], List[Tuple[int, i
219266
for split in (spell.split('x') for spell in match.group("spells").split('-'))
220267
]
221268

222-
return units, spells
269+
return heroes, units, spells, castle_troops, castle_spells
270+
271+
223272

224273

225274
def maybe_sort(

0 commit comments

Comments
 (0)