perf: pre-alloc fade surface, pre-render gradient bar, add --steps-per-frame
fix: fast mode now opens pygame replay window after headless training
This commit is contained in:
@@ -16,6 +16,12 @@ class Visualizer:
|
||||
# Trail surface with per-pixel alpha
|
||||
self.trail_surf = pygame.Surface((self.maze_w, self.maze_h), pygame.SRCALPHA)
|
||||
self.trail_surf.fill((0, 0, 0, 0))
|
||||
# Pre-allocate fade surface — reused every frame (avoids per-frame Surface creation)
|
||||
self._fade_surf = pygame.Surface((self.maze_w, self.maze_h), pygame.SRCALPHA)
|
||||
subtract = max(1, int(255 * (1.0 - cfg.trail_decay)))
|
||||
self._fade_surf.fill((0, 0, 0, subtract))
|
||||
# Pre-render static gradient bar for HUD
|
||||
self._gradient_bar = self._make_gradient_bar(170)
|
||||
# Font
|
||||
pygame.font.init()
|
||||
self.font = pygame.font.SysFont("monospace", cfg.hud_font_size)
|
||||
@@ -24,15 +30,21 @@ class Visualizer:
|
||||
self._goal_flash = 0
|
||||
self._first_goal = False
|
||||
|
||||
def _make_gradient_bar(self, width: int) -> pygame.Surface:
|
||||
surf = pygame.Surface((width, 10))
|
||||
for i in range(width):
|
||||
t = i / width
|
||||
surf.set_at((i, 0), (int(255 * (1 - t)), int(255 * t), 30))
|
||||
for y in range(1, 10):
|
||||
surf.set_at((i, y), (int(255 * (1 - t)), int(255 * t), 30))
|
||||
return surf
|
||||
|
||||
def _rank_color(self, rank: int, total: int) -> tuple[int, int, int]:
|
||||
t = rank / max(1, total - 1)
|
||||
return (int(255 * t), int(255 * (1.0 - t)), 30)
|
||||
|
||||
def _fade_trails(self):
|
||||
subtract = max(1, int(255 * (1.0 - self.cfg.trail_decay)))
|
||||
fade = pygame.Surface((self.maze_w, self.maze_h), pygame.SRCALPHA)
|
||||
fade.fill((0, 0, 0, subtract))
|
||||
self.trail_surf.blit(fade, (0, 0), special_flags=pygame.BLEND_RGBA_SUB)
|
||||
self.trail_surf.blit(self._fade_surf, (0, 0), special_flags=pygame.BLEND_RGBA_SUB)
|
||||
|
||||
def _draw_hud(self, gen: int, best_fitness: float, step: int, alive: int, reached: int):
|
||||
# Dark sidebar background
|
||||
@@ -55,20 +67,16 @@ class Visualizer:
|
||||
self.screen.blit(val_surf, (self.hud_x, y + 16))
|
||||
y += 52
|
||||
|
||||
# Legend
|
||||
# Legend — pre-rendered gradient bar (no per-frame line drawing)
|
||||
y += 20
|
||||
legend_label = self.font_sm.render("RANK", True, (80, 80, 100))
|
||||
self.screen.blit(legend_label, (self.hud_x, y))
|
||||
y += 18
|
||||
bar_w = 170
|
||||
for i in range(bar_w):
|
||||
t = i / bar_w
|
||||
r, g = int(255 * t), int(255 * (1 - t))
|
||||
pygame.draw.line(self.screen, (r, g, 30), (self.hud_x + bar_w - i, y), (self.hud_x + bar_w - i, y + 10))
|
||||
self.screen.blit(self._gradient_bar, (self.hud_x, y))
|
||||
best_lbl = self.font_sm.render("best", True, (0, 255, 30))
|
||||
wrst_lbl = self.font_sm.render("worst", True, (255, 0, 30))
|
||||
self.screen.blit(best_lbl, (self.hud_x, y + 14))
|
||||
self.screen.blit(wrst_lbl, (self.hud_x + bar_w - 35, y + 14))
|
||||
self.screen.blit(wrst_lbl, (self.hud_x + 120, y + 14))
|
||||
|
||||
def render(self, agents, gen: int, step: int):
|
||||
# Sort by fitness for ranking colors
|
||||
|
||||
Reference in New Issue
Block a user