tinysim 0.0.4__py3-none-any.whl → 0.0.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. tinysim/__init__.py +7 -2
  2. tinysim/_tk_base.py +20 -2
  3. tinysim/_widget_base.py +41 -0
  4. tinysim/flappy/__init__.py +5 -3
  5. tinysim/flappy/tk.py +10 -34
  6. tinysim/flappy/widget.py +9 -38
  7. tinysim/frogger/__init__.py +21 -4
  8. tinysim/frogger/tk.py +12 -28
  9. tinysim/frogger/widget.py +8 -37
  10. tinysim/mountain_car/__init__.py +17 -12
  11. tinysim/mountain_car/tk.py +9 -27
  12. tinysim/mountain_car/widget.py +8 -37
  13. tinysim/tinyspace.py +68 -0
  14. tinysim/topdown_driving/__init__.py +16 -18
  15. tinysim/topdown_driving/tk.py +13 -38
  16. tinysim/topdown_driving/track_0.json +1 -753
  17. tinysim/topdown_driving/widget.py +8 -42
  18. {tinysim-0.0.4.dist-info → tinysim-0.0.5.dist-info}/METADATA +5 -6
  19. {tinysim-0.0.4.dist-info → tinysim-0.0.5.dist-info}/RECORD +35 -35
  20. {tinysim-0.0.4.dist-info → tinysim-0.0.5.dist-info}/WHEEL +1 -1
  21. tinysim_mujoco/gl_viewer.py +36 -11
  22. tinysim_mujoco/manipulation/__init__.py +19 -5
  23. tinysim_mujoco/manipulation/push_env.py +268 -0
  24. tinysim_mujoco/manipulation/push_env_cam.py +274 -0
  25. tinysim_mujoco/manipulation/xmls/panda.xml +59 -16
  26. tinysim_mujoco/manipulation/xmls/scene.xml +0 -3
  27. tinysim_mujoco/manipulation/xmls/table.xml +17 -13
  28. tinysim_mujoco/notebook_viewer.py +3 -6
  29. tinysim_mujoco/unitree_a1/__init__.py +7 -10
  30. tinysim_warp/__init__.py +108 -0
  31. tinysim_warp/cart_pole/__init__.py +44 -200
  32. tinysim_warp/quadruped/__init__.py +23 -160
  33. tinysim_warp/simple_quadruped/__init__.py +20 -91
  34. tinysim_warp/simple_quadruped/simple_quadruped.urdf +0 -9
  35. tinysim/simple_amr/__init__.py +0 -0
  36. tinysim/simple_amr/example_maps.py +0 -121
  37. tinysim/simple_amr/sim.js +0 -430
  38. tinysim/simple_amr/styles.css +0 -54
  39. tinysim/simple_amr/widget.py +0 -73
  40. {tinysim-0.0.4.dist-info → tinysim-0.0.5.dist-info}/top_level.txt +0 -0
tinysim/__init__.py CHANGED
@@ -1,11 +1,16 @@
1
1
  from abc import ABC, abstractmethod
2
2
 
3
+ from .tinyspace import Space
4
+
3
5
 
4
6
  class SimEnvironment(ABC):
7
+
8
+ action_space: Space
9
+
5
10
  @abstractmethod
6
- def step(self, action) -> dict:
11
+ def step(self, *args, **kwargs):
7
12
  pass
8
13
 
9
14
  @abstractmethod
10
- def reset(self) -> dict:
15
+ def reset(self, *args, **kwargs):
11
16
  pass
tinysim/_tk_base.py CHANGED
@@ -1,11 +1,14 @@
1
- import tkinter as tk
2
1
  import threading
2
+ import tkinter as tk
3
3
  from abc import ABC, abstractmethod
4
4
 
5
+ from . import SimEnvironment
6
+
5
7
 
6
8
  class TkBaseFrontend(ABC):
7
9
 
8
- def __init__(self):
10
+ def __init__(self, sim_env: SimEnvironment):
11
+ self.sim_env = sim_env
9
12
  self._root = None
10
13
  self._canvas = None
11
14
  self._thread = None
@@ -16,6 +19,21 @@ class TkBaseFrontend(ABC):
16
19
  self._thread = threading.Thread(target=self._window_hook, daemon=True)
