miniworld-maze 1.1.0__py3-none-any.whl → 1.3.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 +17 -5
- miniworld_maze/core/constants.py +55 -14
- miniworld_maze/core/miniworld_gymnasium/__init__.py +1 -1
- miniworld_maze/core/miniworld_gymnasium/base_env.py +3 -0
- miniworld_maze/core/miniworld_gymnasium/unified_env.py +23 -19
- miniworld_maze/environments/__init__.py +0 -2
- miniworld_maze/environments/base_grid_rooms.py +90 -15
- miniworld_maze/environments/factory.py +38 -101
- miniworld_maze/environments/nine_rooms.py +5 -23
- miniworld_maze/environments/spiral_nine_rooms.py +5 -23
- miniworld_maze/environments/twenty_five_rooms.py +5 -38
- miniworld_maze/tools/__init__.py +1 -3
- miniworld_maze/utils.py +286 -0
- {miniworld_maze-1.1.0.dist-info → miniworld_maze-1.3.0.dist-info}/METADATA +25 -14
- {miniworld_maze-1.1.0.dist-info → miniworld_maze-1.3.0.dist-info}/RECORD +16 -17
- miniworld_maze/tools/generate_observations.py +0 -199
- miniworld_maze-1.1.0.dist-info/entry_points.txt +0 -3
- {miniworld_maze-1.1.0.dist-info → miniworld_maze-1.3.0.dist-info}/WHEEL +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""TwentyFiveRooms environment implementation."""
|
|
2
2
|
|
|
3
3
|
from ..core import ObservationLevel
|
|
4
|
+
from ..core.constants import TextureThemes
|
|
4
5
|
from .base_grid_rooms import GridRoomsEnvironment
|
|
5
6
|
|
|
6
7
|
|
|
@@ -78,46 +79,12 @@ class TwentyFiveRooms(GridRoomsEnvironment):
|
|
|
78
79
|
(22, 23),
|
|
79
80
|
(23, 24),
|
|
80
81
|
]
|
|
81
|
-
default_textures =
|
|
82
|
-
"crimson",
|
|
83
|
-
"beanpaste",
|
|
84
|
-
"cobaltgreen",
|
|
85
|
-
"lightnavyblue",
|
|
86
|
-
"skyblue",
|
|
87
|
-
"lightcobaltgreen",
|
|
88
|
-
"oakbrown",
|
|
89
|
-
"copperred",
|
|
90
|
-
"lightgray",
|
|
91
|
-
"lime",
|
|
92
|
-
"turquoise",
|
|
93
|
-
"violet",
|
|
94
|
-
"beige",
|
|
95
|
-
"morningglory",
|
|
96
|
-
"silver",
|
|
97
|
-
"magenta",
|
|
98
|
-
"sunnyyellow",
|
|
99
|
-
"blueberry",
|
|
100
|
-
"lightbeige",
|
|
101
|
-
"seablue",
|
|
102
|
-
"lemongrass",
|
|
103
|
-
"orchid",
|
|
104
|
-
"redbean",
|
|
105
|
-
"orange",
|
|
106
|
-
"realblueberry",
|
|
107
|
-
]
|
|
82
|
+
default_textures = TextureThemes.TWENTY_FIVE_ROOMS
|
|
108
83
|
|
|
109
84
|
# Initialize goal positions for each room (1 goal per room at center)
|
|
110
|
-
goal_positions =
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
)
|
|
85
|
+
goal_positions = GridRoomsEnvironment._generate_goal_positions(
|
|
86
|
+
5, room_size, goals_per_room=1
|
|
87
|
+
)
|
|
121
88
|
|
|
122
89
|
super().__init__(
|
|
123
90
|
grid_size=5,
|
miniworld_maze/tools/__init__.py
CHANGED
miniworld_maze/utils.py
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
"""Utility functions for miniworld_maze package."""
|
|
2
|
+
|
|
3
|
+
from typing import Tuple, Union
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def environment_to_pixel_coords(
|
|
8
|
+
env_pos: np.ndarray,
|
|
9
|
+
env_min: np.ndarray,
|
|
10
|
+
env_max: np.ndarray,
|
|
11
|
+
image_size: Union[int, Tuple[int, int]],
|
|
12
|
+
) -> Tuple[int, int]:
|
|
13
|
+
"""
|
|
14
|
+
Convert environment coordinates to pixel coordinates.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
env_pos: Environment position as ndarray [x, z] or [x, y]
|
|
18
|
+
env_min: Environment minimum bounds as ndarray [min_x, min_z] or [min_x, min_y]
|
|
19
|
+
env_max: Environment maximum bounds as ndarray [max_x, max_z] or [max_x, max_y]
|
|
20
|
+
image_size: Image size (width, height) or single size for square image
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
Tuple of (pixel_x, pixel_y) coordinates
|
|
24
|
+
"""
|
|
25
|
+
env_x, env_y = env_pos[:2]
|
|
26
|
+
env_min_x, env_min_y = env_min[:2]
|
|
27
|
+
env_max_x, env_max_y = env_max[:2]
|
|
28
|
+
|
|
29
|
+
if isinstance(image_size, int):
|
|
30
|
+
width = height = image_size
|
|
31
|
+
else:
|
|
32
|
+
width, height = image_size
|
|
33
|
+
|
|
34
|
+
# Normalize to [0, 1] range and scale to pixel coordinates
|
|
35
|
+
pixel_x = int((env_x - env_min_x) / (env_max_x - env_min_x) * width)
|
|
36
|
+
pixel_y = int((env_y - env_min_y) / (env_max_y - env_min_y) * height)
|
|
37
|
+
|
|
38
|
+
return pixel_x, pixel_y
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def pixel_to_environment_coords(
|
|
42
|
+
pixel_pos: np.ndarray,
|
|
43
|
+
env_min: np.ndarray,
|
|
44
|
+
env_max: np.ndarray,
|
|
45
|
+
image_size: Union[int, Tuple[int, int]],
|
|
46
|
+
) -> Tuple[float, float]:
|
|
47
|
+
"""
|
|
48
|
+
Convert pixel coordinates to environment coordinates.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
pixel_pos: Pixel position as ndarray [x, y]
|
|
52
|
+
env_min: Environment minimum bounds as ndarray [min_x, min_z] or [min_x, min_y]
|
|
53
|
+
env_max: Environment maximum bounds as ndarray [max_x, max_z] or [max_x, max_y]
|
|
54
|
+
image_size: Image size (width, height) or single size for square image
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
Tuple of (env_x, env_y) coordinates
|
|
58
|
+
"""
|
|
59
|
+
pixel_x, pixel_y = pixel_pos[:2]
|
|
60
|
+
env_min_x, env_min_y = env_min[:2]
|
|
61
|
+
env_max_x, env_max_y = env_max[:2]
|
|
62
|
+
|
|
63
|
+
if isinstance(image_size, int):
|
|
64
|
+
width = height = image_size
|
|
65
|
+
else:
|
|
66
|
+
width, height = image_size
|
|
67
|
+
|
|
68
|
+
# Convert to normalized [0, 1] range and scale to environment coordinates
|
|
69
|
+
env_x = pixel_x / width * (env_max_x - env_min_x) + env_min_x
|
|
70
|
+
env_y = pixel_y / height * (env_max_y - env_min_y) + env_min_y
|
|
71
|
+
|
|
72
|
+
return env_x, env_y
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def clamp_to_bounds(
|
|
76
|
+
value: Union[int, float, np.ndarray],
|
|
77
|
+
min_val: Union[int, float, np.ndarray],
|
|
78
|
+
max_val: Union[int, float, np.ndarray],
|
|
79
|
+
) -> Union[int, float, np.ndarray]:
|
|
80
|
+
"""
|
|
81
|
+
Clamp a value or array of values to specified bounds.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
value: Value(s) to clamp (scalar or ndarray)
|
|
85
|
+
min_val: Minimum bound(s) (scalar or ndarray)
|
|
86
|
+
max_val: Maximum bound(s) (scalar or ndarray)
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
Clamped value(s)
|
|
90
|
+
"""
|
|
91
|
+
if isinstance(value, np.ndarray):
|
|
92
|
+
return np.clip(value, min_val, max_val)
|
|
93
|
+
else:
|
|
94
|
+
return max(min_val, min(max_val, value))
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def clamp_pixel_coords(
|
|
98
|
+
pixel_x: int, pixel_y: int, image_size: Union[int, Tuple[int, int]]
|
|
99
|
+
) -> Tuple[int, int]:
|
|
100
|
+
"""
|
|
101
|
+
Clamp pixel coordinates to image bounds.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
pixel_x: X pixel coordinate
|
|
105
|
+
pixel_y: Y pixel coordinate
|
|
106
|
+
image_size: Image size (width, height) or single size for square image
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
Tuple of clamped (pixel_x, pixel_y) coordinates
|
|
110
|
+
"""
|
|
111
|
+
if isinstance(image_size, int):
|
|
112
|
+
width = height = image_size
|
|
113
|
+
else:
|
|
114
|
+
width, height = image_size
|
|
115
|
+
|
|
116
|
+
clamped_x = max(0, min(width - 1, pixel_x))
|
|
117
|
+
clamped_y = max(0, min(height - 1, pixel_y))
|
|
118
|
+
|
|
119
|
+
return clamped_x, clamped_y
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def normalize_coordinates(
|
|
123
|
+
coords: np.ndarray,
|
|
124
|
+
min_bounds: np.ndarray,
|
|
125
|
+
max_bounds: np.ndarray,
|
|
126
|
+
) -> Tuple[float, float]:
|
|
127
|
+
"""
|
|
128
|
+
Normalize coordinates to [0, 1] range based on given bounds.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
coords: Coordinates to normalize as ndarray
|
|
132
|
+
min_bounds: Minimum bounds as ndarray
|
|
133
|
+
max_bounds: Maximum bounds as ndarray
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
Normalized coordinates as (x, y) tuple
|
|
137
|
+
"""
|
|
138
|
+
x, y = coords[:2]
|
|
139
|
+
min_x, min_y = min_bounds[:2]
|
|
140
|
+
max_x, max_y = max_bounds[:2]
|
|
141
|
+
|
|
142
|
+
norm_x = (x - min_x) / (max_x - min_x)
|
|
143
|
+
norm_y = (y - min_y) / (max_y - min_y)
|
|
144
|
+
|
|
145
|
+
return norm_x, norm_y
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def denormalize_coordinates(
|
|
149
|
+
normalized_coords: np.ndarray,
|
|
150
|
+
min_bounds: np.ndarray,
|
|
151
|
+
max_bounds: np.ndarray,
|
|
152
|
+
) -> Tuple[float, float]:
|
|
153
|
+
"""
|
|
154
|
+
Convert normalized [0, 1] coordinates back to original coordinate space.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
normalized_coords: Normalized coordinates in [0, 1] range as ndarray
|
|
158
|
+
min_bounds: Original minimum bounds as ndarray
|
|
159
|
+
max_bounds: Original maximum bounds as ndarray
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
Denormalized coordinates as (x, y) tuple
|
|
163
|
+
"""
|
|
164
|
+
norm_x, norm_y = normalized_coords[:2]
|
|
165
|
+
min_x, min_y = min_bounds[:2]
|
|
166
|
+
max_x, max_y = max_bounds[:2]
|
|
167
|
+
|
|
168
|
+
x = norm_x * (max_x - min_x) + min_x
|
|
169
|
+
y = norm_y * (max_y - min_y) + min_y
|
|
170
|
+
|
|
171
|
+
return x, y
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def get_environment_bounds(env) -> Tuple[Tuple[float, float], Tuple[float, float]]:
|
|
175
|
+
"""
|
|
176
|
+
Extract environment bounds from an environment object.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
env: Environment object (may be wrapped)
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
Tuple of ((min_x, min_z), (max_x, max_z))
|
|
183
|
+
"""
|
|
184
|
+
# Unwrap environment to access base environment
|
|
185
|
+
base_env = env
|
|
186
|
+
while hasattr(base_env, "env"):
|
|
187
|
+
base_env = base_env.env
|
|
188
|
+
|
|
189
|
+
min_bounds = (base_env.min_x, base_env.min_z)
|
|
190
|
+
max_bounds = (base_env.max_x, base_env.max_z)
|
|
191
|
+
|
|
192
|
+
return min_bounds, max_bounds
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def calculate_view_size_from_bounds(
|
|
196
|
+
min_bounds: np.ndarray,
|
|
197
|
+
max_bounds: np.ndarray,
|
|
198
|
+
) -> Tuple[float, float]:
|
|
199
|
+
"""
|
|
200
|
+
Calculate view size (width, height) from coordinate bounds.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
min_bounds: Minimum bounds as ndarray (min_x, min_y)
|
|
204
|
+
max_bounds: Maximum bounds as ndarray (max_x, max_y)
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
Tuple of (width, height)
|
|
208
|
+
"""
|
|
209
|
+
min_x, min_y = min_bounds[:2]
|
|
210
|
+
max_x, max_y = max_bounds[:2]
|
|
211
|
+
|
|
212
|
+
width = max_x - min_x
|
|
213
|
+
height = max_y - min_y
|
|
214
|
+
|
|
215
|
+
return width, height
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def scale_coordinates(
|
|
219
|
+
coords: np.ndarray,
|
|
220
|
+
scale_factor: Union[float, Tuple[float, float]],
|
|
221
|
+
) -> Tuple[float, float]:
|
|
222
|
+
"""
|
|
223
|
+
Scale coordinates by a given factor.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
coords: Coordinates to scale as ndarray
|
|
227
|
+
scale_factor: Scale factor (uniform) or (scale_x, scale_y)
|
|
228
|
+
|
|
229
|
+
Returns:
|
|
230
|
+
Scaled coordinates as (x, y) tuple
|
|
231
|
+
"""
|
|
232
|
+
x, y = coords[:2]
|
|
233
|
+
|
|
234
|
+
if isinstance(scale_factor, (tuple, list)):
|
|
235
|
+
scale_x, scale_y = scale_factor
|
|
236
|
+
else:
|
|
237
|
+
scale_x = scale_y = scale_factor
|
|
238
|
+
|
|
239
|
+
return x * scale_x, y * scale_y
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def distance_2d(
|
|
243
|
+
pos1: np.ndarray,
|
|
244
|
+
pos2: np.ndarray,
|
|
245
|
+
) -> float:
|
|
246
|
+
"""
|
|
247
|
+
Calculate 2D Euclidean distance between two positions.
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
pos1: First position as ndarray (x, y)
|
|
251
|
+
pos2: Second position as ndarray (x, y)
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
Euclidean distance
|
|
255
|
+
"""
|
|
256
|
+
x1, y1 = pos1[:2]
|
|
257
|
+
x2, y2 = pos2[:2]
|
|
258
|
+
|
|
259
|
+
return np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def lerp_2d(
|
|
263
|
+
pos1: np.ndarray,
|
|
264
|
+
pos2: np.ndarray,
|
|
265
|
+
t: float,
|
|
266
|
+
) -> Tuple[float, float]:
|
|
267
|
+
"""
|
|
268
|
+
Linear interpolation between two 2D positions.
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
pos1: Start position as ndarray (x, y)
|
|
272
|
+
pos2: End position as ndarray (x, y)
|
|
273
|
+
t: Interpolation parameter [0, 1]
|
|
274
|
+
|
|
275
|
+
Returns:
|
|
276
|
+
Interpolated position as (x, y) tuple
|
|
277
|
+
"""
|
|
278
|
+
x1, y1 = pos1[:2]
|
|
279
|
+
x2, y2 = pos2[:2]
|
|
280
|
+
|
|
281
|
+
t = clamp_to_bounds(t, 0.0, 1.0)
|
|
282
|
+
|
|
283
|
+
x = x1 + t * (x2 - x1)
|
|
284
|
+
y = y1 + t * (y2 - y1)
|
|
285
|
+
|
|
286
|
+
return x, y
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: miniworld-maze
|
|
3
|
-
Version: 1.
|
|
4
|
-
Summary: Multi-room maze environments from the DrStrategy paper
|
|
3
|
+
Version: 1.3.0
|
|
4
|
+
Summary: Multi-room maze environments from the DrStrategy paper. Provides NineRooms-v0, SpiralNineRooms-v0, and TwentyFiveRooms-v0 gymnasium environments.
|
|
5
5
|
Keywords: reinforcement-learning,environment,gymnasium,multi-room-maze,drstrategy,maze-navigation,partial-observability,3d-environments
|
|
6
6
|
Author: Tim Joseph
|
|
7
7
|
Author-email: Tim Joseph <tim@mctigger.com>
|
|
@@ -46,9 +46,6 @@ Requires-Dist: opencv-python>=4.5.0,<5.0.0
|
|
|
46
46
|
Requires-Dist: pillow>=8.0.0,<11.0.0
|
|
47
47
|
Requires-Dist: pyopengl>=3.1.0,<4.0.0
|
|
48
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
49
|
Requires-Dist: ruff>=0.1.0,<1.0.0 ; extra == 'dev'
|
|
53
50
|
Requires-Dist: build>=0.8.0,<2.0.0 ; extra == 'dev'
|
|
54
51
|
Requires-Dist: twine>=4.0.0,<6.0.0 ; extra == 'dev'
|
|
@@ -83,6 +80,18 @@ pip install miniworld-maze
|
|
|
83
80
|
|
|
84
81
|
## Usage
|
|
85
82
|
|
|
83
|
+
### Registered Environments
|
|
84
|
+
|
|
85
|
+
This package registers the following gymnasium environments:
|
|
86
|
+
|
|
87
|
+
| Environment ID | Description | Rooms | Max Steps |
|
|
88
|
+
|---|---|---|---|
|
|
89
|
+
| `NineRooms-v0` | Standard 3×3 grid with adjacent room connections | 9 | 1000 |
|
|
90
|
+
| `SpiralNineRooms-v0` | 3×3 grid with spiral connection pattern | 9 | 1000 |
|
|
91
|
+
| `TwentyFiveRooms-v0` | Large 5×5 grid with complex navigation | 25 | 1000 |
|
|
92
|
+
|
|
93
|
+
All environments use `TOP_DOWN_PARTIAL` observation level and factory default room/door sizes by default.
|
|
94
|
+
|
|
86
95
|
### Basic Usage
|
|
87
96
|
|
|
88
97
|
See `examples/basic_usage.py` for a complete working example:
|
|
@@ -95,12 +104,13 @@ Basic usage example for miniworld-maze environments.
|
|
|
95
104
|
This is a minimal example showing how to create and interact with the environment.
|
|
96
105
|
"""
|
|
97
106
|
|
|
98
|
-
|
|
107
|
+
import gymnasium as gym
|
|
108
|
+
import miniworld_maze # noqa: F401
|
|
99
109
|
|
|
100
110
|
|
|
101
111
|
def main():
|
|
102
|
-
# Create environment
|
|
103
|
-
env =
|
|
112
|
+
# Create environment using gymnasium registry
|
|
113
|
+
env = gym.make("NineRooms-v0", obs_width=64, obs_height=64)
|
|
104
114
|
obs, info = env.reset()
|
|
105
115
|
|
|
106
116
|
# obs is a dictionary containing:
|
|
@@ -212,14 +222,15 @@ Each environment supports three different observation modes:
|
|
|
212
222
|
All environments can be customized with the following parameters:
|
|
213
223
|
|
|
214
224
|
```python
|
|
215
|
-
|
|
216
|
-
from miniworld_maze
|
|
225
|
+
import gymnasium as gym
|
|
226
|
+
from miniworld_maze import ObservationLevel
|
|
227
|
+
import miniworld_maze # noqa: F401
|
|
217
228
|
|
|
218
|
-
env =
|
|
219
|
-
|
|
229
|
+
env = gym.make(
|
|
230
|
+
"NineRooms-v0", # Environment variant
|
|
220
231
|
obs_level=ObservationLevel.TOP_DOWN_PARTIAL, # Observation type
|
|
221
|
-
|
|
222
|
-
|
|
232
|
+
obs_width=64, # Observation image width
|
|
233
|
+
obs_height=64, # Observation image height
|
|
223
234
|
room_size=5, # Size of each room in environment units
|
|
224
235
|
door_size=2, # Size of doors between rooms
|
|
225
236
|
agent_mode="empty", # Agent rendering: "empty", "circle", "triangle"
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
miniworld_maze/__init__.py,sha256=
|
|
1
|
+
miniworld_maze/__init__.py,sha256=Dfq3558bJ5kgxDZxPxvlHu1531zfBhtiDfKbVL_4zCE,1430
|
|
2
2
|
miniworld_maze/core/__init__.py,sha256=5BA4WKXQjrG55TNaEid2JGrnf1KQniJZ1HhRqovM1Q0,293
|
|
3
|
-
miniworld_maze/core/constants.py,sha256=
|
|
3
|
+
miniworld_maze/core/constants.py,sha256=UXqmuvsT9ww1GljW74lWPPP9XxVmvti-8JfM_RBSoWQ,4314
|
|
4
4
|
miniworld_maze/core/miniworld_gymnasium/README.md,sha256=kkZgkRKBdgixpot3uHuiBFlRIKRFIVBVfXwu68XTEv0,74
|
|
5
|
-
miniworld_maze/core/miniworld_gymnasium/__init__.py,sha256=
|
|
6
|
-
miniworld_maze/core/miniworld_gymnasium/base_env.py,sha256=
|
|
5
|
+
miniworld_maze/core/miniworld_gymnasium/__init__.py,sha256=ALOqr4SCVk9I9bmxyoU0Du8LUPE_57jIyZuV4QhOcBc,159
|
|
6
|
+
miniworld_maze/core/miniworld_gymnasium/base_env.py,sha256=K2L5r4gG2k4fEknFqRJ7f-b2S0Uj5QhanS-MLi6ncVc,1927
|
|
7
7
|
miniworld_maze/core/miniworld_gymnasium/entities/__init__.py,sha256=gbMJcFeasvlRSIuXWyOYO-MhW0JKKY5ZNxF5TMsWJ5c,262
|
|
8
8
|
miniworld_maze/core/miniworld_gymnasium/entities/agent.py,sha256=U3Zt2Hk21rJSdzPCBj46-N930n7XAkA9qo_fKbezn2k,3153
|
|
9
9
|
miniworld_maze/core/miniworld_gymnasium/entities/base_entity.py,sha256=ox2k3rf64Y2mp4S0mcpNpPUg0QeUuJ7LVoduvBuLXDg,3657
|
|
@@ -260,19 +260,18 @@ 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=7A4sAmMpopLfKMXtZ4jzbMlFJbzeu9Abv7hGYVbvOIA,46925
|
|
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=
|
|
273
|
-
miniworld_maze/tools/__init__.py,sha256=
|
|
274
|
-
miniworld_maze/
|
|
275
|
-
miniworld_maze-1.
|
|
276
|
-
miniworld_maze-1.
|
|
277
|
-
miniworld_maze-1.
|
|
278
|
-
miniworld_maze-1.1.0.dist-info/RECORD,,
|
|
267
|
+
miniworld_maze/environments/__init__.py,sha256=DKld5MQU7x9eNL6BlxIettA44bCiIn2zIpYECDCNxoQ,331
|
|
268
|
+
miniworld_maze/environments/base_grid_rooms.py,sha256=--tm6t9cHn444xJX9N3Md-4YApK38a2dQi7mnggevbI,14885
|
|
269
|
+
miniworld_maze/environments/factory.py,sha256=Zk26JawsMgSLMgvSnQxFhQCD8yMH76HgqFtogzWFfqY,1333
|
|
270
|
+
miniworld_maze/environments/nine_rooms.py,sha256=Ct96cKtSt1_nLNI5RBUhwqdNUQq1rHfBJ3aB5Igbdow,1794
|
|
271
|
+
miniworld_maze/environments/spiral_nine_rooms.py,sha256=a_pUuv-ghez8h76Z7YsHkQoLXsQ-w9azKLjEjO4uKmA,1749
|
|
272
|
+
miniworld_maze/environments/twenty_five_rooms.py,sha256=MewKPDHDilscQGTT3aGRrSHvo4uFgHHAOrnJMrHaezQ,2598
|
|
273
|
+
miniworld_maze/tools/__init__.py,sha256=XiReXrJIcBKvDVyPZrKPq1mckJs0_WC7q_RmdXXcKHs,55
|
|
274
|
+
miniworld_maze/utils.py,sha256=HTOkfRq72oOC844gVXjWMH1ox7wdSxfCS6oTrWBw05Q,7523
|
|
275
|
+
miniworld_maze-1.3.0.dist-info/WHEEL,sha256=NHRAbdxxzyL9K3IO2LjmlNqKSyPZnKv2BD16YYVKo18,79
|
|
276
|
+
miniworld_maze-1.3.0.dist-info/METADATA,sha256=qKeYDRC9Evc7PtegEs0PVFYy7fMgKlqNZPiFf3GnZkk,9657
|
|
277
|
+
miniworld_maze-1.3.0.dist-info/RECORD,,
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Generate comprehensive observations for Nine Rooms environment variants.
|
|
4
|
-
Supports: NineRooms, SpiralNineRooms, TwentyFiveRooms
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import argparse
|
|
8
|
-
import os
|
|
9
|
-
|
|
10
|
-
import numpy as np
|
|
11
|
-
from PIL import Image
|
|
12
|
-
|
|
13
|
-
from ..core import FrameBuffer
|
|
14
|
-
from ..environments.factory import NineRoomsEnvironmentWrapper
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def generate_observations(variant, output_dir=None, high_res_full_views=False):
|
|
18
|
-
"""Generate comprehensive observations for the specified environment variant."""
|
|
19
|
-
if output_dir is None:
|
|
20
|
-
output_dir = f"{variant.lower()}_observations"
|
|
21
|
-
|
|
22
|
-
os.makedirs(output_dir, exist_ok=True)
|
|
23
|
-
|
|
24
|
-
# Create environment
|
|
25
|
-
env = NineRoomsEnvironmentWrapper(variant=variant, size=64)
|
|
26
|
-
|
|
27
|
-
# Get base environment for direct render access
|
|
28
|
-
base_env = getattr(env, "env", getattr(env, "_env", env))
|
|
29
|
-
while hasattr(base_env, "env") or hasattr(base_env, "_env"):
|
|
30
|
-
if hasattr(base_env, "env"):
|
|
31
|
-
base_env = base_env.env
|
|
32
|
-
elif hasattr(base_env, "_env"):
|
|
33
|
-
base_env = base_env._env
|
|
34
|
-
else:
|
|
35
|
-
break
|
|
36
|
-
|
|
37
|
-
# Reset environment
|
|
38
|
-
obs, _ = env.reset(seed=42)
|
|
39
|
-
|
|
40
|
-
# Create high-resolution frame buffer if requested
|
|
41
|
-
high_res_fb = None
|
|
42
|
-
if high_res_full_views:
|
|
43
|
-
high_res_fb = FrameBuffer(512, 512, 8)
|
|
44
|
-
|
|
45
|
-
# === FULL ENVIRONMENT OBSERVATIONS ===
|
|
46
|
-
|
|
47
|
-
# 1. Full view with agent at starting position
|
|
48
|
-
if high_res_full_views:
|
|
49
|
-
full_view_start = base_env.render_top_view(
|
|
50
|
-
frame_buffer=high_res_fb, POMDP=False
|
|
51
|
-
)
|
|
52
|
-
else:
|
|
53
|
-
full_view_start = base_env.render_top_view(POMDP=False)
|
|
54
|
-
Image.fromarray(full_view_start).save(f"{output_dir}/full_view_start.png")
|
|
55
|
-
|
|
56
|
-
# 2. Full view without agent (clean maze view)
|
|
57
|
-
if high_res_full_views:
|
|
58
|
-
full_view_clean = base_env.render_top_view(
|
|
59
|
-
frame_buffer=high_res_fb, POMDP=False, render_ag=False
|
|
60
|
-
)
|
|
61
|
-
else:
|
|
62
|
-
full_view_clean = base_env.render_top_view(POMDP=False, render_ag=False)
|
|
63
|
-
Image.fromarray(full_view_clean).save(f"{output_dir}/full_view_clean.png")
|
|
64
|
-
|
|
65
|
-
# 3. Full view with agent in center
|
|
66
|
-
center_x = (base_env.min_x + base_env.max_x) / 2
|
|
67
|
-
center_z = (base_env.min_z + base_env.max_z) / 2
|
|
68
|
-
base_env.place_agent(pos=[center_x, 0.0, center_z])
|
|
69
|
-
if high_res_full_views:
|
|
70
|
-
full_view_center = base_env.render_top_view(
|
|
71
|
-
frame_buffer=high_res_fb, POMDP=False
|
|
72
|
-
)
|
|
73
|
-
else:
|
|
74
|
-
full_view_center = base_env.render_top_view(POMDP=False)
|
|
75
|
-
Image.fromarray(full_view_center).save(f"{output_dir}/full_view_center.png")
|
|
76
|
-
|
|
77
|
-
# === PARTIAL OBSERVATIONS ===
|
|
78
|
-
|
|
79
|
-
# Reset agent to start position
|
|
80
|
-
base_env.place_agent(pos=[2.5, 0.0, 2.5])
|
|
81
|
-
|
|
82
|
-
# 1. Partial view from starting position
|
|
83
|
-
partial_start = base_env.render_top_view(POMDP=True)
|
|
84
|
-
Image.fromarray(partial_start).save(f"{output_dir}/partial_start.png")
|
|
85
|
-
|
|
86
|
-
# 2. Partial view from center
|
|
87
|
-
base_env.place_agent(pos=[center_x, 0.0, center_z])
|
|
88
|
-
partial_center = base_env.render_top_view(POMDP=True)
|
|
89
|
-
Image.fromarray(partial_center).save(f"{output_dir}/partial_center.png")
|
|
90
|
-
|
|
91
|
-
# 3. Partial view from corner/edge
|
|
92
|
-
corner_x = base_env.max_x - 2.5
|
|
93
|
-
corner_z = base_env.max_z - 2.5
|
|
94
|
-
base_env.place_agent(pos=[corner_x, 0.0, corner_z])
|
|
95
|
-
partial_corner = base_env.render_top_view(POMDP=True)
|
|
96
|
-
Image.fromarray(partial_corner).save(f"{output_dir}/partial_corner.png")
|
|
97
|
-
|
|
98
|
-
# 4. Partial view at strategic location
|
|
99
|
-
if variant == "NineRooms":
|
|
100
|
-
strategic_x, strategic_z = 15.0, 7.5 # Room boundary
|
|
101
|
-
elif variant == "SpiralNineRooms":
|
|
102
|
-
strategic_x, strategic_z = 22.5, 15.0 # Center of spiral
|
|
103
|
-
else: # TwentyFiveRooms
|
|
104
|
-
strategic_x, strategic_z = 37.5, 37.5 # Mid-outer area
|
|
105
|
-
|
|
106
|
-
base_env.place_agent(pos=[strategic_x, 0.0, strategic_z])
|
|
107
|
-
partial_strategic = base_env.render_top_view(POMDP=True)
|
|
108
|
-
Image.fromarray(partial_strategic).save(f"{output_dir}/partial_strategic.png")
|
|
109
|
-
|
|
110
|
-
# === WRAPPED OBSERVATIONS ===
|
|
111
|
-
|
|
112
|
-
# Reset environment
|
|
113
|
-
obs, _ = env.reset(seed=42)
|
|
114
|
-
|
|
115
|
-
# 1. Standard gymnasium observation
|
|
116
|
-
obs_hwc = np.transpose(obs, (1, 2, 0))
|
|
117
|
-
Image.fromarray(obs_hwc).save(f"{output_dir}/gymnasium_standard.png")
|
|
118
|
-
|
|
119
|
-
# 2. Observations after movement
|
|
120
|
-
actions = [2, 2, 1] # move_forward, move_forward, turn_right
|
|
121
|
-
action_names = ["move_forward", "move_forward", "turn_right"]
|
|
122
|
-
|
|
123
|
-
for i, action in enumerate(actions):
|
|
124
|
-
obs, _, _, _, _ = env.step(action)
|
|
125
|
-
obs_hwc = np.transpose(obs, (1, 2, 0))
|
|
126
|
-
Image.fromarray(obs_hwc).save(
|
|
127
|
-
f"{output_dir}/gymnasium_step_{i + 1}_{action_names[i]}.png"
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
# === RENDER_ON_POS EXAMPLES ===
|
|
131
|
-
|
|
132
|
-
# Define test positions based on variant
|
|
133
|
-
if variant == "NineRooms":
|
|
134
|
-
test_positions = [
|
|
135
|
-
[7.5, 0.0, 7.5], # top-middle room center
|
|
136
|
-
[37.5, 0.0, 37.5], # bottom-right room center
|
|
137
|
-
[22.5, 0.0, 22.5], # environment center
|
|
138
|
-
[7.5, 0.0, 22.5], # middle-left room center
|
|
139
|
-
]
|
|
140
|
-
elif variant == "SpiralNineRooms":
|
|
141
|
-
test_positions = [
|
|
142
|
-
[7.5, 0.0, 7.5], # top-left room (spiral start)
|
|
143
|
-
[37.5, 0.0, 37.5], # bottom-right room (spiral end)
|
|
144
|
-
[22.5, 0.0, 7.5], # top-right room
|
|
145
|
-
[7.5, 0.0, 37.5], # bottom-left room
|
|
146
|
-
]
|
|
147
|
-
else: # TwentyFiveRooms
|
|
148
|
-
test_positions = [
|
|
149
|
-
[37.5, 0.0, 37.5], # room (1,1) - near corner
|
|
150
|
-
[112.5, 0.0, 112.5], # room (4,4) - far corner
|
|
151
|
-
[75.0, 0.0, 75.0], # center room (2,2)
|
|
152
|
-
[37.5, 0.0, 112.5], # room (1,4) - opposite corner
|
|
153
|
-
]
|
|
154
|
-
|
|
155
|
-
for i, pos in enumerate(test_positions):
|
|
156
|
-
render_obs = env.render_on_pos(pos)
|
|
157
|
-
|
|
158
|
-
# Convert CHW to HWC for PIL
|
|
159
|
-
if len(render_obs.shape) == 3 and render_obs.shape[0] == 3:
|
|
160
|
-
render_obs = np.transpose(render_obs, (1, 2, 0))
|
|
161
|
-
|
|
162
|
-
Image.fromarray(render_obs).save(f"{output_dir}/render_on_pos_{i + 1}.png")
|
|
163
|
-
|
|
164
|
-
env.close()
|
|
165
|
-
return output_dir
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
def main():
|
|
169
|
-
parser = argparse.ArgumentParser(
|
|
170
|
-
description="Generate observations for Nine Rooms environment variants"
|
|
171
|
-
)
|
|
172
|
-
parser.add_argument(
|
|
173
|
-
"variant",
|
|
174
|
-
choices=["NineRooms", "SpiralNineRooms", "TwentyFiveRooms"],
|
|
175
|
-
help="Environment variant to use",
|
|
176
|
-
)
|
|
177
|
-
parser.add_argument(
|
|
178
|
-
"--output-dir",
|
|
179
|
-
type=str,
|
|
180
|
-
default=None,
|
|
181
|
-
help="Output directory for images (default: {variant}_observations)",
|
|
182
|
-
)
|
|
183
|
-
parser.add_argument(
|
|
184
|
-
"--high-res-full",
|
|
185
|
-
action="store_true",
|
|
186
|
-
help="Generate 512x512 high-resolution full environment views",
|
|
187
|
-
)
|
|
188
|
-
|
|
189
|
-
args = parser.parse_args()
|
|
190
|
-
|
|
191
|
-
output_dir = generate_observations(
|
|
192
|
-
args.variant, args.output_dir, args.high_res_full
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
return output_dir
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
if __name__ == "__main__":
|
|
199
|
-
main()
|
|
File without changes
|