miniworld-maze 1.0.0__py3-none-any.whl → 1.2.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.

@@ -0,0 +1,261 @@
1
+ Metadata-Version: 2.3
2
+ Name: miniworld-maze
3
+ Version: 1.2.0
4
+ Summary: Multi-room maze environments from the DrStrategy paper. Provides NineRooms-v0, SpiralNineRooms-v0, and TwentyFiveRooms-v0 gymnasium environments.
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: ruff>=0.1.0,<1.0.0 ; extra == 'dev'
50
+ Requires-Dist: build>=0.8.0,<2.0.0 ; extra == 'dev'
51
+ Requires-Dist: twine>=4.0.0,<6.0.0 ; extra == 'dev'
52
+ Requires-Dist: mujoco>=2.3.0,<4.0.0 ; extra == 'mujoco'
53
+ Requires-Python: >=3.8
54
+ Project-URL: Bug Tracker, https://github.com/mctigger/miniworld-maze/issues
55
+ Project-URL: Documentation, https://github.com/mctigger/miniworld-maze#readme
56
+ Project-URL: Homepage, https://github.com/mctigger/miniworld-maze
57
+ Project-URL: Repository, https://github.com/mctigger/miniworld-maze
58
+ Provides-Extra: dev
59
+ Provides-Extra: mujoco
60
+ Description-Content-Type: text/markdown
61
+
62
+ # MiniWorld DrStrategy - Multi-Room Maze Environment
63
+
64
+ 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).
65
+
66
+ ## Environment Observations
67
+
68
+ ### Environment Views
69
+ Full environment layout and render-on-position views:
70
+
71
+ | Full Environment | Partial Top-Down Observations | Partial First-Person Observations |
72
+ |---|---|---|
73
+ | ![Full View Clean](assets/images/full_view_clean.png) | ![Top Middle TD](assets/images/render_on_pos_1_top_middle_room_topdown.png) ![Center TD](assets/images/render_on_pos_3_environment_center_topdown.png) | ![Top Middle FP](assets/images/render_on_pos_1_top_middle_room_firstperson.png) ![Center FP](assets/images/render_on_pos_3_environment_center_firstperson.png) |
74
+
75
+ ## Installation
76
+
77
+ ```bash
78
+ pip install miniworld-maze
79
+ ```
80
+
81
+ ## Usage
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
+
95
+ ### Basic Usage
96
+
97
+ See `examples/basic_usage.py` for a complete working example:
98
+
99
+ ```python
100
+ #!/usr/bin/env python3
101
+ """
102
+ Basic usage example for miniworld-maze environments.
103
+
104
+ This is a minimal example showing how to create and interact with the environment.
105
+ """
106
+
107
+ import gymnasium as gym
108
+ import miniworld_maze # noqa: F401
109
+
110
+
111
+ def main():
112
+ # Create environment using gymnasium registry
113
+ env = gym.make("NineRooms-v0", obs_width=64, obs_height=64)
114
+ obs, info = env.reset()
115
+
116
+ # obs is a dictionary containing:
117
+ # - 'observation': (64, 64, 3) RGB image array
118
+ # - 'desired_goal': (64, 64, 3) RGB image of the goal state
119
+ # - 'achieved_goal': (64, 64, 3) RGB image of the current state
120
+
121
+ # Take a few random actions
122
+ for step in range(10):
123
+ action = env.action_space.sample()
124
+ obs, reward, terminated, truncated, info = env.step(action)
125
+
126
+ print(f"Step {step + 1}: reward={reward:.3f}, terminated={terminated}")
127
+
128
+ if terminated or truncated:
129
+ obs, info = env.reset()
130
+
131
+ env.close()
132
+ print("Environment closed successfully!")
133
+
134
+
135
+ if __name__ == "__main__":
136
+ main()
137
+ ```
138
+
139
+ ### Headless Environments
140
+
141
+ When running in headless environments (servers, CI/CD, Docker containers) or when encountering X11/OpenGL context issues, you need to enable headless rendering:
142
+
143
+ ```bash
144
+ # Set environment variable before running Python
145
+ export PYGLET_HEADLESS=1
146
+ python your_script.py
147
+ ```
148
+
149
+ Or in your Python code (must be set before importing the library):
150
+
151
+ ```python
152
+ import os
153
+ os.environ['PYGLET_HEADLESS'] = '1'
154
+
155
+ import miniworld_maze
156
+ # ... rest of your code
157
+ ```
158
+
159
+ This configures the underlying pyglet library to use EGL rendering instead of X11, allowing the environments to run without a display server.
160
+
161
+ ## Environment Variants
162
+
163
+ ### Available Environments
164
+
165
+ The package provides three main environment variants, each with different room layouts and connection patterns:
166
+
167
+ #### 1. NineRooms (3×3 Grid)
168
+ ```
169
+ -------------
170
+ | 0 | 1 | 2 |
171
+ -------------
172
+ | 3 | 4 | 5 |
173
+ -------------
174
+ | 6 | 7 | 8 |
175
+ -------------
176
+ ```
177
+ 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.
178
+
179
+ #### 2. SpiralNineRooms (3×3 Spiral Pattern)
180
+ ```
181
+ -------------
182
+ | 0 | 1 | 2 |
183
+ -------------
184
+ | 3 | 4 | 5 |
185
+ -------------
186
+ | 6 | 7 | 8 |
187
+ -------------
188
+ ```
189
+ 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.
190
+
191
+ #### 3. TwentyFiveRooms (5×5 Grid)
192
+ ```
193
+ ---------------------
194
+ | 0 | 1 | 2 | 3 | 4 |
195
+ ---------------------
196
+ | 5 | 6 | 7 | 8 | 9 |
197
+ ---------------------
198
+ |10 |11 |12 |13 |14 |
199
+ ---------------------
200
+ |15 |16 |17 |18 |19 |
201
+ ---------------------
202
+ |20 |21 |22 |23 |24 |
203
+ ---------------------
204
+ ```
205
+ A larger 5×5 grid environment with 25 rooms, providing more complex navigation challenges and longer episode lengths.
206
+
207
+ ### Observation Types
208
+
209
+ Each environment supports three different observation modes:
210
+
211
+ - **`TOP_DOWN_PARTIAL`** (default): Agent-centered partial top-down view with limited visibility range (POMDP)
212
+ - **`TOP_DOWN_FULL`**: Complete top-down view showing the entire environment
213
+ - **`FIRST_PERSON`**: 3D first-person perspective view from the agent's current position
214
+
215
+ ### Action Space
216
+
217
+ - **Discrete Actions** (default): 7 discrete actions (turn left/right, move forward/backward, strafe left/right, no-op)
218
+ - **Continuous Actions**: Continuous control with `continuous=True` parameter
219
+
220
+ ### Environment Configuration
221
+
222
+ All environments can be customized with the following parameters:
223
+
224
+ ```python
225
+ import gymnasium as gym
226
+ from miniworld_maze import ObservationLevel
227
+ import miniworld_maze # noqa: F401
228
+
229
+ env = gym.make(
230
+ "NineRooms-v0", # Environment variant
231
+ obs_level=ObservationLevel.TOP_DOWN_PARTIAL, # Observation type
232
+ obs_width=64, # Observation image width
233
+ obs_height=64, # Observation image height
234
+ room_size=5, # Size of each room in environment units
235
+ door_size=2, # Size of doors between rooms
236
+ agent_mode="empty", # Agent rendering: "empty", "circle", "triangle"
237
+ )
238
+ ```
239
+
240
+ ### Observation Format
241
+
242
+ The environment returns observations in dictionary format:
243
+
244
+ ```python
245
+ obs = {
246
+ 'observation': np.ndarray, # (64, 64, 3) RGB image of current view
247
+ 'desired_goal': np.ndarray, # (64, 64, 3) RGB image of goal location
248
+ 'achieved_goal': np.ndarray, # (64, 64, 3) RGB image of current state
249
+ }
250
+ ```
251
+
252
+ ### Reward Structure
253
+
254
+ - **Goal reaching**: Positive reward when agent reaches the goal location
255
+ - **Step penalty**: Small negative reward per step to encourage efficiency
256
+ - **Episode termination**: When goal is reached or maximum steps exceeded
257
+
258
+
259
+ ## License
260
+
261
+ MIT License - see LICENSE file for details.
@@ -1,8 +1,8 @@
1
- miniworld_maze/__init__.py,sha256=P5cqGqyF1wSO-ERuRWW8jTHXFVOAelvlIvNUrZKoJio,1215
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=GX1pSnaWGOkangYStxaBy7gIQhWxVKIbXnTSd-eA_vs,3962
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=zgqRxYBKT9Jo06kqWusZ6OjHyz25AyW03gkyrpZqY1I,151
5
+ miniworld_maze/core/miniworld_gymnasium/__init__.py,sha256=ALOqr4SCVk9I9bmxyoU0Du8LUPE_57jIyZuV4QhOcBc,159
6
6
  miniworld_maze/core/miniworld_gymnasium/base_env.py,sha256=heoJxEw_GGEHSzU75MWgqRkWARY3lgTgwNE9Zp1P_YA,1795
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
@@ -260,21 +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=lKP9IdBJSl2sUHPLIP5OK3ncNuod_dKvm4CJ3Gc0egQ,45674
263
+ miniworld_maze/core/miniworld_gymnasium/unified_env.py,sha256=B7kfG6axiL05o3kLiBvE6O1Q7kB8PaLdlAt1-Sksv0I,46529
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=hIrk8MulC725dMfslsqHtQus3dHL8C-vasUQeDphEnU,467
268
- miniworld_maze/environments/base_grid_rooms.py,sha256=RqL8Te1vk3JaCC2aq5RxI2omXm1lkfiOfVNx2Pe-ZWU,7602
269
- miniworld_maze/environments/factory.py,sha256=U7SnhTzsPy6VhARDMpnexKZwtJj0kh4CSzgRQBeEVjc,4914
270
- miniworld_maze/environments/nine_rooms.py,sha256=hZwRb2jjsGxbwCBv0dhpMKvgkpCNGrNZvFJWLTaFjxo,1727
271
- miniworld_maze/environments/spiral_nine_rooms.py,sha256=gDI2mLvaNmaxeM4Ara7RD1hGCjvETo60V3ar-SZZ-Dk,1675
272
- miniworld_maze/environments/twenty_five_rooms.py,sha256=xpc_d91s5j_mWhH-r9YpCTVqCEzB4mVcyoQ7ywWHXPU,2905
273
- miniworld_maze/tools/__init__.py,sha256=PgkKMO21xnwIfJtD437P_RtkguOHoOSFV1ohsO-n7tc,150
274
- miniworld_maze/tools/generate_observations.py,sha256=1etBz2ndTZwPFghnLhp15l1WVUaBN5DkMwjyGtzyepA,6769
275
- miniworld_maze/wrappers/__init__.py,sha256=cdTbUbwDBRC_d9kdFV0e392F3-718elthLoBJII5Npg,130
276
- miniworld_maze/wrappers/image_transforms.py,sha256=4xr4HfateUKeJjFRBBew8z6LO72ygue4yQjAZgOgo5g,1199
277
- miniworld_maze-1.0.0.dist-info/WHEEL,sha256=4n27za1eEkOnA7dNjN6C5-O2rUiw6iapszm14Uj-Qmk,79
278
- miniworld_maze-1.0.0.dist-info/entry_points.txt,sha256=Ue03NHCOQCiJ87tqfJSns29C3Dw02jsZXL_Auzw2pb4,91
279
- miniworld_maze-1.0.0.dist-info/METADATA,sha256=GhSg5-xatBRjjkKZuhnkjfFExyH_R77BUDrCjgoLCEE,4775
280
- miniworld_maze-1.0.0.dist-info/RECORD,,
267
+ miniworld_maze/environments/__init__.py,sha256=DKld5MQU7x9eNL6BlxIettA44bCiIn2zIpYECDCNxoQ,331
268
+ miniworld_maze/environments/base_grid_rooms.py,sha256=j4LnyUv0YjHlCLfjqX3fyoXUOOyCr4e3_Pdj-sM3FHo,14753
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.2.0.dist-info/WHEEL,sha256=NHRAbdxxzyL9K3IO2LjmlNqKSyPZnKv2BD16YYVKo18,79
276
+ miniworld_maze-1.2.0.dist-info/METADATA,sha256=QHJBCKSCHQr2u-Utcck1qMOffK1Cc6T0sV2k6_H7OAE,9657
277
+ miniworld_maze-1.2.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.8.13
2
+ Generator: uv 0.8.14
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -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 create_nine_rooms_env
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 = create_nine_rooms_env(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()
@@ -1,5 +0,0 @@
1
- """Gymnasium wrappers for Nine Rooms environments."""
2
-
3
- from .image_transforms import ImageToPyTorch
4
-
5
- __all__ = ["ImageToPyTorch"]
@@ -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
- | ![Full View Clean](assets/images/full_view_clean.png) | ![Top Middle TD](assets/images/render_on_pos_1_top_middle_room_topdown.png) ![Center TD](assets/images/render_on_pos_3_environment_center_topdown.png) | ![Top Middle FP](assets/images/render_on_pos_1_top_middle_room_firstperson.png) ![Center FP](assets/images/render_on_pos_3_environment_center_firstperson.png) |
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.
@@ -1,3 +0,0 @@
1
- [console_scripts]
2
- generate-observations = miniworld_maze.tools.generate_observations:main
3
-