17
20
  self._thread.start()
18
21
 
22
+ def step(self, *args, **kwargs):
23
+ state = self.sim_env.step(*args, **kwargs)
24
+ if self._root:
25
+ self._root.after(0, lambda: self._draw_state(state))
26
+ return state
27
+
28
+ def reset(self, *args, **kwargs):
29
+ state = self.sim_env.reset()
30
+ if self._canvas:
31
+ self._draw_state(state)
32
+ return state
33
+
34
+ def _draw_state(self, state):
35
+ raise NotImplementedError
36
+
19
37
  def _window_hook(self):
20
38
  root = tk.Tk()
21
39
  root.protocol("WM_DELETE_WINDOW", self._on_close)
@@ -0,0 +1,41 @@
1
+ import anywidget
2
+ import traitlets
3
+ from IPython.display import display
4
+ from jupyter_ui_poll import ui_events
5
+
6
+ from . import SimEnvironment
7
+
8
+
9
+ class BaseWidget(anywidget.AnyWidget):
10
+
11
+ sim_env: SimEnvironment
12
+ _view_ready = traitlets.Bool(default_value=False).tag(sync=True)
13
+
14
+ def __init__(self, sim_env: SimEnvironment):
15
+ super().__init__()
16
+ self.sim_env = sim_env
17
+ self.sim_state = self.sim_env.reset()
18
+ self._update_props(self.sim_state)
19
+
20
+ def render(self):
21
+ display(self)
22
+
23
+ try:
24
+ with ui_events() as ui_poll:
25
+ while not self._view_ready:
26
+ ui_poll(100)
27
+ except Exception:
28
+ pass
29
+
30
+ def _update_props(self, sim_state):
31
+ self.sim_state = sim_state
32
+
33
+ def step(self, *args, **kwargs):
34
+ sim_state = self.sim_env.step(*args, **kwargs)
35
+ self._update_props(sim_state)
36
+ return sim_state
37
+
38
+ def reset(self, *args, **kwargs):
39
+ sim_state = self.sim_env.reset(*args, **kwargs)
40
+ self._update_props(sim_state)
41
+ return sim_state
@@ -1,5 +1,7 @@
1
1
  import numpy as np
2
+
2
3
  from .. import SimEnvironment
4
+ from ..tinyspace import Discrete
3
5
 
4
6
  WIDTH, HEIGHT = 800, 600
5
7
  GRAVITY = 900.0
@@ -16,6 +18,7 @@ BIRD_SIZE = 35
16
18
  class FlappyEnv(SimEnvironment):
17
19
  def __init__(self, num_envs: int = 1):
18
20
  self.num_envs = num_envs
21
+ self.action_space = Discrete(2) # 0: no flap, 1: flap
19
22
  self.reset()
20
23
 
21
24
  def reset(self):
@@ -54,16 +57,15 @@ class FlappyEnv(SimEnvironment):
54
57
  self.pipes_x = self.pipes_x[keep]
55
58
  self.pipes_y = self.pipes_y[keep]
56
59
 
57
- def _check_collisions(self): # world bounds
60
+ def _check_collisions(self):
58
61
  hit_bounds = (self.bird_y < 0) | (self.bird_y + BIRD_SIZE > HEIGHT)
59
- bx = BIRD_X
60
62
  by = self.bird_y[:, None]
61
63
  px = self.pipes_x[None, :]
62
64
  upper_y = np.zeros_like(self.pipes_y)[None, :]
63
65
  upper_h = self.pipes_y[None, :]
64
66
  lower_y = (self.pipes_y + PIPE_GAP)[None, :]
65
67
  lower_h = (HEIGHT - (self.pipes_y + PIPE_GAP))[None, :]
66
- x_overlap = (bx < px + PIPE_WIDTH) & (bx + BIRD_SIZE > px)
68
+ x_overlap = (BIRD_X < px + PIPE_WIDTH) & (BIRD_X + BIRD_SIZE > px)
67
69
  upper_hit = x_overlap & (by < upper_y + upper_h) & (by + BIRD_SIZE > upper_y)
