Skip to content

Commit 974ba00

Browse files
Merge pull request #124 from jonbinney/split_renderers
Renderers: split them in files in renderers
2 parents 20097e8 + e0a6ae1 commit 974ba00

File tree

8 files changed

+175
-156
lines changed

8 files changed

+175
-156
lines changed

deep_quoridor/src/renderers.py

Lines changed: 0 additions & 156 deletions
This file was deleted.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from arena import ArenaPlugin
2+
3+
4+
class Renderer(ArenaPlugin):
5+
"""
6+
Base class for all renderers, which take a game and render it in some way.
7+
"""
8+
9+
renderers = {}
10+
11+
def __init_subclass__(cls, **kwargs):
12+
friendly_name = cls.__name__.replace("Renderer", "").lower()
13+
Renderer.renderers[friendly_name] = cls
14+
15+
@staticmethod
16+
def create(friendly_name: str):
17+
return Renderer.renderers[friendly_name]()
18+
19+
@staticmethod
20+
def names():
21+
return list(Renderer.renderers.keys())
22+
23+
24+
from renderers.arena_results import ArenaResultsRenderer # noqa: E402, F401
25+
from renderers.curses_board import CursesBoardRenderer # noqa: E402, F401
26+
from renderers.match_results import MatchResultsRenderer # noqa: E402, F401
27+
from renderers.none import NoneRenderer # noqa: E402, F401
28+
from renderers.progress_bar import ProgressBarRenderer # noqa: E402, F401
29+
from renderers.text_board import TextBoardRenderer # noqa: E402, F401
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from renderers import Renderer
2+
from prettytable import PrettyTable
3+
import numpy as np
4+
from arena import GameResult
5+
6+
7+
class ArenaResultsRenderer(Renderer):
8+
def end_arena(self, game, results: list[GameResult]):
9+
def perc(wins: int, played: int) -> str:
10+
if played == 0:
11+
return "-"
12+
13+
return f"{wins / played * 100.0:.0f}%"
14+
15+
print("Arena stats")
16+
print("===========")
17+
print("Board size: ", game.board_size)
18+
print("Max walls: ", game.max_walls)
19+
print("Step rewards: ", game.step_rewards)
20+
print("Total number of games: ", len(results), "\n")
21+
22+
all_players = sorted(set([r.player1 for r in results]) | set([r.player2 for r in results]))
23+
players = {player: i for i, player in enumerate(all_players)}
24+
25+
table = PrettyTable()
26+
table.field_names = ["P1 \\ P2"] + list(players) + ["Total"]
27+
28+
N = len(players)
29+
wins = np.zeros((N + 1, N + 1))
30+
games = np.zeros((N + 1, N + 1))
31+
32+
for r in results:
33+
games[players[r.player1], players[r.player2]] += 1
34+
if r.winner == r.player1:
35+
wins[players[r.player1], players[r.player2]] += 1
36+
37+
# Get the totals per row and column
38+
wins[-1, :] = np.sum(wins, axis=0)
39+
wins[:, -1] = np.sum(wins, axis=1)
40+
games[-1, :] = np.sum(games, axis=0)
41+
games[:, -1] = np.sum(games, axis=1)
42+
43+
# Hacky way of adding an extra column and row for the totals
44+
players["Total"] = max(players.values()) + 1
45+
46+
# Set the results in the PrettyTable
47+
for player1, i1 in players.items():
48+
row = [player1]
49+
for _, i2 in players.items():
50+
row.append(perc(wins[i1, i2], games[i1, i2]))
51+
52+
table.add_row(row)
53+
54+
# Before the last row add this separation, since the last row is the total
55+
if i1 == len(players) - 2:
56+
table.add_row(["======" for _ in range(len(players) + 1)])
57+
58+
print(table)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from renderers import Renderer
2+
from arena import GameResult
3+
from agents import Agent
4+
import curses
5+
6+
7+
class CursesBoardRenderer(Renderer):
8+
def __init__(self, napms=100):
9+
super().__init__()
10+
self.napms = napms
11+
12+
def start_arena(self, game, total_games: int):
13+
self.stdscr = curses.initscr()
14+
curses.noecho()
15+
curses.cbreak()
16+
curses.start_color()
17+
18+
def end_arena(self, game, results: list[GameResult]):
19+
curses.nocbreak()
20+
curses.echo()
21+
curses.endwin()
22+
23+
def start_game(self, game, agent1: Agent, agent2: Agent):
24+
self.match = f"{agent1.name()} vs {agent2.name()}"
25+
26+
def action(self, game, step, agent, action):
27+
board = game.render()
28+
self.stdscr.erase()
29+
self.stdscr.addstr(0, 0, f"Game: {self.match} - Step {step + 1}: {agent} takes action {action}")
30+
self.stdscr.addstr(2, 2, board)
31+
self.stdscr.refresh()
32+
curses.napms(self.napms)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from renderers import Renderer
2+
from arena import GameResult
3+
from agents import Agent
4+
5+
6+
class MatchResultsRenderer(Renderer):
7+
def start_game(self, game, agent1: Agent, agent2: Agent):
8+
self.match = f"{agent1.name()} vs {agent2.name()}"
9+
10+
def end_game(self, game, result: GameResult):
11+
print(f"{result.game_id}: {self.match} - {result.winner} won in {result.steps} steps")
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from renderers import Renderer
2+
3+
4+
class NoneRenderer(Renderer):
5+
pass
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from renderers import Renderer
2+
from arena import GameResult
3+
4+
5+
class ProgressBarRenderer(Renderer):
6+
def update_progress_bar(self, bar_width: int = 50):
7+
progress = self.games_played / self.total_games * 100
8+
filled = int(bar_width * progress / 100)
9+
bar = "=" * filled + "-" * (bar_width - filled)
10+
print(f"\rProgress: [{bar}] {progress:.1f}% ({self.games_played}/{self.total_games})", end="", flush=True)
11+
12+
def start_arena(self, game, total_games):
13+
self.total_games = total_games
14+
self.games_played = 0
15+
self.update_progress_bar()
16+
17+
def end_game(self, game, result):
18+
self.games_played += 1
19+
self.update_progress_bar()
20+
21+
def end_arena(self, game, results: list[GameResult]):
22+
print()
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from renderers import Renderer
2+
from arena import GameResult
3+
from agents import Agent
4+
5+
6+
class TextBoardRenderer(Renderer):
7+
def start_game(self, game, agent1: Agent, agent2: Agent):
8+
self.match = f"{agent1.name()} vs {agent2.name()}"
9+
print("Initial Board State:")
10+
print(game.render())
11+
12+
def end_game(self, game, result: GameResult):
13+
print(f"{result.game_id}: {self.match} - {result.winner} won in {result.steps} steps")
14+
15+
def action(self, game, step, agent, action):
16+
print(f"\nStep {step + 1}: {agent} takes action {action}")
17+
print(f"Rewards: {game.rewards}")
18+
print(game.render())

0 commit comments

Comments
 (0)