|
4 | 4 |
|
5 | 5 | from __future__ import annotations
|
6 | 6 |
|
| 7 | +import pickle |
| 8 | +from base64 import b85decode |
7 | 9 | from dataclasses import dataclass
|
8 | 10 | from functools import total_ordering
|
9 | 11 | from itertools import combinations, count, product
|
| 12 | +from pathlib import Path |
10 | 13 | from typing import Any, Callable, Dict, Iterable, List, MutableMapping, Optional, TypeVar
|
11 | 14 |
|
| 15 | +import click |
12 | 16 | import numpy
|
13 | 17 | from loguru import logger
|
14 | 18 | from numpy import arange, ndarray, vstack
|
15 | 19 | from numpy.random import choice, permutation, randint
|
16 | 20 |
|
| 21 | +import bestmobabot.logging_ |
| 22 | +from bestmobabot import constants |
17 | 23 | from bestmobabot.constants import TEAM_SIZE
|
18 |
| -from bestmobabot.dataclasses_ import BaseArenaEnemy, Hero, Loggable |
| 24 | +from bestmobabot.database import Database |
| 25 | +from bestmobabot.dataclasses_ import ArenaEnemy, BaseArenaEnemy, GrandArenaEnemy, Hero, Loggable |
19 | 26 | from bestmobabot.itertools_ import CountDown, secretary_max, slices
|
20 | 27 | from bestmobabot.model import Model
|
21 | 28 |
|
@@ -130,9 +137,13 @@ def __init__(
|
130 | 137 | self.solutions = numpy.array([[]])
|
131 | 138 |
|
132 | 139 | def solve(self) -> ArenaSolution:
|
| 140 | + self.initialize() |
| 141 | + return secretary_max(self.yield_solutions(), self.max_iterations, early_stop=self.early_stop) |
| 142 | + |
| 143 | + def initialize(self) -> ArenaSolver: |
133 | 144 | logger.debug('Generating initial solutions…')
|
134 | 145 | self.solutions = vstack([permutation(len(self.heroes)) for _ in range(self.n_keep_solutions)])
|
135 |
| - return secretary_max(self.yield_solutions(), self.max_iterations, early_stop=self.early_stop) |
| 146 | + return self |
136 | 147 |
|
137 | 148 | def yield_solutions(self) -> Iterable[ArenaSolution]:
|
138 | 149 | """
|
@@ -325,3 +336,64 @@ def reduce_grand_arena(y1: ndarray, y2: ndarray, y3: ndarray) -> ndarray:
|
325 | 336 | Gives probability to win at least two of three battles.
|
326 | 337 | """
|
327 | 338 | return y1 * y2 * y3 + y1 * y2 * (1.0 - y3) + y2 * y3 * (1.0 - y1) + y1 * y3 * (1.0 - y2)
|
| 339 | + |
| 340 | + |
| 341 | +# Tester. |
| 342 | +# ---------------------------------------------------------------------------------------------------------------------- |
| 343 | + |
| 344 | +@click.command() |
| 345 | +@click.option('verbosity', '-v', '--verbose', count=True, help='Increase verbosity.') |
| 346 | +def main(verbosity: int): |
| 347 | + """Test the solver on the pre-dumped data.""" |
| 348 | + bestmobabot.logging_.install_logging(verbosity) |
| 349 | + |
| 350 | + logger.info('Loading the dumps…') |
| 351 | + with Database(constants.DATABASE_NAME) as db: |
| 352 | + model: Model = pickle.loads(b85decode(db['bot:model'])) |
| 353 | + heroes: List[Hero] = pickle.loads((Path('dumps') / 'heroes.pkl').read_bytes()) |
| 354 | + arena_enemies: List[ArenaEnemy] = pickle.loads((Path('dumps') / 'arena_enemies.pkl').read_bytes()) |
| 355 | + grand_enemies: List[GrandArenaEnemy] = pickle.loads((Path('dumps') / 'grand_enemies.pkl').read_bytes()) |
| 356 | + |
| 357 | + logger.info('') |
| 358 | + for enemy in arena_enemies: |
| 359 | + solution = ArenaSolver( |
| 360 | + db={}, |
| 361 | + model=model, |
| 362 | + user_clan_id=None, |
| 363 | + heroes=heroes, |
| 364 | + n_required_teams=1, |
| 365 | + max_iterations=0, |
| 366 | + n_keep_solutions=50, |
| 367 | + n_generate_solutions=100, |
| 368 | + n_generations_count_down=25, |
| 369 | + early_stop=0.95, |
| 370 | + get_enemies=list, |
| 371 | + friendly_clans=[], |
| 372 | + reduce_probabilities=reduce_normal_arena, |
| 373 | + callback=lambda: None, |
| 374 | + ).initialize().solve_enemy(enemy) |
| 375 | + logger.info('{}', solution) |
| 376 | + |
| 377 | + logger.info('') |
| 378 | + for enemy in grand_enemies: |
| 379 | + solution = ArenaSolver( |
| 380 | + db={}, |
| 381 | + model=model, |
| 382 | + user_clan_id=None, |
| 383 | + heroes=heroes, |
| 384 | + n_required_teams=constants.N_GRAND_TEAMS, |
| 385 | + max_iterations=0, |
| 386 | + n_keep_solutions=50, |
| 387 | + n_generate_solutions=500, |
| 388 | + n_generations_count_down=50, |
| 389 | + early_stop=0.95, |
| 390 | + get_enemies=list, |
| 391 | + friendly_clans=[], |
| 392 | + reduce_probabilities=reduce_grand_arena, |
| 393 | + callback=lambda: None, |
| 394 | + ).initialize().solve_enemy(enemy) |
| 395 | + logger.info('{}', solution) |
| 396 | + |
| 397 | + |
| 398 | +if __name__ == '__main__': |
| 399 | + main() |
0 commit comments