68
70
  lower_hit = x_overlap & (by < lower_y + lower_h) & (by + BIRD_SIZE > lower_y)
69
71
  hit_pipe = (upper_hit | lower_hit).any(axis=1)
tinysim/flappy/tk.py CHANGED
@@ -1,45 +1,22 @@
1
- import asyncio
2
-
3
1
  try:
4
2
  import tkinter as tk
5
- from .. import _tk_base
3
+
4
+ from .._tk_base import TkBaseFrontend
6
5
  except ImportError:
7
6
  raise ImportError("tkinter is required for FlappyTkFrontend")
8
7
 
9
- from . import (
10
- FlappyEnv,
11
- WIDTH,
12
- HEIGHT,
13
- PIPE_WIDTH,
14
- BIRD_SIZE,
15
- BIRD_X,
16
- PIPE_GAP,
17
- )
18
-
19
-
20
- class FlappyTkFrontend(_tk_base.TkBaseFrontend):
8
+ from . import BIRD_SIZE, BIRD_X, HEIGHT, PIPE_GAP, PIPE_WIDTH, WIDTH, FlappyEnv
21
9
 
22
- def __init__(self, viewport_size=(800, 600), sim_env=None):
23
- super().__init__()
24
- if sim_env is None:
25
- sim_env = FlappyEnv()
26
10
 
27
- self.sim_env = sim_env
11
+ class FlappyTkFrontend(TkBaseFrontend):
12
+ def __init__(self, viewport_size=(800, 600), sim_env=FlappyEnv()):
13
+ super().__init__(sim_env)
28
14
  self._viewport_size = viewport_size
29
15
 
30
- async def step(self, action, dt=0.02):
31
- state = self.sim_env.step(action, dt=dt)
32
- if self._root:
33
- self._root.after(0, lambda: self._draw_state(state))
34
-
35
- await asyncio.sleep(dt)
36
- return state
37
-
38
- async def reset(self):
39
- state = self.sim_env.reset()
40
- if self._root:
41
- self._draw_state(state)
42
- return state
16
+ if sim_env.num_envs != 1:
17
+ raise ValueError(
18
+ "FlappyTkFrontend currently only supports single environment."
19
+ )
43
20
 
44
21
  def _create_window(self, root):
45
22
  w, h = self._viewport_size
@@ -66,7 +43,6 @@ class FlappyTkFrontend(_tk_base.TkBaseFrontend):
66
43
 
67
44
  # bird
68
45
  by = state["bird_y"]
69
-
70
46
  if not state.get("done", False):
