miniworld-maze 1.0.0__py3-none-any.whl → 1.1.0__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.
Potentially problematic release.
This version of miniworld-maze might be problematic. Click here for more details.
- miniworld_maze/__init__.py +0 -4
- miniworld_maze/core/miniworld_gymnasium/unified_env.py +42 -21
- miniworld_maze/environments/__init__.py +1 -2
- miniworld_maze/environments/base_grid_rooms.py +140 -1
- miniworld_maze/environments/factory.py +7 -57
- miniworld_maze/environments/nine_rooms.py +15 -0
- miniworld_maze/environments/spiral_nine_rooms.py +15 -0
- miniworld_maze/environments/twenty_five_rooms.py +14 -0
- miniworld_maze/tools/generate_observations.py +3 -3
- miniworld_maze-1.1.0.dist-info/METADATA +250 -0
- {miniworld_maze-1.0.0.dist-info → miniworld_maze-1.1.0.dist-info}/RECORD +13 -15
- {miniworld_maze-1.0.0.dist-info → miniworld_maze-1.1.0.dist-info}/WHEEL +1 -1
- miniworld_maze/wrappers/__init__.py +0 -5
- miniworld_maze/wrappers/image_transforms.py +0 -40
- miniworld_maze-1.0.0.dist-info/METADATA +0 -108
- {miniworld_maze-1.0.0.dist-info → miniworld_maze-1.1.0.dist-info}/entry_points.txt +0 -0
miniworld_maze/__init__.py
CHANGED
|
@@ -18,8 +18,6 @@ Main modules:
|
|
|
18
18
|
from .core import ObservationLevel
|
|
19
19
|
from .environments.factory import (
|
|
20
20
|
NineRoomsEnvironmentWrapper,
|
|
21
|
-
create_drstrategy_env,
|
|
22
|
-
create_nine_rooms_env,
|
|
23
21
|
)
|
|
24
22
|
from .environments.nine_rooms import NineRooms
|
|
25
23
|
from .environments.spiral_nine_rooms import SpiralNineRooms
|
|
@@ -27,8 +25,6 @@ from .environments.twenty_five_rooms import TwentyFiveRooms
|
|
|
27
25
|
|
|
28
26
|
__version__ = "1.0.0"
|
|
29
27
|
__all__ = [
|
|
30
|
-
"create_drstrategy_env",
|
|
31
|
-
"create_nine_rooms_env", # deprecated but kept for backward compatibility
|
|
32
28
|
"NineRoomsEnvironmentWrapper",
|
|
33
29
|
"NineRooms",
|
|
34
30
|
"SpiralNineRooms",
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import math
|
|
4
4
|
from ctypes import POINTER
|
|
5
5
|
from enum import IntEnum
|
|
6
|
+
from typing import List, Optional
|
|
6
7
|
|
|
7
8
|
import gymnasium as gym
|
|
8
9
|
import numpy as np
|
|
@@ -10,6 +11,7 @@ import pyglet
|
|
|
10
11
|
from gymnasium import spaces
|
|
11
12
|
from pyglet.gl import *
|
|
12
13
|
|
|
14
|
+
from ..observation_types import ObservationLevel
|
|
13
15
|
from .entities import *
|
|
14
16
|
from .math import *
|
|
15
17
|
from .objmesh import *
|
|
@@ -95,6 +97,7 @@ class UnifiedMiniWorldEnv(gym.Env):
|
|
|
95
97
|
window_height=DEFAULT_WINDOW_HEIGHT,
|
|
96
98
|
params=DEFAULT_PARAMS,
|
|
97
99
|
domain_rand=False,
|
|
100
|
+
info_obs: Optional[List[ObservationLevel]] = None,
|
|
98
101
|
):
|
|
99
102
|
"""
|
|
100
103
|
Initialize unified MiniWorld environment.
|
|
@@ -110,6 +113,7 @@ class UnifiedMiniWorldEnv(gym.Env):
|
|
|
110
113
|
window_height: Window height for human rendering
|
|
111
114
|
params: Environment parameters for domain randomization
|
|
112
115
|
domain_rand: Whether to enable domain randomization
|
|
116
|
+
info_obs: List of observation levels to include in info dictionary
|
|
113
117
|
"""
|
|
114
118
|
# Store configuration
|
|
115
119
|
self.obs_level = obs_level
|
|
@@ -118,6 +122,7 @@ class UnifiedMiniWorldEnv(gym.Env):
|
|
|
118
122
|
self.max_episode_steps = max_episode_steps
|
|
119
123
|
self.params = params
|
|
120
124
|
self.domain_rand = domain_rand
|
|
125
|
+
self.info_obs = info_obs
|
|
121
126
|
|
|
122
127
|
# Setup action space
|
|
123
128
|
self._setup_action_space()
|
|
@@ -329,8 +334,20 @@ class UnifiedMiniWorldEnv(gym.Env):
|
|
|
329
334
|
# Generate the first camera image
|
|
330
335
|
obs = self._generate_observation()
|
|
331
336
|
|
|
337
|
+
# Generate additional observations for info dictionary if specified
|
|
338
|
+
info = {}
|
|
339
|
+
if self.info_obs is not None:
|
|
340
|
+
for obs_level in self.info_obs:
|
|
341
|
+
# Temporarily change obs_level to generate the desired observation
|
|
342
|
+
original_obs_level = self.obs_level
|
|
343
|
+
self.obs_level = obs_level
|
|
344
|
+
info_obs = self._generate_observation()
|
|
345
|
+
self.obs_level = original_obs_level
|
|
346
|
+
# Use the observation level name as key
|
|
347
|
+
info[str(obs_level)] = info_obs
|
|
348
|
+
|
|
332
349
|
# Return first observation with info dict for Gymnasium compatibility
|
|
333
|
-
return obs,
|
|
350
|
+
return obs, info
|
|
334
351
|
|
|
335
352
|
def _generate_observation(self, render_agent: bool = None):
|
|
336
353
|
"""Generate observation based on current observation level.
|
|
@@ -369,18 +386,6 @@ class UnifiedMiniWorldEnv(gym.Env):
|
|
|
369
386
|
f"Invalid obs_level {self.obs_level}. Must be one of {valid_levels}"
|
|
370
387
|
)
|
|
371
388
|
|
|
372
|
-
def get_observation(self, render_agent: bool = None):
|
|
373
|
-
"""Public method to generate observation with optional agent rendering control.
|
|
374
|
-
|
|
375
|
-
Args:
|
|
376
|
-
render_agent: Whether to render the agent in the observation.
|
|
377
|
-
If None, uses default behavior based on observation level.
|
|
378
|
-
|
|
379
|
-
Returns:
|
|
380
|
-
np.ndarray: Generated observation image
|
|
381
|
-
"""
|
|
382
|
-
return self._generate_observation(render_agent=render_agent)
|
|
383
|
-
|
|
384
389
|
def _calculate_carried_object_position(self, agent_pos, ent):
|
|
385
390
|
"""Compute the position at which to place an object being carried."""
|
|
386
391
|
dist = self.agent.radius + ent.radius + self.max_forward_step
|
|
@@ -577,21 +582,37 @@ class UnifiedMiniWorldEnv(gym.Env):
|
|
|
577
582
|
if self.obs_level != 2: # Not TOP_DOWN_FULL
|
|
578
583
|
topdown = self.render_top_view(POMDP=False, frame_buffer=self.topdown_fb)
|
|
579
584
|
|
|
585
|
+
# Generate additional observations for info dictionary if specified
|
|
586
|
+
info = {}
|
|
587
|
+
if self.info_obs is not None:
|
|
588
|
+
for obs_level in self.info_obs:
|
|
589
|
+
# Temporarily change obs_level to generate the desired observation
|
|
590
|
+
original_obs_level = self.obs_level
|
|
591
|
+
self.obs_level = obs_level
|
|
592
|
+
info_obs = self._generate_observation()
|
|
593
|
+
self.obs_level = original_obs_level
|
|
594
|
+
# Use the observation level name as key
|
|
595
|
+
info[str(obs_level)] = info_obs
|
|
596
|
+
|
|
580
597
|
# Check termination
|
|
581
598
|
if self.step_count >= self.max_episode_steps:
|
|
582
599
|
terminated = True
|
|
583
600
|
reward = 0
|
|
584
|
-
info
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
601
|
+
info.update(
|
|
602
|
+
{
|
|
603
|
+
"pos": self.agent.pos,
|
|
604
|
+
"mdp_view": topdown if topdown is not None else observation,
|
|
605
|
+
}
|
|
606
|
+
)
|
|
588
607
|
else:
|
|
589
608
|
reward = 0
|
|
590
609
|
terminated = False
|
|
591
|
-
info
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
610
|
+
info.update(
|
|
611
|
+
{
|
|
612
|
+
"pos": self.agent.pos,
|
|
613
|
+
"mdp_view": topdown if topdown is not None else observation,
|
|
614
|
+
}
|
|
615
|
+
)
|
|
595
616
|
|
|
596
617
|
return reward, terminated, info
|
|
597
618
|
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
"""Nine Rooms environment implementations."""
|
|
2
2
|
|
|
3
3
|
from .base_grid_rooms import GridRoomsEnvironment
|
|
4
|
-
from .factory import NineRoomsEnvironmentWrapper
|
|
4
|
+
from .factory import NineRoomsEnvironmentWrapper
|
|
5
5
|
from .nine_rooms import NineRooms
|
|
6
6
|
from .spiral_nine_rooms import SpiralNineRooms
|
|
7
7
|
from .twenty_five_rooms import TwentyFiveRooms
|
|
8
8
|
|
|
9
9
|
__all__ = [
|
|
10
10
|
"GridRoomsEnvironment",
|
|
11
|
-
"create_nine_rooms_env",
|
|
12
11
|
"NineRoomsEnvironmentWrapper",
|
|
13
12
|
"NineRooms",
|
|
14
13
|
"SpiralNineRooms",
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import List, Optional, Tuple, Union
|
|
4
4
|
|
|
5
|
+
import cv2
|
|
6
|
+
import numpy as np
|
|
5
7
|
from gymnasium import spaces
|
|
6
8
|
|
|
7
9
|
from ..core import COLORS, Box, ObservationLevel
|
|
@@ -35,6 +37,7 @@ class GridRoomsEnvironment(UnifiedMiniWorldEnv):
|
|
|
35
37
|
grid_size: int,
|
|
36
38
|
connections: List[Tuple[int, int]],
|
|
37
39
|
textures: List[str],
|
|
40
|
+
goal_positions: List[List[List[float]]],
|
|
38
41
|
placed_room: Optional[int] = None,
|
|
39
42
|
obs_level: ObservationLevel = ObservationLevel.TOP_DOWN_PARTIAL,
|
|
40
43
|
continuous: bool = False,
|
|
@@ -52,6 +55,7 @@ class GridRoomsEnvironment(UnifiedMiniWorldEnv):
|
|
|
52
55
|
grid_size: Size of the grid (e.g., 3 for 3x3 grid)
|
|
53
56
|
connections: List of (room1, room2) tuples for connections
|
|
54
57
|
textures: List of texture names for each room
|
|
58
|
+
goal_positions: List of goal positions for each room
|
|
55
59
|
placed_room: Initial room index (defaults to 0)
|
|
56
60
|
obs_level: Observation level (defaults to 1)
|
|
57
61
|
continuous: Whether to use continuous actions (defaults to False)
|
|
@@ -77,6 +81,9 @@ class GridRoomsEnvironment(UnifiedMiniWorldEnv):
|
|
|
77
81
|
)
|
|
78
82
|
self.textures = textures
|
|
79
83
|
|
|
84
|
+
# Set goal positions
|
|
85
|
+
self.goal_positions = goal_positions
|
|
86
|
+
|
|
80
87
|
# Set placed room
|
|
81
88
|
if placed_room is None:
|
|
82
89
|
self.placed_room = 0 # Start in the first room
|
|
@@ -101,6 +108,10 @@ class GridRoomsEnvironment(UnifiedMiniWorldEnv):
|
|
|
101
108
|
# Mark this as a custom environment for background color handling
|
|
102
109
|
self._is_custom_env = True
|
|
103
110
|
|
|
111
|
+
# Store observation dimensions for rendering (needed before super().__init__)
|
|
112
|
+
self.obs_width = obs_width
|
|
113
|
+
self.obs_height = obs_height
|
|
114
|
+
|
|
104
115
|
super().__init__(
|
|
105
116
|
obs_level=obs_level,
|
|
106
117
|
max_episode_steps=MAX_EPISODE_STEPS,
|
|
@@ -114,6 +125,18 @@ class GridRoomsEnvironment(UnifiedMiniWorldEnv):
|
|
|
114
125
|
if not self.continuous:
|
|
115
126
|
self.action_space = spaces.Discrete(self.actions.move_forward + 1)
|
|
116
127
|
|
|
128
|
+
# Store original observation space before updating
|
|
129
|
+
original_obs_space = self.observation_space
|
|
130
|
+
|
|
131
|
+
# Update observation space to include desired_goal and achieved_goal
|
|
132
|
+
self.observation_space = spaces.Dict(
|
|
133
|
+
{
|
|
134
|
+
"observation": original_obs_space,
|
|
135
|
+
"desired_goal": original_obs_space,
|
|
136
|
+
"achieved_goal": original_obs_space,
|
|
137
|
+
}
|
|
138
|
+
)
|
|
139
|
+
|
|
117
140
|
def _generate_world_layout(self, pos=None):
|
|
118
141
|
rooms = []
|
|
119
142
|
|
|
@@ -201,4 +224,120 @@ class GridRoomsEnvironment(UnifiedMiniWorldEnv):
|
|
|
201
224
|
|
|
202
225
|
def step(self, action):
|
|
203
226
|
obs, reward, terminated, truncated, info = super().step(action)
|
|
204
|
-
|
|
227
|
+
|
|
228
|
+
# Check if goal is achieved
|
|
229
|
+
if self.is_goal_achieved():
|
|
230
|
+
terminated = True
|
|
231
|
+
reward = 1.0 # Positive reward for achieving goal
|
|
232
|
+
|
|
233
|
+
# Return observation as dict
|
|
234
|
+
obs_dict = {
|
|
235
|
+
"observation": obs,
|
|
236
|
+
"desired_goal": self.desired_goal,
|
|
237
|
+
"achieved_goal": obs,
|
|
238
|
+
}
|
|
239
|
+
return obs_dict, reward, terminated, truncated, info
|
|
240
|
+
|
|
241
|
+
def reset(self, seed=None, options=None, pos=None):
|
|
242
|
+
"""
|
|
243
|
+
Reset the environment and generate a new goal.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
seed: Random seed
|
|
247
|
+
options: Additional options
|
|
248
|
+
pos: Agent starting position
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
tuple: (observation, info)
|
|
252
|
+
"""
|
|
253
|
+
# Call parent reset
|
|
254
|
+
obs, info = super().reset(seed=seed, options=options, pos=pos)
|
|
255
|
+
|
|
256
|
+
# Generate goal
|
|
257
|
+
self.desired_goal = self.get_goal()
|
|
258
|
+
|
|
259
|
+
# Return observation as dict with desired_goal and achieved_goal
|
|
260
|
+
obs_dict = {
|
|
261
|
+
"observation": obs,
|
|
262
|
+
"desired_goal": self.desired_goal,
|
|
263
|
+
"achieved_goal": obs,
|
|
264
|
+
}
|
|
265
|
+
return obs_dict, info
|
|
266
|
+
|
|
267
|
+
def get_goal(self):
|
|
268
|
+
"""
|
|
269
|
+
Generate a goal by randomly selecting a room and goal position.
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
np.ndarray: Rendered goal image
|
|
273
|
+
"""
|
|
274
|
+
# Select random room
|
|
275
|
+
room_idx = np.random.randint(len(self.goal_positions))
|
|
276
|
+
|
|
277
|
+
# Select random goal within room
|
|
278
|
+
goal_idx = np.random.randint(len(self.goal_positions[room_idx]))
|
|
279
|
+
|
|
280
|
+
# Get goal position
|
|
281
|
+
goal_position = self.goal_positions[room_idx][goal_idx]
|
|
282
|
+
self._current_goal_position = goal_position
|
|
283
|
+
self._current_goal_room = room_idx
|
|
284
|
+
self._current_goal_idx = goal_idx
|
|
285
|
+
|
|
286
|
+
# Render goal image
|
|
287
|
+
goal_image = self.render_on_pos(goal_position)
|
|
288
|
+
|
|
289
|
+
return goal_image
|
|
290
|
+
|
|
291
|
+
def render_on_pos(self, pos):
|
|
292
|
+
"""
|
|
293
|
+
Render observation from a specific position.
|
|
294
|
+
|
|
295
|
+
Args:
|
|
296
|
+
pos: Position to render from [x, y, z]
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
np.ndarray: Rendered observation
|
|
300
|
+
"""
|
|
301
|
+
# Store current agent position
|
|
302
|
+
current_pos = self.agent.pos.copy()
|
|
303
|
+
|
|
304
|
+
# Move agent to target position
|
|
305
|
+
self.place_agent(pos=pos)
|
|
306
|
+
|
|
307
|
+
# Render observation from this position
|
|
308
|
+
obs = self.render_top_view(POMDP=True, render_ag=False)
|
|
309
|
+
|
|
310
|
+
# Resize to match observation dimensions if needed
|
|
311
|
+
if obs.shape[:2] != (self.obs_height, self.obs_width):
|
|
312
|
+
obs = cv2.resize(
|
|
313
|
+
obs, (self.obs_width, self.obs_height), interpolation=cv2.INTER_AREA
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
# Restore agent position
|
|
317
|
+
self.place_agent(pos=current_pos)
|
|
318
|
+
|
|
319
|
+
return obs
|
|
320
|
+
|
|
321
|
+
def is_goal_achieved(self, pos=None, threshold=0.5):
|
|
322
|
+
"""
|
|
323
|
+
Check if the agent has achieved the current goal.
|
|
324
|
+
|
|
325
|
+
Args:
|
|
326
|
+
pos: Agent position to check (uses current agent pos if None)
|
|
327
|
+
threshold: Distance threshold for goal achievement
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
bool: True if goal is achieved
|
|
331
|
+
"""
|
|
332
|
+
if pos is None:
|
|
333
|
+
pos = self.agent.pos
|
|
334
|
+
|
|
335
|
+
if not hasattr(self, "_current_goal_position"):
|
|
336
|
+
return False
|
|
337
|
+
|
|
338
|
+
# Convert to numpy arrays and calculate distance
|
|
339
|
+
pos_array = np.array(pos)
|
|
340
|
+
goal_array = np.array(self._current_goal_position)
|
|
341
|
+
distance = np.linalg.norm(pos_array - goal_array)
|
|
342
|
+
|
|
343
|
+
return bool(distance < threshold)
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"""Factory for creating Nine Rooms environment variants."""
|
|
2
2
|
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
3
5
|
import gymnasium as gym
|
|
4
6
|
import numpy as np
|
|
5
7
|
|
|
6
8
|
from ..core import ObservationLevel
|
|
7
9
|
from ..core.constants import FACTORY_DOOR_SIZE, FACTORY_ROOM_SIZE
|
|
8
|
-
from ..wrappers.image_transforms import ImageToPyTorch
|
|
9
10
|
from .nine_rooms import NineRooms
|
|
10
11
|
from .spiral_nine_rooms import SpiralNineRooms
|
|
11
12
|
from .twenty_five_rooms import TwentyFiveRooms
|
|
@@ -23,6 +24,7 @@ class NineRoomsEnvironmentWrapper(gym.Wrapper):
|
|
|
23
24
|
room_size=FACTORY_ROOM_SIZE,
|
|
24
25
|
door_size=FACTORY_DOOR_SIZE,
|
|
25
26
|
agent_mode=None,
|
|
27
|
+
info_obs: List[ObservationLevel] = None,
|
|
26
28
|
):
|
|
27
29
|
"""
|
|
28
30
|
Create a Nine Rooms environment variant.
|
|
@@ -35,6 +37,7 @@ class NineRoomsEnvironmentWrapper(gym.Wrapper):
|
|
|
35
37
|
room_size: Size of each room in environment units
|
|
36
38
|
door_size: Size of doors between rooms
|
|
37
39
|
agent_mode: Agent rendering mode ('empty', 'circle', 'triangle', or None for default)
|
|
40
|
+
info_obs: List of observation levels to include in info dictionary
|
|
38
41
|
"""
|
|
39
42
|
self.variant = variant
|
|
40
43
|
|
|
@@ -61,13 +64,13 @@ class NineRoomsEnvironmentWrapper(gym.Wrapper):
|
|
|
61
64
|
obs_width=size,
|
|
62
65
|
obs_height=size,
|
|
63
66
|
agent_mode=agent_mode,
|
|
67
|
+
info_obs=info_obs,
|
|
64
68
|
)
|
|
65
69
|
|
|
66
70
|
# Apply wrappers - no resize needed since we render at target size
|
|
67
|
-
env = ImageToPyTorch(base_env)
|
|
68
71
|
|
|
69
|
-
# Initialize gym.Wrapper with the
|
|
70
|
-
super().__init__(
|
|
72
|
+
# Initialize gym.Wrapper with the base environment
|
|
73
|
+
super().__init__(base_env)
|
|
71
74
|
|
|
72
75
|
def render_on_pos(self, pos):
|
|
73
76
|
"""Render observation from a specific position."""
|
|
@@ -100,56 +103,3 @@ class NineRoomsEnvironmentWrapper(gym.Wrapper):
|
|
|
100
103
|
return obs
|
|
101
104
|
|
|
102
105
|
|
|
103
|
-
def create_drstrategy_env(variant="NineRooms", **kwargs):
|
|
104
|
-
"""
|
|
105
|
-
Factory function to create DrStrategy environment variants.
|
|
106
|
-
|
|
107
|
-
Args:
|
|
108
|
-
variant: Environment variant ("NineRooms", "SpiralNineRooms", "TwentyFiveRooms")
|
|
109
|
-
**kwargs: Additional arguments passed to NineRoomsEnvironmentWrapper
|
|
110
|
-
|
|
111
|
-
Returns:
|
|
112
|
-
NineRoomsEnvironmentWrapper instance
|
|
113
|
-
"""
|
|
114
|
-
return NineRoomsEnvironmentWrapper(variant=variant, **kwargs)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
# Backward compatibility alias
|
|
118
|
-
def create_nine_rooms_env(variant="NineRooms", **kwargs):
|
|
119
|
-
"""
|
|
120
|
-
Legacy factory function for backward compatibility.
|
|
121
|
-
|
|
122
|
-
Deprecated: Use create_drstrategy_env() instead.
|
|
123
|
-
"""
|
|
124
|
-
import warnings
|
|
125
|
-
|
|
126
|
-
warnings.warn(
|
|
127
|
-
"create_nine_rooms_env() is deprecated. Use create_drstrategy_env() instead.",
|
|
128
|
-
DeprecationWarning,
|
|
129
|
-
stacklevel=2,
|
|
130
|
-
)
|
|
131
|
-
return create_drstrategy_env(variant=variant, **kwargs)
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
# Legacy function - deprecated
|
|
135
|
-
def NineRoomsFullyPureGymnasium(
|
|
136
|
-
name="NineRooms",
|
|
137
|
-
obs_level=ObservationLevel.TOP_DOWN_PARTIAL,
|
|
138
|
-
continuous=False,
|
|
139
|
-
size=64,
|
|
140
|
-
):
|
|
141
|
-
"""
|
|
142
|
-
Legacy function for backward compatibility.
|
|
143
|
-
|
|
144
|
-
Deprecated: Use create_drstrategy_env() instead.
|
|
145
|
-
"""
|
|
146
|
-
import warnings
|
|
147
|
-
|
|
148
|
-
warnings.warn(
|
|
149
|
-
"NineRoomsFullyPureGymnasium() is deprecated. Use create_drstrategy_env() instead.",
|
|
150
|
-
DeprecationWarning,
|
|
151
|
-
stacklevel=2,
|
|
152
|
-
)
|
|
153
|
-
return create_drstrategy_env(
|
|
154
|
-
variant="NineRooms", obs_level=obs_level, continuous=continuous, size=size
|
|
155
|
-
)
|
|
@@ -58,10 +58,25 @@ class NineRooms(GridRoomsEnvironment):
|
|
|
58
58
|
"cobaltgreen",
|
|
59
59
|
]
|
|
60
60
|
|
|
61
|
+
# Initialize goal positions for each room (2 goals per room)
|
|
62
|
+
goal_positions = []
|
|
63
|
+
for i in range(3): # rows
|
|
64
|
+
for j in range(3): # columns
|
|
65
|
+
center_x = room_size * j + room_size / 2
|
|
66
|
+
center_z = room_size * i + room_size / 2
|
|
67
|
+
# Two goals per room: center-left and center-right
|
|
68
|
+
goal_positions.append(
|
|
69
|
+
[
|
|
70
|
+
[center_x - 1.0, 0.0, center_z], # left goal
|
|
71
|
+
[center_x + 1.0, 0.0, center_z], # right goal
|
|
72
|
+
]
|
|
73
|
+
)
|
|
74
|
+
|
|
61
75
|
super().__init__(
|
|
62
76
|
grid_size=3,
|
|
63
77
|
connections=connections or default_connections,
|
|
64
78
|
textures=textures or default_textures,
|
|
79
|
+
goal_positions=goal_positions,
|
|
65
80
|
placed_room=placed_room,
|
|
66
81
|
obs_level=obs_level,
|
|
67
82
|
continuous=continuous,
|
|
@@ -54,10 +54,25 @@ class SpiralNineRooms(GridRoomsEnvironment):
|
|
|
54
54
|
"cobaltgreen",
|
|
55
55
|
]
|
|
56
56
|
|
|
57
|
+
# Initialize goal positions for each room (2 goals per room)
|
|
58
|
+
goal_positions = []
|
|
59
|
+
for i in range(3): # rows
|
|
60
|
+
for j in range(3): # columns
|
|
61
|
+
center_x = room_size * j + room_size / 2
|
|
62
|
+
center_z = room_size * i + room_size / 2
|
|
63
|
+
# Two goals per room: center-left and center-right
|
|
64
|
+
goal_positions.append(
|
|
65
|
+
[
|
|
66
|
+
[center_x - 1.0, 0.0, center_z], # left goal
|
|
67
|
+
[center_x + 1.0, 0.0, center_z], # right goal
|
|
68
|
+
]
|
|
69
|
+
)
|
|
70
|
+
|
|
57
71
|
super().__init__(
|
|
58
72
|
grid_size=3,
|
|
59
73
|
connections=connections or default_connections,
|
|
60
74
|
textures=textures or default_textures,
|
|
75
|
+
goal_positions=goal_positions,
|
|
61
76
|
placed_room=placed_room,
|
|
62
77
|
obs_level=obs_level,
|
|
63
78
|
continuous=continuous,
|
|
@@ -106,10 +106,24 @@ class TwentyFiveRooms(GridRoomsEnvironment):
|
|
|
106
106
|
"realblueberry",
|
|
107
107
|
]
|
|
108
108
|
|
|
109
|
+
# Initialize goal positions for each room (1 goal per room at center)
|
|
110
|
+
goal_positions = []
|
|
111
|
+
for i in range(5): # rows
|
|
112
|
+
for j in range(5): # columns
|
|
113
|
+
center_x = room_size * j + room_size / 2
|
|
114
|
+
center_z = room_size * i + room_size / 2
|
|
115
|
+
# One goal per room at the center
|
|
116
|
+
goal_positions.append(
|
|
117
|
+
[
|
|
118
|
+
[center_x, 0.0, center_z],
|
|
119
|
+
]
|
|
120
|
+
)
|
|
121
|
+
|
|
109
122
|
super().__init__(
|
|
110
123
|
grid_size=5,
|
|
111
124
|
connections=connections or default_connections,
|
|
112
125
|
textures=textures or default_textures,
|
|
126
|
+
goal_positions=goal_positions,
|
|
113
127
|
placed_room=placed_room,
|
|
114
128
|
obs_level=obs_level,
|
|
115
129
|
continuous=continuous,
|
|
@@ -11,7 +11,7 @@ import numpy as np
|
|
|
11
11
|
from PIL import Image
|
|
12
12
|
|
|
13
13
|
from ..core import FrameBuffer
|
|
14
|
-
from ..environments.factory import
|
|
14
|
+
from ..environments.factory import NineRoomsEnvironmentWrapper
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def generate_observations(variant, output_dir=None, high_res_full_views=False):
|
|
@@ -22,10 +22,10 @@ def generate_observations(variant, output_dir=None, high_res_full_views=False):
|
|
|
22
22
|
os.makedirs(output_dir, exist_ok=True)
|
|
23
23
|
|
|
24
24
|
# Create environment
|
|
25
|
-
env =
|
|
25
|
+
env = NineRoomsEnvironmentWrapper(variant=variant, size=64)
|
|
26
26
|
|
|
27
27
|
# Get base environment for direct render access
|
|
28
|
-
base_env = getattr(env,
|
|
28
|
+
base_env = getattr(env, "env", getattr(env, "_env", env))
|
|
29
29
|
while hasattr(base_env, "env") or hasattr(base_env, "_env"):
|
|
30
30
|
if hasattr(base_env, "env"):
|
|
31
31
|
base_env = base_env.env
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: miniworld-maze
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Multi-room maze environments from the DrStrategy paper for reinforcement learning research
|
|
5
|
+
Keywords: reinforcement-learning,environment,gymnasium,multi-room-maze,drstrategy,maze-navigation,partial-observability,3d-environments
|
|
6
|
+
Author: Tim Joseph
|
|
7
|
+
Author-email: Tim Joseph <tim@mctigger.com>
|
|
8
|
+
License: MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2025 Tim Joseph
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
29
|
+
Classifier: Development Status :: 4 - Beta
|
|
30
|
+
Classifier: Intended Audience :: Science/Research
|
|
31
|
+
Classifier: Intended Audience :: Developers
|
|
32
|
+
Classifier: Operating System :: OS Independent
|
|
33
|
+
Classifier: Programming Language :: Python :: 3
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
39
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
40
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
41
|
+
Classifier: Environment :: Console
|
|
42
|
+
Classifier: Typing :: Typed
|
|
43
|
+
Requires-Dist: gymnasium>=1.0.0,<2.0.0
|
|
44
|
+
Requires-Dist: numpy>=1.20.0,<3.0.0
|
|
45
|
+
Requires-Dist: opencv-python>=4.5.0,<5.0.0
|
|
46
|
+
Requires-Dist: pillow>=8.0.0,<11.0.0
|
|
47
|
+
Requires-Dist: pyopengl>=3.1.0,<4.0.0
|
|
48
|
+
Requires-Dist: pyglet>=1.5.0,<2.0.0
|
|
49
|
+
Requires-Dist: black>=22.0,<25.0 ; extra == 'dev'
|
|
50
|
+
Requires-Dist: isort>=5.10,<6.0 ; extra == 'dev'
|
|
51
|
+
Requires-Dist: flake8>=4.0,<7.0 ; extra == 'dev'
|
|
52
|
+
Requires-Dist: ruff>=0.1.0,<1.0.0 ; extra == 'dev'
|
|
53
|
+
Requires-Dist: build>=0.8.0,<2.0.0 ; extra == 'dev'
|
|
54
|
+
Requires-Dist: twine>=4.0.0,<6.0.0 ; extra == 'dev'
|
|
55
|
+
Requires-Dist: mujoco>=2.3.0,<4.0.0 ; extra == 'mujoco'
|
|
56
|
+
Requires-Python: >=3.8
|
|
57
|
+
Project-URL: Bug Tracker, https://github.com/mctigger/miniworld-maze/issues
|
|
58
|
+
Project-URL: Documentation, https://github.com/mctigger/miniworld-maze#readme
|
|
59
|
+
Project-URL: Homepage, https://github.com/mctigger/miniworld-maze
|
|
60
|
+
Project-URL: Repository, https://github.com/mctigger/miniworld-maze
|
|
61
|
+
Provides-Extra: dev
|
|
62
|
+
Provides-Extra: mujoco
|
|
63
|
+
Description-Content-Type: text/markdown
|
|
64
|
+
|
|
65
|
+
# MiniWorld DrStrategy - Multi-Room Maze Environment
|
|
66
|
+
|
|
67
|
+
A refactored implementation of Dr. Strategy's MiniWorld-based maze environments with updated dependencies and modern Python packaging. Based on the now-deprecated [MiniWorld](https://github.com/Farama-Foundation/Miniworld) project and the original [DrStrategy implementation](https://github.com/ahn-ml/drstrategy).
|
|
68
|
+
|
|
69
|
+
## Environment Observations
|
|
70
|
+
|
|
71
|
+
### Environment Views
|
|
72
|
+
Full environment layout and render-on-position views:
|
|
73
|
+
|
|
74
|
+
| Full Environment | Partial Top-Down Observations | Partial First-Person Observations |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
|  |   |   |
|
|
77
|
+
|
|
78
|
+
## Installation
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pip install miniworld-maze
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Usage
|
|
85
|
+
|
|
86
|
+
### Basic Usage
|
|
87
|
+
|
|
88
|
+
See `examples/basic_usage.py` for a complete working example:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
#!/usr/bin/env python3
|
|
92
|
+
"""
|
|
93
|
+
Basic usage example for miniworld-maze environments.
|
|
94
|
+
|
|
95
|
+
This is a minimal example showing how to create and interact with the environment.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
from miniworld_maze import NineRoomsEnvironmentWrapper
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def main():
|
|
102
|
+
# Create environment
|
|
103
|
+
env = NineRoomsEnvironmentWrapper(variant="NineRooms", size=64)
|
|
104
|
+
obs, info = env.reset()
|
|
105
|
+
|
|
106
|
+
# obs is a dictionary containing:
|
|
107
|
+
# - 'observation': (64, 64, 3) RGB image array
|
|
108
|
+
# - 'desired_goal': (64, 64, 3) RGB image of the goal state
|
|
109
|
+
# - 'achieved_goal': (64, 64, 3) RGB image of the current state
|
|
110
|
+
|
|
111
|
+
# Take a few random actions
|
|
112
|
+
for step in range(10):
|
|
113
|
+
action = env.action_space.sample()
|
|
114
|
+
obs, reward, terminated, truncated, info = env.step(action)
|
|
115
|
+
|
|
116
|
+
print(f"Step {step + 1}: reward={reward:.3f}, terminated={terminated}")
|
|
117
|
+
|
|
118
|
+
if terminated or truncated:
|
|
119
|
+
obs, info = env.reset()
|
|
120
|
+
|
|
121
|
+
env.close()
|
|
122
|
+
print("Environment closed successfully!")
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
if __name__ == "__main__":
|
|
126
|
+
main()
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Headless Environments
|
|
130
|
+
|
|
131
|
+
When running in headless environments (servers, CI/CD, Docker containers) or when encountering X11/OpenGL context issues, you need to enable headless rendering:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Set environment variable before running Python
|
|
135
|
+
export PYGLET_HEADLESS=1
|
|
136
|
+
python your_script.py
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Or in your Python code (must be set before importing the library):
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
import os
|
|
143
|
+
os.environ['PYGLET_HEADLESS'] = '1'
|
|
144
|
+
|
|
145
|
+
import miniworld_maze
|
|
146
|
+
# ... rest of your code
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
This configures the underlying pyglet library to use EGL rendering instead of X11, allowing the environments to run without a display server.
|
|
150
|
+
|
|
151
|
+
## Environment Variants
|
|
152
|
+
|
|
153
|
+
### Available Environments
|
|
154
|
+
|
|
155
|
+
The package provides three main environment variants, each with different room layouts and connection patterns:
|
|
156
|
+
|
|
157
|
+
#### 1. NineRooms (3×3 Grid)
|
|
158
|
+
```
|
|
159
|
+
-------------
|
|
160
|
+
| 0 | 1 | 2 |
|
|
161
|
+
-------------
|
|
162
|
+
| 3 | 4 | 5 |
|
|
163
|
+
-------------
|
|
164
|
+
| 6 | 7 | 8 |
|
|
165
|
+
-------------
|
|
166
|
+
```
|
|
167
|
+
A standard 3×3 grid where adjacent rooms are connected. The agent can navigate between rooms through doorways, with connections forming a fully connected grid pattern.
|
|
168
|
+
|
|
169
|
+
#### 2. SpiralNineRooms (3×3 Spiral Pattern)
|
|
170
|
+
```
|
|
171
|
+
-------------
|
|
172
|
+
| 0 | 1 | 2 |
|
|
173
|
+
-------------
|
|
174
|
+
| 3 | 4 | 5 |
|
|
175
|
+
-------------
|
|
176
|
+
| 6 | 7 | 8 |
|
|
177
|
+
-------------
|
|
178
|
+
```
|
|
179
|
+
Same room layout as NineRooms but with a spiral connection pattern. Only specific room pairs are connected, creating a more challenging navigation task with fewer available paths.
|
|
180
|
+
|
|
181
|
+
#### 3. TwentyFiveRooms (5×5 Grid)
|
|
182
|
+
```
|
|
183
|
+
---------------------
|
|
184
|
+
| 0 | 1 | 2 | 3 | 4 |
|
|
185
|
+
---------------------
|
|
186
|
+
| 5 | 6 | 7 | 8 | 9 |
|
|
187
|
+
---------------------
|
|
188
|
+
|10 |11 |12 |13 |14 |
|
|
189
|
+
---------------------
|
|
190
|
+
|15 |16 |17 |18 |19 |
|
|
191
|
+
---------------------
|
|
192
|
+
|20 |21 |22 |23 |24 |
|
|
193
|
+
---------------------
|
|
194
|
+
```
|
|
195
|
+
A larger 5×5 grid environment with 25 rooms, providing more complex navigation challenges and longer episode lengths.
|
|
196
|
+
|
|
197
|
+
### Observation Types
|
|
198
|
+
|
|
199
|
+
Each environment supports three different observation modes:
|
|
200
|
+
|
|
201
|
+
- **`TOP_DOWN_PARTIAL`** (default): Agent-centered partial top-down view with limited visibility range (POMDP)
|
|
202
|
+
- **`TOP_DOWN_FULL`**: Complete top-down view showing the entire environment
|
|
203
|
+
- **`FIRST_PERSON`**: 3D first-person perspective view from the agent's current position
|
|
204
|
+
|
|
205
|
+
### Action Space
|
|
206
|
+
|
|
207
|
+
- **Discrete Actions** (default): 7 discrete actions (turn left/right, move forward/backward, strafe left/right, no-op)
|
|
208
|
+
- **Continuous Actions**: Continuous control with `continuous=True` parameter
|
|
209
|
+
|
|
210
|
+
### Environment Configuration
|
|
211
|
+
|
|
212
|
+
All environments can be customized with the following parameters:
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
from miniworld_maze import NineRoomsEnvironmentWrapper
|
|
216
|
+
from miniworld_maze.core import ObservationLevel
|
|
217
|
+
|
|
218
|
+
env = NineRoomsEnvironmentWrapper(
|
|
219
|
+
variant="NineRooms", # "NineRooms", "SpiralNineRooms", "TwentyFiveRooms"
|
|
220
|
+
obs_level=ObservationLevel.TOP_DOWN_PARTIAL, # Observation type
|
|
221
|
+
continuous=False, # Use continuous actions
|
|
222
|
+
size=64, # Observation image size (64x64)
|
|
223
|
+
room_size=5, # Size of each room in environment units
|
|
224
|
+
door_size=2, # Size of doors between rooms
|
|
225
|
+
agent_mode="empty", # Agent rendering: "empty", "circle", "triangle"
|
|
226
|
+
)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Observation Format
|
|
230
|
+
|
|
231
|
+
The environment returns observations in dictionary format:
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
obs = {
|
|
235
|
+
'observation': np.ndarray, # (64, 64, 3) RGB image of current view
|
|
236
|
+
'desired_goal': np.ndarray, # (64, 64, 3) RGB image of goal location
|
|
237
|
+
'achieved_goal': np.ndarray, # (64, 64, 3) RGB image of current state
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Reward Structure
|
|
242
|
+
|
|
243
|
+
- **Goal reaching**: Positive reward when agent reaches the goal location
|
|
244
|
+
- **Step penalty**: Small negative reward per step to encourage efficiency
|
|
245
|
+
- **Episode termination**: When goal is reached or maximum steps exceeded
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
## License
|
|
249
|
+
|
|
250
|
+
MIT License - see LICENSE file for details.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
miniworld_maze/__init__.py,sha256=
|
|
1
|
+
miniworld_maze/__init__.py,sha256=kz5QqyvwIV_XkjXw_yHRkhqlPSl8X1Usra3DF0Zy4_E,1053
|
|
2
2
|
miniworld_maze/core/__init__.py,sha256=5BA4WKXQjrG55TNaEid2JGrnf1KQniJZ1HhRqovM1Q0,293
|
|
3
3
|
miniworld_maze/core/constants.py,sha256=GX1pSnaWGOkangYStxaBy7gIQhWxVKIbXnTSd-eA_vs,3962
|
|
4
4
|
miniworld_maze/core/miniworld_gymnasium/README.md,sha256=kkZgkRKBdgixpot3uHuiBFlRIKRFIVBVfXwu68XTEv0,74
|
|
@@ -260,21 +260,19 @@ miniworld_maze/core/miniworld_gymnasium/textures/white_1.png,sha256=wRrgs92I_Ids
|
|
|
260
260
|
miniworld_maze/core/miniworld_gymnasium/textures/wood_1.png,sha256=XRZyIN34HFo14olbxRcsHGrzCAFqUlowc6nLR22IFBE,184713
|
|
261
261
|
miniworld_maze/core/miniworld_gymnasium/textures/wood_2.png,sha256=qSDHB-ZO11JJLQuiQse-0edpbuTg1YO-eIBhdTvNUhc,93121
|
|
262
262
|
miniworld_maze/core/miniworld_gymnasium/textures/wood_planks_1.png,sha256=E4SNN1s4yOtkLfZFQy905eip6KvDWnnPUrpS82FxMAg,847259
|
|
263
|
-
miniworld_maze/core/miniworld_gymnasium/unified_env.py,sha256=
|
|
263
|
+
miniworld_maze/core/miniworld_gymnasium/unified_env.py,sha256=oY2YXCZ-ro8kl6ie0h8TEBooWjB6bvmQu42-1tDsrw4,46689
|
|
264
264
|
miniworld_maze/core/miniworld_gymnasium/utils.py,sha256=9cfpg4qYz-Esxvu8nTMPFJc-Tl0TRxTrX6cfg0YuK_o,1007
|
|
265
265
|
miniworld_maze/core/miniworld_gymnasium/wrappers.py,sha256=cD0nGSJYNU96zoWv63aEiKd986POhtHfGGEpNpRL5ec,122
|
|
266
266
|
miniworld_maze/core/observation_types.py,sha256=Co8mEIXzIgk0MLx6tqeBd1EE0PuZOL1gbZwobiEde08,1316
|
|
267
|
-
miniworld_maze/environments/__init__.py,sha256=
|
|
268
|
-
miniworld_maze/environments/base_grid_rooms.py,sha256=
|
|
269
|
-
miniworld_maze/environments/factory.py,sha256=
|
|
270
|
-
miniworld_maze/environments/nine_rooms.py,sha256=
|
|
271
|
-
miniworld_maze/environments/spiral_nine_rooms.py,sha256=
|
|
272
|
-
miniworld_maze/environments/twenty_five_rooms.py,sha256=
|
|
267
|
+
miniworld_maze/environments/__init__.py,sha256=6O1G4vlhUSn8OuR46u-t4Wz3de8da76Tz21TsVlzBZo,415
|
|
268
|
+
miniworld_maze/environments/base_grid_rooms.py,sha256=kpF6psn0YCfvA-q1vtU2KaqwmfQaPpX0w9jBTxt2qs8,11833
|
|
269
|
+
miniworld_maze/environments/factory.py,sha256=g8qYF6UF9DsKExZIHhMsP8PX3b11kvmkLMwE2IpgBxc,3501
|
|
270
|
+
miniworld_maze/environments/nine_rooms.py,sha256=0CzUkRy2hJZ4JEEj9E-6xCopseZ1u8iGCfKLaxwATGo,2368
|
|
271
|
+
miniworld_maze/environments/spiral_nine_rooms.py,sha256=LB9wKQXp9S8pVd8JhM9zfsc5z4ksxsQxQKoEXrDgPhE,2316
|
|
272
|
+
miniworld_maze/environments/twenty_five_rooms.py,sha256=ExF4Mt0B3pkaVQtBF7oaVxdj_9uaAkTFYCe83Lw8Evk,3448
|
|
273
273
|
miniworld_maze/tools/__init__.py,sha256=PgkKMO21xnwIfJtD437P_RtkguOHoOSFV1ohsO-n7tc,150
|
|
274
|
-
miniworld_maze/tools/generate_observations.py,sha256
|
|
275
|
-
miniworld_maze/
|
|
276
|
-
miniworld_maze/
|
|
277
|
-
miniworld_maze-1.
|
|
278
|
-
miniworld_maze-1.
|
|
279
|
-
miniworld_maze-1.0.0.dist-info/METADATA,sha256=GhSg5-xatBRjjkKZuhnkjfFExyH_R77BUDrCjgoLCEE,4775
|
|
280
|
-
miniworld_maze-1.0.0.dist-info/RECORD,,
|
|
274
|
+
miniworld_maze/tools/generate_observations.py,sha256=-WWoex0KY6PSMs4BenMTepeE4tA2NYZ26jIQL2tYfZY,6781
|
|
275
|
+
miniworld_maze-1.1.0.dist-info/WHEEL,sha256=NHRAbdxxzyL9K3IO2LjmlNqKSyPZnKv2BD16YYVKo18,79
|
|
276
|
+
miniworld_maze-1.1.0.dist-info/entry_points.txt,sha256=Ue03NHCOQCiJ87tqfJSns29C3Dw02jsZXL_Auzw2pb4,91
|
|
277
|
+
miniworld_maze-1.1.0.dist-info/METADATA,sha256=atsdko20fA_iqS8y2muB0dQkLDnmLpP4ppuTuNLfcxA,9270
|
|
278
|
+
miniworld_maze-1.1.0.dist-info/RECORD,,
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
"""Image transformation wrappers for Nine Rooms environments."""
|
|
2
|
-
|
|
3
|
-
import gymnasium as gym
|
|
4
|
-
import numpy as np
|
|
5
|
-
from gymnasium import spaces
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class ImageToPyTorch(gym.ObservationWrapper):
|
|
9
|
-
"""Convert HWC to CHW format for PyTorch compatibility."""
|
|
10
|
-
|
|
11
|
-
def __init__(self, env):
|
|
12
|
-
"""
|
|
13
|
-
Initialize PyTorch-compatible image transformation wrapper.
|
|
14
|
-
|
|
15
|
-
Transforms observation space from HWC (Height, Width, Channels) format
|
|
16
|
-
to CHW (Channels, Height, Width) format expected by PyTorch models.
|
|
17
|
-
|
|
18
|
-
Args:
|
|
19
|
-
env: The environment to wrap
|
|
20
|
-
"""
|
|
21
|
-
super(ImageToPyTorch, self).__init__(env)
|
|
22
|
-
obs_shape = self.observation_space.shape
|
|
23
|
-
self.observation_space = spaces.Box(
|
|
24
|
-
low=0,
|
|
25
|
-
high=255,
|
|
26
|
-
shape=(obs_shape[2], obs_shape[0], obs_shape[1]),
|
|
27
|
-
dtype=np.uint8,
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
def observation(self, observation):
|
|
31
|
-
"""
|
|
32
|
-
Transform observation from HWC to CHW format.
|
|
33
|
-
|
|
34
|
-
Args:
|
|
35
|
-
observation: Input observation in HWC format (H, W, C)
|
|
36
|
-
|
|
37
|
-
Returns:
|
|
38
|
-
np.ndarray: Observation in CHW format (C, H, W)
|
|
39
|
-
"""
|
|
40
|
-
return np.transpose(observation, (2, 0, 1))
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.3
|
|
2
|
-
Name: miniworld-maze
|
|
3
|
-
Version: 1.0.0
|
|
4
|
-
Summary: Multi-room maze environments from the DrStrategy paper for reinforcement learning research
|
|
5
|
-
Keywords: reinforcement-learning,environment,gymnasium,multi-room-maze,drstrategy,maze-navigation,partial-observability,3d-environments
|
|
6
|
-
Author: Tim Joseph
|
|
7
|
-
Author-email: Tim Joseph <tim@mctigger.com>
|
|
8
|
-
License: MIT License
|
|
9
|
-
|
|
10
|
-
Copyright (c) 2025 DrStrategy Research Team
|
|
11
|
-
|
|
12
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
-
in the Software without restriction, including without limitation the rights
|
|
15
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
-
furnished to do so, subject to the following conditions:
|
|
18
|
-
|
|
19
|
-
The above copyright notice and this permission notice shall be included in all
|
|
20
|
-
copies or substantial portions of the Software.
|
|
21
|
-
|
|
22
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
-
SOFTWARE.
|
|
29
|
-
Classifier: Development Status :: 4 - Beta
|
|
30
|
-
Classifier: Intended Audience :: Science/Research
|
|
31
|
-
Classifier: Intended Audience :: Developers
|
|
32
|
-
Classifier: Operating System :: OS Independent
|
|
33
|
-
Classifier: Programming Language :: Python :: 3
|
|
34
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
35
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
36
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
37
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
38
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
39
|
-
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
40
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
41
|
-
Classifier: Environment :: Console
|
|
42
|
-
Classifier: Typing :: Typed
|
|
43
|
-
Requires-Dist: gymnasium>=1.0.0,<2.0.0
|
|
44
|
-
Requires-Dist: numpy>=1.20.0,<3.0.0
|
|
45
|
-
Requires-Dist: opencv-python>=4.5.0,<5.0.0
|
|
46
|
-
Requires-Dist: pillow>=8.0.0,<11.0.0
|
|
47
|
-
Requires-Dist: pyopengl>=3.1.0,<4.0.0
|
|
48
|
-
Requires-Dist: pyglet>=1.5.0,<2.0.0
|
|
49
|
-
Requires-Dist: black>=22.0,<25.0 ; extra == 'dev'
|
|
50
|
-
Requires-Dist: isort>=5.10,<6.0 ; extra == 'dev'
|
|
51
|
-
Requires-Dist: flake8>=4.0,<7.0 ; extra == 'dev'
|
|
52
|
-
Requires-Dist: build>=0.8.0,<2.0.0 ; extra == 'dev'
|
|
53
|
-
Requires-Dist: twine>=4.0.0,<6.0.0 ; extra == 'dev'
|
|
54
|
-
Requires-Dist: mujoco>=2.3.0,<4.0.0 ; extra == 'mujoco'
|
|
55
|
-
Requires-Python: >=3.8
|
|
56
|
-
Project-URL: Bug Tracker, https://github.com/mctigger/miniworld-maze/issues
|
|
57
|
-
Project-URL: Documentation, https://github.com/mctigger/miniworld-maze#readme
|
|
58
|
-
Project-URL: Homepage, https://github.com/mctigger/miniworld-maze
|
|
59
|
-
Project-URL: Repository, https://github.com/mctigger/miniworld-maze
|
|
60
|
-
Provides-Extra: dev
|
|
61
|
-
Provides-Extra: mujoco
|
|
62
|
-
Description-Content-Type: text/markdown
|
|
63
|
-
|
|
64
|
-
# MiniWorld DrStrategy - Multi-Room Maze Environment
|
|
65
|
-
|
|
66
|
-
A refactored implementation of Dr. Strategy's MiniWorld-based maze environments with updated dependencies and modern Python packaging. Based on the now-deprecated [MiniWorld](https://github.com/Farama-Foundation/Miniworld) project and the original [DrStrategy implementation](https://github.com/ahn-ml/drstrategy).
|
|
67
|
-
|
|
68
|
-
## Environment Observations
|
|
69
|
-
|
|
70
|
-
### Environment Views
|
|
71
|
-
Full environment layout and render-on-position views:
|
|
72
|
-
|
|
73
|
-
| Full Environment | Partial Top-Down Observations | Partial First-Person Observations |
|
|
74
|
-
|---|---|---|
|
|
75
|
-
|  |   |   |
|
|
76
|
-
|
|
77
|
-
## Installation
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
pip install miniworld-maze
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## Usage
|
|
84
|
-
|
|
85
|
-
```python
|
|
86
|
-
from miniworld_drstrategy import create_nine_rooms_env
|
|
87
|
-
|
|
88
|
-
# Create environment
|
|
89
|
-
env = create_nine_rooms_env(variant="NineRooms", size=64)
|
|
90
|
-
obs, info = env.reset()
|
|
91
|
-
|
|
92
|
-
# Take actions
|
|
93
|
-
action = env.action_space.sample()
|
|
94
|
-
obs, reward, terminated, truncated, info = env.step(action)
|
|
95
|
-
|
|
96
|
-
env.close()
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## Environment Variants
|
|
100
|
-
|
|
101
|
-
- **NineRooms**: 3×3 grid layout
|
|
102
|
-
- **SpiralNineRooms**: Spiral connection pattern
|
|
103
|
-
- **TwentyFiveRooms**: 5×5 grid layout
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
## License
|
|
107
|
-
|
|
108
|
-
MIT License - see LICENSE file for details.
|
|
File without changes
|