Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
051751e
mujoco bindings
rodrigodelazcano Apr 2, 2022
3fd204d
Update README.md
jkterry1 Apr 7, 2022
227e246
Pyright versioning update. Fix #2700 (#2739)
gianlucadecola Apr 8, 2022
623dd8d
fix #2736 (#2737)
younik Apr 8, 2022
d4cda25
AutoResetWrapper integration with gym.make() (#2728)
balisujohn Apr 8, 2022
2ac8553
Added kwarg documentation for BlackJack and LunarLander (#2742)
Markus28 Apr 10, 2022
b717924
Update the parametrize to show the ids of the specification to make d…
pseudo-rnd-thoughts Apr 10, 2022
06072ed
fix: type ignore from #2739 (#2744)
kir0ul Apr 11, 2022
33970e2
Update README.md
jkterry1 Apr 13, 2022
9632946
mujoco bindings
rodrigodelazcano Apr 2, 2022
b18d22a
auto gl backend
rodrigodelazcano Apr 13, 2022
027aaad
new mujoco release dep
rodrigodelazcano Apr 13, 2022
a20dc21
Merge branch 'master' of https://github.com/rodrigodelazcano/gym
rodrigodelazcano Apr 13, 2022
0120576
update pusher v4
rodrigodelazcano Apr 13, 2022
5ae6bf9
Bipedal fix bounds and type hints (#2750)
jjshoots Apr 14, 2022
ab38034
remove contact forces mujoco
rodrigodelazcano Apr 14, 2022
75c7fbc
readd contact forces
rodrigodelazcano Apr 14, 2022
1a3a891
fix #2723 and remove unuseful board (#2754)
younik Apr 15, 2022
681a992
Add gravity and wind as kwarg in Lunar Lander (#2746)
jjshoots Apr 15, 2022
c6deb81
Add mild domain randomization to Car Racing Env (#2749)
jjshoots Apr 15, 2022
da7b8ae
Made documentation for carracing more descriptive, and renamed one of…
jjshoots Apr 15, 2022
6138920
Fix turn indicators not working in Carracing (#2759)
jjshoots Apr 17, 2022
36a7fe5
Add test gym utils play. Fix #2729 (#2743)
gianlucadecola Apr 18, 2022
a81ed98
mujoco bindings
rodrigodelazcano Apr 2, 2022
f7a1f43
auto gl backend
rodrigodelazcano Apr 13, 2022
bb603ea
new mujoco release dep
rodrigodelazcano Apr 13, 2022
4060922
update pusher v4
rodrigodelazcano Apr 13, 2022
fab4ffb
remove contact forces mujoco
rodrigodelazcano Apr 14, 2022
45330b4
readd contact forces
rodrigodelazcano Apr 14, 2022
8a1b425
skip rendering mujoco_py test
rodrigodelazcano Apr 19, 2022
906789e
Merge branch 'master' of https://github.com/rodrigodelazcano/gym
rodrigodelazcano Apr 19, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add test gym utils play. Fix #2729 (#2743)
* refactoring play function. Tests for keys to action mapping.

* Add mocking pygame events.

* partial event processing in class.

* pre-commit.

* quit pygame after tests.

* fix typos in functions names.

* Add type hint.

* Add test for play function.

* remove mockKeyEvent.

* remove unused main code.

* Adding type hints.

* catch custom exception in tests.

* Fix magic numbers.

* Add test with an actual environment.

* fix comment.

* Add TODO memo on env.render.

* change map with list comprehension.

* remove unused imports.

* Add type hint.

* typo.

* docstring.
  • Loading branch information
gianlucadecola authored Apr 18, 2022
commit 36a7fe5a312f86b016495c60f7a12a32334291f6
167 changes: 98 additions & 69 deletions gym/utils/play.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import argparse
from typing import Callable, Dict, Optional, Tuple

import matplotlib
import pygame
from numpy.typing import NDArray
from pygame import Surface
from pygame.event import Event

import gym
from gym import logger
from gym import Env, logger

try:
import matplotlib

matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
except ImportError as e:
Expand All @@ -18,15 +22,87 @@
from pygame.locals import VIDEORESIZE


def display_arr(screen, arr, video_size, transpose):
class MissingKeysToAction(Exception):
"""Raised when the environment does not have
a default keys_to_action mapping
"""


class PlayableGame:
def __init__(
self,
env: Env,
keys_to_action: Optional[Dict[Tuple[int], int]] = None,
zoom: Optional[float] = None,
):
self.env = env
self.relevant_keys = self._get_relevant_keys(keys_to_action)
self.video_size = self._get_video_size(zoom)
self.screen = pygame.display.set_mode(self.video_size)
self.pressed_keys = []
self.running = True

def _get_relevant_keys(
self, keys_to_action: Optional[Dict[Tuple[int], int]] = None
) -> set:
if keys_to_action is None:
if hasattr(self.env, "get_keys_to_action"):
keys_to_action = self.env.get_keys_to_action()
elif hasattr(self.env.unwrapped, "get_keys_to_action"):
keys_to_action = self.env.unwrapped.get_keys_to_action()
else:
raise MissingKeysToAction(
"%s does not have explicit key to action mapping, "
"please specify one manually" % self.env.spec.id
)
relevant_keys = set(sum((list(k) for k in keys_to_action.keys()), []))
return relevant_keys

def _get_video_size(self, zoom: Optional[float] = None) -> Tuple[int, int]:
# TODO: this needs to be updated when the render API change goes through
rendered = self.env.render(mode="rgb_array")
video_size = [rendered.shape[1], rendered.shape[0]]

if zoom is not None:
video_size = int(video_size[0] * zoom), int(video_size[1] * zoom)

return video_size

def process_event(self, event: Event) -> None:
if event.type == pygame.KEYDOWN:
if event.key in self.relevant_keys:
self.pressed_keys.append(event.key)
elif event.key == pygame.K_ESCAPE:
self.running = False
elif event.type == pygame.KEYUP:
if event.key in self.relevant_keys:
self.pressed_keys.remove(event.key)
elif event.type == pygame.QUIT:
self.running = False
elif event.type == VIDEORESIZE:
self.video_size = event.size
self.screen = pygame.display.set_mode(self.video_size)


def display_arr(
screen: Surface, arr: NDArray, video_size: Tuple[int, int], transpose: bool
):
arr_min, arr_max = arr.min(), arr.max()
arr = 255.0 * (arr - arr_min) / (arr_max - arr_min)
pyg_img = pygame.surfarray.make_surface(arr.swapaxes(0, 1) if transpose else arr)
pyg_img = pygame.transform.scale(pyg_img, video_size)
screen.blit(pyg_img, (0, 0))


def play(env, transpose=True, fps=30, zoom=None, callback=None, keys_to_action=None):
def play(
env: Env,
transpose: Optional[bool] = True,
fps: Optional[int] = 30,
zoom: Optional[float] = None,
callback: Optional[Callable] = None,
keys_to_action: Optional[Dict[Tuple[int], int]] = None,
seed: Optional[int] = None,
):
"""Allows one to play the game using keyboard.

To simply play the game use:
Expand Down Expand Up @@ -81,65 +157,35 @@ def callback(obs_t, obs_tp1, action, rew, done, info):
# ...
}
If None, default key_to_action mapping for that env is used, if provided.
seed: bool or None
Random seed used when resetting the environment. If None, no seed is used.
"""
env.reset()
rendered = env.render(mode="rgb_array")

if keys_to_action is None:
if hasattr(env, "get_keys_to_action"):
keys_to_action = env.get_keys_to_action()
elif hasattr(env.unwrapped, "get_keys_to_action"):
keys_to_action = env.unwrapped.get_keys_to_action()
else:
assert False, (
env.spec.id
+ " does not have explicit key to action mapping, "
+ "please specify one manually"
)
relevant_keys = set(sum(map(list, keys_to_action.keys()), []))

video_size = [rendered.shape[1], rendered.shape[0]]
if zoom is not None:
video_size = int(video_size[0] * zoom), int(video_size[1] * zoom)
env.reset(seed=seed)
game = PlayableGame(env, keys_to_action, zoom)

pressed_keys = []
running = True
env_done = True

screen = pygame.display.set_mode(video_size)
done = True
clock = pygame.time.Clock()

while running:
if env_done:
env_done = False
obs = env.reset()
while game.running:
if done:
done = False
obs = env.reset(seed=seed)
else:
action = keys_to_action.get(tuple(sorted(pressed_keys)), 0)
action = keys_to_action.get(tuple(sorted(game.pressed_keys)), 0)
prev_obs = obs
obs, rew, env_done, info = env.step(action)
obs, rew, done, info = env.step(action)
if callback is not None:
callback(prev_obs, obs, action, rew, env_done, info)
callback(prev_obs, obs, action, rew, done, info)
if obs is not None:
# TODO: this needs to be updated when the render API change goes through
rendered = env.render(mode="rgb_array")
display_arr(screen, rendered, transpose=transpose, video_size=video_size)
display_arr(
game.screen, rendered, transpose=transpose, video_size=game.video_size
)

# process pygame events
for event in pygame.event.get():
# test events, set key states
if event.type == pygame.KEYDOWN:
if event.key in relevant_keys:
pressed_keys.append(event.key)
elif event.key == 27:
running = False
elif event.type == pygame.KEYUP:
if event.key in relevant_keys:
pressed_keys.remove(event.key)
elif event.type == pygame.QUIT:
running = False
elif event.type == VIDEORESIZE:
video_size = event.size
screen = pygame.display.set_mode(video_size)
print(video_size)
game.process_event(event)

pygame.display.flip()
clock.tick(fps)
Expand Down Expand Up @@ -180,20 +226,3 @@ def callback(self, obs_t, obs_tp1, action, rew, done, info):
)
self.ax[i].set_xlim(xmin, xmax)
plt.pause(0.000001)


def main():
parser = argparse.ArgumentParser()
parser.add_argument(
"--env",
type=str,
default="MontezumaRevengeNoFrameskip-v4",
help="Define Environment",
)
args = parser.parse_args()
env = gym.make(args.env)
play(env, zoom=4, fps=60)


if __name__ == "__main__":
main()
Loading