neural-boy / src /game /game.py
sachinkumarsingh's picture
Upload folder using huggingface_hub
d548197 verified
Raw
History Blame Contribute Delete
4.97 kB
from collections import OrderedDict
from typing import Tuple, Union
import numpy as np
import pygame
from PIL import Image
from .dataset_env import DatasetEnv
from .keymap import Keymap
from .play_env import PlayEnv
class Game:
def __init__(
self,
play_env: Union[PlayEnv, DatasetEnv],
keymap: Keymap,
size: Tuple[int, int],
fps: int,
verbose: bool,
) -> None:
self.env = play_env
self.keymap = keymap
self.height, self.width = size
self.fps = fps
self.verbose = verbose
self.keymap = OrderedDict()
for keys, act in sorted(keymap.items(), key=lambda keys_act: -len(keys_act[0])):
self.keymap[keys] = act
print("\nControls (general):\n")
print("⏎ : reset env")
print(". : pause/unpause")
print("e : step-by-step (when paused)")
self.env.print_controls()
print("\n")
def run(self) -> None:
pygame.init()
header_height = 150 if self.verbose else 0
font_size = 16
screen = pygame.display.set_mode((self.width, self.height + header_height))
clock = pygame.time.Clock()
font = pygame.font.SysFont("mono", font_size)
header_rect = pygame.Rect(0, 0, self.width, header_height)
def clear_header():
pygame.draw.rect(screen, pygame.Color("black"), header_rect)
pygame.draw.rect(screen, pygame.Color("white"), header_rect, 1)
def draw_text(text, idx_line, idx_column, num_cols):
pos = (5 + idx_column * int(self.width // num_cols), 5 + idx_line * font_size)
assert (0 <= pos[0] <= self.width) and (0 <= pos[1] <= header_height)
screen.blit(font.render(text, True, pygame.Color("white")), pos)
def draw_game(obs):
assert obs.ndim == 4 and obs.size(0) == 1
img = Image.fromarray(obs[0].add(1).div(2).mul(255).byte().permute(1, 2, 0).cpu().numpy())
pygame_image = np.array(img.resize((self.width, self.height), resample=Image.NEAREST)).transpose((1, 0, 2))
surface = pygame.surfarray.make_surface(pygame_image)
screen.blit(surface, (0, header_height))
def reset():
nonlocal obs, info, do_reset, ep_return, ep_length
obs, info = self.env.reset()
do_reset = False
ep_return = 0
ep_length = 0
obs, info, do_reset, ep_return, ep_length = (None,) * 5
reset()
do_wait = False
should_stop = False
while not should_stop:
do_one_step = False
action = 0 # noop
pygame.event.pump()
for event in pygame.event.get():
if event.type == pygame.QUIT:
should_stop = True
if event.type != pygame.KEYDOWN:
continue
if event.key == pygame.K_RETURN:
do_reset = True
if event.key == pygame.K_PERIOD:
do_wait = not do_wait
print("Game paused." if do_wait else "Game resumed.")
if event.key == pygame.K_e:
do_one_step = True
if event.key == pygame.K_m:
do_reset = self.env.next_mode()
if event.key == pygame.K_UP:
do_reset = self.env.next_axis_1()
if event.key == pygame.K_DOWN:
do_reset = self.env.prev_axis_1()
if event.key == pygame.K_RIGHT:
do_reset = self.env.next_axis_2()
if event.key == pygame.K_LEFT:
do_reset = self.env.prev_axis_2()
if action == 0:
pressed = pygame.key.get_pressed()
for keys, action in self.keymap.items():
if all([pressed[key] for key in keys]):
break
else:
action = 0
if do_reset:
reset()
if do_wait and not do_one_step:
continue
next_obs, rew, end, trunc, info = self.env.step(action)
ep_return += rew.item()
ep_length += 1
draw_game(obs)
if self.verbose and info is not None:
clear_header()
assert isinstance(info, dict) and "header" in info
header = info["header"]
num_cols = len(header)
for j, col in enumerate(header):
for i, row in enumerate(col):
draw_text(row, idx_line=i, idx_column=j, num_cols=num_cols)
pygame.display.flip() # update screen
clock.tick(self.fps) # ensures game maintains the given frame rate
if end or trunc:
reset()
else:
obs = next_obs
pygame.quit()