"""Evaluacny harness: odohra N kol medzi 4 hracmi a spocita metriky. Metriky per hrac (viz rl/DESIGN.md, sekcia 5): priemerne body na kolo a presnost tipu (% kol s presne trafenym tipom). Sedadla sa medzi kolami rotuju, aby ziadny hrac nebol systematicky zvyhodneny poradim tipovania. Spustenie ako skript porovna baseline botov: py -m rl.evaluate --rounds 500 --seed 7 """ import argparse from random import Random from bridzik import ROUNDS_PER_SERIES from rl.env import PHASE_GUESS, RoundEnv def play_round(players: list, env: RoundEnv, round_number: int = None, first_player: int = None) -> list: """Odohra jedno kolo; `players[seat]` rozhoduje za sedadlo `seat`. Vrati body 4 sedadiel (`Round.get_points_summary()`). """ decision = env.reset(round_number, first_player) while True: seat = decision.player if decision.phase == PHASE_GUESS: action = players[seat].guess(env.round, seat) else: action = players[seat].play(env.round, seat) decision, rewards, done = env.step(action) if done: return rewards def evaluate(players: list, n_rounds: int, rng: Random = None, round_numbers: list = None) -> list: """Odohra `n_rounds` kol s rotaciou sedadiel; vrati stats per hrac. Vystup: zoznam dictov v poradi `players` -- {'avg_points': float, 'hit_rate': float, 'rounds': int}. """ rng = rng if rng is not None else Random() env = RoundEnv(rng) points = [0] * 4 hits = [0] * 4 for i in range(n_rounds): round_number = rng.choice(round_numbers) if round_numbers \ else rng.randrange(ROUNDS_PER_SERIES) # rotacia: sedadlo s obsadzuje players[(s + i) % 4] seating = [players[(s + i) % 4] for s in range(4)] rewards = play_round(seating, env, round_number) for seat in range(4): player_index = (seat + i) % 4 points[player_index] += rewards[seat] hits[player_index] += rewards[seat] > 0 return [{'avg_points': points[p] / n_rounds, 'hit_rate': hits[p] / n_rounds, 'rounds': n_rounds} for p in range(len(players))] def main(): from rl.players import HeuristicPlayer, RandomPlayer parser = argparse.ArgumentParser(description='Evaluacia baseline botov') parser.add_argument('--rounds', type=int, default=500) parser.add_argument('--seed', type=int, default=7) parser.add_argument('--mc-samples', type=int, default=100) args = parser.parse_args() rng = Random(args.seed) lineups = [ ('4x random', [RandomPlayer(rng) for _ in range(4)]), ('1x heuristika + 3x random', [HeuristicPlayer(rng, n_samples=args.mc_samples)] + [RandomPlayer(rng) for _ in range(3)]), ('4x heuristika', [HeuristicPlayer(rng, n_samples=args.mc_samples) for _ in range(4)]), ] for label, players in lineups: stats = evaluate(players, args.rounds, rng) print(f'\n{label} ({args.rounds} kol):') for i, s in enumerate(stats): print(f' hrac {i}: {s["avg_points"]:6.2f} bodov/kolo, ' f'tip trafeny {100 * s["hit_rate"]:5.1f} %') if __name__ == '__main__': main()