34
34
35
35
36
36
TAG_VALIDATOR = re .compile (r"^#?[PYLQGRJCUV0289]+$" )
37
- ARMY_LINK_SEPERATOR = re .compile (r"u(?P<units>[\d+x-]+)|s(?P<spells>[\d+x-]+)" )
38
37
39
38
T = TypeVar ('T' )
40
39
T_co = TypeVar ('T_co' , covariant = True )
@@ -186,12 +185,13 @@ def wrapper(*args, **kwargs) -> T:
186
185
return deco
187
186
188
187
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.
191
191
192
- .. note::
192
+ . note::
193
193
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.
195
195
196
196
Parameters
197
197
----------
@@ -200,15 +200,62 @@ def parse_army_link(link: str) -> Tuple[List[Tuple[int, int]], List[Tuple[int, i
200
200
201
201
Returns
202
202
-------
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.
205
207
206
208
"""
207
- matches = ARMY_LINK_SEPERATOR .finditer (link )
208
209
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" ):
212
259
units = [
213
260
(int (split [1 ]), int (split [0 ]))
214
261
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
219
266
for split in (spell .split ('x' ) for spell in match .group ("spells" ).split ('-' ))
220
267
]
221
268
222
- return units , spells
269
+ return heroes , units , spells , castle_troops , castle_spells
270
+
271
+
223
272
224
273
225
274
def maybe_sort (
0 commit comments