71
47
  canvas.create_oval(
72
48
  BIRD_X,
tinysim/flappy/widget.py CHANGED
@@ -1,53 +1,24 @@
1
1
  import pathlib
2
- import anywidget
2
+
3
3
  import traitlets
4
- import asyncio
5
- from IPython.display import display
6
- from jupyter_ui_poll import ui_events
7
4
 
5
+ from .._widget_base import BaseWidget
8
6
  from . import FlappyEnv
9
7
 
10
8
 
11
- class FlappySim(anywidget.AnyWidget):
9
+ class FlappySim(BaseWidget):
12
10
  _esm = pathlib.Path(__file__).parent / "sim.js"
13
11
 
14
12
  sim_state = traitlets.Dict(default_value={}).tag(sync=True)
15
- _viewport_size = traitlets.Tuple(
16
- traitlets.Int(), traitlets.Int(), default_value=(800, 600)
17
- ).tag(sync=True)
13
+ _viewport_size = traitlets.Tuple(default_value=(800, 600)).tag(sync=True)
18
14
  _manual_control = traitlets.Bool(default_value=False).tag(sync=True)
19
- _view_ready = traitlets.Bool(default_value=False).tag(sync=True)
20
15
 
21
- def __init__(self, viewport_size=(800, 600), manual_control=False, sim_env=None):
22
- super().__init__()
16
+ def __init__(
17
+ self, viewport_size=(800, 600), manual_control=False, sim_env=FlappyEnv()
18
+ ):
19
+ super().__init__(sim_env)
23
20
  self._viewport_size = viewport_size
24
21
  self._manual_control = manual_control
25
- if sim_env is None:
26
- sim_env = FlappyEnv()
22
+
27
23
  if sim_env.num_envs != 1:
28
24
  raise ValueError("FlappySim currently only supports single environment.")
29
-
30
- self.sim_env = sim_env
31
- self.sim_state = self.sim_env.reset()
32
-
33
- def render(self):
34
- display(self)
35
-
36
- try:
37
- with ui_events() as ui_poll:
38
- while not self._view_ready:
39
- ui_poll(100)
40
- except Exception:
41
- pass
42
-
43
- async def step(self, action, dt=0.02):
44
- state = self.sim_env.step(action, dt=dt)
45
- self.sim_state = state
46
- await asyncio.sleep(dt)
47
- return state
48
-
49
- async def reset(self):
50
- state = self.sim_env.reset()
51
- self.sim_state = state
52
- await asyncio.sleep(0)
53
- return state
@@ -1,5 +1,7 @@
1
1
  import numpy as np
2
+
2
3
  from .. import SimEnvironment
4
+ from ..tinyspace import Discrete
3
5
 
4
6
  WIDTH, HEIGHT = 800, 600
5
7
  CELL = 40
@@ -14,6 +16,9 @@ class FroggerEnv(SimEnvironment):
14
16
  self.car_width = CELL * 2
15
17
  self.traffic_rows = np.array([4, 5, 6, 8, 9])
16
18
  self.speeds = np.array([120, -150, 200, -180, 140], dtype=np.float32)
19
+ self.done = np.zeros(self.num_envs, dtype=bool)
20
+
21
+ self.action_space = Discrete(5) # 0: stay, 1: left, 2: right, 3: up, 4: down
17
22
  self.reset()
18
23
 
19
24
  def reset(self):
@@ -62,9 +67,17 @@ class FroggerEnv(SimEnvironment):
62
67
  dx = np.array([action_map[a][0] for a in action])
63
68
  dy = np.array([action_map[a][1] for a in action])
64
69
 
65
- # Move frogs
66
- self.frog_pos[:, 0] = np.clip(self.frog_pos[:, 0] + dx, 0, COLS - 1)
67
- self.frog_pos[:, 1] = np.clip(self.frog_pos[:, 1] + dy, 0, ROWS - 1)
70
+ # Move frogs only move frog if not done
71
+ self.frog_pos[:, 0] = np.where(
72
+ ~self.done,
73
+ np.clip(self.frog_pos[:, 0] + dx, 0, COLS - 1),
74
+ self.frog_pos[:, 0],
75
+ )
76
+ self.frog_pos[:, 1] = np.where(
77
+ ~self.done,
78
+ np.clip(self.frog_pos[:, 1] + dy, 0, ROWS - 1),
79
+ self.frog_pos[:, 1],
80
+ )
68
81
 
69
82
  # Update car positions
70
83
  self.car_x += self.speeds[:, None] * dt
@@ -127,6 +140,10 @@ class FroggerEnv(SimEnvironment):
127
140
  current_height = self.total_height - self.frog_pos[:, 1]
128
141
  self.score = self.crossings + current_height / self.total_height
129
142
 
143
+ # Added to persist done state
144
+ self.done = done | self.done
145
+ done = self.done
146
+
130
147
  frog_pos = self.frog_pos.tolist()
131
148
  grid = self._build_car_grid().tolist()
132
149
  scores = self.score.tolist()
@@ -140,6 +157,6 @@ class FroggerEnv(SimEnvironment):
140
157
  return {
141
158
  "frog_pos": frog_pos,
142
159
  "grid": grid,
143
- "done": done,
144
160
  "score": scores,
161
+ "done": done,
145
162
  }
tinysim/frogger/tk.py CHANGED
@@ -1,41 +1,24 @@
1
- import asyncio
2
- from . import FroggerEnv, WIDTH, HEIGHT, CELL, ROWS, COLS
1
+ from . import CELL, COLS, HEIGHT, ROWS, WIDTH, FroggerEnv
3
2
 
4
3
  try:
5
4
  import tkinter as tk
6
- from .. import _tk_base
5
+
6
+ from .._tk_base import TkBaseFrontend
7
7
  except ImportError:
8
8
  raise ImportError("tkinter is required for FroggerTkFrontend")
9
9
 
10
10
 
11
- class FroggerTkFrontend(_tk_base.TkBaseFrontend):
11
+ class FroggerTkFrontend(TkBaseFrontend):
12
+
13
+ def __init__(self, viewport_size=(800, 600), sim_env=FroggerEnv()):
14
+ super().__init__(sim_env)
15
+ self._viewport_size = viewport_size
16
+ self.keys = set()
12
17
 
13
- def __init__(self, viewport_size=(800, 600), sim_env=None):
14
- super().__init__()
15
- if sim_env is None:
16
- sim_env = FroggerEnv()
17
18
  if sim_env.num_envs != 1:
18
19
  raise ValueError(
19
20
  "FroggerTkFrontend currently only supports single environment."
20
21
  )
21
- self.sim_env = sim_env
22
- self._viewport_size = viewport_size
23
-
24
- self.keys = set()
25
-
26
- async def step(self, action, dt=0.01):
27
- state = self.sim_env.step(action, dt=dt)
28
- if self._root:
29
- self._root.after(0, lambda: self._draw_state(self.sim_env))
30
-
31
- await asyncio.sleep(dt)
32
- return state
33
-
34
- async def reset(self):
35
- state = self.sim_env.reset()
36
- if self._canvas:
37
- self._draw_state(self.sim_env)
38
- return state
39
22
 
40
23
  def _create_window(self, root):
41
24
  w, h = self._viewport_size
@@ -49,11 +32,12 @@ class FroggerTkFrontend(_tk_base.TkBaseFrontend):
49
32
  root.bind("<KeyRelease>", lambda e: self.keys.discard(e.keysym))
50
33
 
51
34
  self.bring_to_front(root)
52
- self._draw_state(self.sim_env)
35
+ self._draw_state()
53
36
  self._pump()
54
37
  root.mainloop()
55
38
 
56
- def _draw_state(self, sim_env: FroggerEnv):
39
+ def _draw_state(self, state=None):
40
+ sim_env = self.sim_env
57
41
  if not self._canvas:
58
42
  return
59
43
 
tinysim/frogger/widget.py CHANGED
@@ -1,60 +1,31 @@
1
1
  import pathlib
2
- import anywidget
3
- import traitlets
4
- import asyncio
2
+
5
3
  import numpy as np
6
- from IPython.display import display
7
- from jupyter_ui_poll import ui_events
4
+ import traitlets
8
5
 
6
+ from .._widget_base import BaseWidget
9
7
  from . import FroggerEnv
10
8
 
11
9
 
12
- class FroggerWidget(anywidget.AnyWidget):
10
+ class FroggerWidget(BaseWidget):
13
11
  _esm = pathlib.Path(__file__).parent / "sim.js"
14
12
 
15
13
  sim_state = traitlets.Dict(default_value={}).tag(sync=True)
16
14
  car_positions = traitlets.List(default_value=[]).tag(sync=True)
17
- _viewport_size = traitlets.Tuple(
18
- traitlets.Int(), traitlets.Int(), default_value=(800, 600)
19
- ).tag(sync=True)
20
- _view_ready = traitlets.Bool(default_value=False).tag(sync=True)
15
+ _viewport_size = traitlets.Tuple(default_value=(800, 600)).tag(sync=True)
21
16
 
22
17
  def get_car_positions(self):
23
18
  return np.vstack(self.sim_env.car_rects).flatten().tolist()
24
19
 
25
- def __init__(self, viewport_size=(800, 600), sim_env=None):
20
+ def __init__(self, viewport_size=(800, 600), sim_env=FroggerEnv()):
21
+ super().__init__(sim_env)
26
22
  self._viewport_size = viewport_size
27
- super().__init__()
28
- if sim_env is None:
29
- sim_env = FroggerEnv()
30
23
 
31
24
  if sim_env.num_envs != 1:
32
25
  raise ValueError(
33
26
  "FroggerWidget currently only supports single environment."
34
27
  )
35
28
 
36
- self.sim_env = sim_env
37
- self.sim_state = self.sim_env.reset()
38
- self.car_positions = self.get_car_positions()
39
-
40
- def render(self):
41
- display(self)
42
-
43
- try:
44
- with ui_events() as ui_poll:
45
- while not self._view_ready:
46
- ui_poll(100)
47
- except Exception:
48
- pass
49
-
50
- async def step(self, action: int, dt: float = 0.01) -> dict:
51
- sim_state = self.sim_env.step(action)
29
+ def _update_props(self, sim_state):
52
30
  self.sim_state = sim_state
53
31
  self.car_positions = self.get_car_positions()
54
- await asyncio.sleep(dt)
55
- return sim_state
56
-
57
- async def reset(self) -> dict:
58
- sim_state = self.sim_env.reset()
59
- self.sim_state = sim_state
60
- return sim_state
@@ -1,5 +1,7 @@
1
1
  import numpy as np
2
+
2
3
  from .. import SimEnvironment
4
+ from ..tinyspace import Discrete
3
5
 
4
6
 
5
7
  class MountainCarEnv(SimEnvironment):
@@ -12,12 +14,12 @@ class MountainCarEnv(SimEnvironment):
12
14
  self.force = 0.001
13
15
  self.gravity = 0.0025
14
16
  self.goal_position = 0.5
17
+ self.reset()
15
18
 
16
- # initial state
17
- self.position = np.full(num_envs, -0.5, dtype=np.float32)
18
- self.velocity = np.zeros(num_envs, dtype=np.float32)
19
+ # actions: 0 (left), 1 (no push), 2 (right)
20
+ self.action_space = Discrete(3)
19
21
 
20
- def step(self, action) -> dict:
22
+ def step(self, action):
21
23
  if np.isscalar(action):
22
24
  action = np.full(self.num_envs, action, dtype=np.float32)
23
25
  else:
@@ -46,11 +48,14 @@ class MountainCarEnv(SimEnvironment):
46
48
 
47
49
  return {"position": self.position, "velocity": self.velocity, "done": done}
48
50
 
49
- def reset(self) -> dict:
50
- self.position = -0.5
51
- self.velocity = 0.0
52
- return {
53
- "position": self.position,
54
- "velocity": self.velocity,
55
- "done": self.position >= self.goal_position,
56
- }
51
+ def reset(self, **kwargs) -> dict:
52
+ self.position = np.full(self.num_envs, -0.5, dtype=np.float32)
53
+ self.velocity = np.zeros(self.num_envs, dtype=np.float32)
54
+ done = self.position >= self.goal_position
55
+
56
+ if self.num_envs == 1:
57
+ self.position = float(self.position[0])
58
+ self.velocity = float(self.velocity[0])
59
+ done = bool(done[0])
60
+
61
+ return {"position": self.position, "velocity": self.velocity, "done": done}
@@ -1,39 +1,23 @@
1
- import asyncio
2
1
  import math
2
+
3
3
  import numpy as np
4
+
4
5
  from . import MountainCarEnv
5
6
 
6
7
  try:
7
8
  import tkinter as tk
8
- from .. import _tk_base
9
+
10
+ from .._tk_base import TkBaseFrontend
9
11
  except ImportError:
10
12
  raise ImportError("tkinter is required for MountainCarTkFrontend")
11
13
 
12
14
 
13
- class MountainCarTkFrontend(_tk_base.TkBaseFrontend):
15
+ class MountainCarTkFrontend(TkBaseFrontend):
14
16
 
15
- def __init__(self, viewport_size=(600, 400), sim_env=None):
16
- super().__init__()
17
- if sim_env is None:
18
- sim_env = MountainCarEnv()
19
- self.sim_env = sim_env
17
+ def __init__(self, viewport_size=(600, 400), sim_env=MountainCarEnv()):
18
+ super().__init__(sim_env)
20
19
  self._viewport_size = viewport_size
21
20
 
22
- async def step(self, action, dt=0.01):
23
- state = self.sim_env.step(action)
24
-
25
- if self._root:
26
- self._root.after(0, lambda s=state: self._draw_state(s))
27
-
28
- await asyncio.sleep(dt)
29
- return state
30
-
31
- async def reset(self):
32
- state = self.sim_env.reset()
33
- if self._canvas:
34
- self._draw_state(state)
35
- return state
36
-
37
21
  def _create_window(self, root):
38
22
  w, h = self._viewport_size
39
23
  root.title("Mountain Car")
@@ -46,7 +30,7 @@ class MountainCarTkFrontend(_tk_base.TkBaseFrontend):
46
30
  self._pump()
47
31
  root.mainloop()
48
32
 
49
- def _draw_state(self, state: dict):
33
+ def _draw_state(self, state=None):
50
34
  if not self._canvas:
51
35
  return
52
36
 
@@ -54,12 +38,10 @@ class MountainCarTkFrontend(_tk_base.TkBaseFrontend):
54
38
  w = int(c.winfo_width() or self._viewport_size[0])
55
39
  h = int(c.winfo_height() or self._viewport_size[1])
56
40
  c.delete("all")
57
-
58
41
  min_x = self.sim_env.min_position
59
42
  max_x = self.sim_env.max_position
60
43
  world_width = max_x - min_x
61
44
  scale = w / world_width
62
- clearance = 10
63
45
 
64
46
  def heightFn(x):
65
47
  return np.sin(3 * x) * 0.45 + 0.55
@@ -105,7 +87,7 @@ class MountainCarTkFrontend(_tk_base.TkBaseFrontend):
105
87
  for i, x_world in enumerate(positions):
106
88
  y_world = heightFn(x_world)
107
89
  x_screen = (x_world - min_x) * scale
108
- y_screen = h - y_world * scale - clearance
90
+ y_screen = h - y_world * scale
109
91
 
110
92
  slope = math.cos(3 * x_world)
111
93
  angle = -math.atan(slope)
@@ -1,56 +1,27 @@
1
1
  import pathlib
2
- import anywidget
2
+
3
3
  import traitlets
4
- import asyncio
5
- from IPython.display import display
6
- from jupyter_ui_poll import ui_events
7
4
 
5
+ from .._widget_base import BaseWidget
8
6
  from . import MountainCarEnv
9
7
 
10
8
 
11
- class MountainCarWidget(anywidget.AnyWidget):
9
+ class MountainCarWidget(BaseWidget):
12
10
  _esm = pathlib.Path(__file__).parent / "sim.js"
13
11
  _css = pathlib.Path(__file__).parent / "styles.css"
14
12
 
15
13
  sim_state = traitlets.Dict(default_value={}).tag(sync=True)
16
- _viewport_size = traitlets.Tuple(
17
- traitlets.Int(), traitlets.Int(), default_value=(600, 400)
18
- ).tag(sync=True)
19
- _view_ready = traitlets.Bool(default_value=False).tag(sync=True)
14
+ _viewport_size = traitlets.Tuple(default_value=(600, 400)).tag(sync=True)
20
15
  _manual_control = traitlets.Bool(default_value=False).tag(sync=True)
21
16
 
22
- def __init__(self, manual_control=False, viewport_size=(600, 400), sim_env=None):
17
+ def __init__(
18
+ self, manual_control=False, viewport_size=(600, 400), sim_env=MountainCarEnv()
19
+ ):
20
+ super().__init__(sim_env)
23
21
  self._manual_control = manual_control
24
22
  self._viewport_size = viewport_size
25
- super().__init__()
26
- if sim_env is None:
27
- sim_env = MountainCarEnv()
28
23
 
29
24
  if sim_env.num_envs != 1:
30
25
  raise ValueError(
31
26
  "MountainCarWidget currently only supports single environment."
32
27
  )
33
-
34
- self.sim_env = sim_env
35
- self.sim_state = self.sim_env.reset()
36
-
37
- def render(self):
38
- display(self)
39
-
40
- try:
41
- with ui_events() as ui_poll:
42
- while not self._view_ready:
43
- ui_poll(100)
44
- except Exception:
45
- pass
46
-
47
- async def step(self, action: int, dt: float = 0.01) -> dict:
48
- sim_state = self.sim_env.step(action)
49
- self.sim_state = sim_state
50
- await asyncio.sleep(dt)
51
- return sim_state
52
-
53
- async def reset(self) -> dict:
54
- sim_state = self.sim_env.reset()
55
- self.sim_state = sim_state
56
- return sim_state