Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub
Browse files- README.md +3 -3
- pyproject.toml +1 -1
- server/maze_environment.py +60 -17
README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
| 1 |
---
|
| 2 |
title: Maze Environment Server
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: docker
|
| 7 |
pinned: false
|
| 8 |
app_port: 8000
|
|
|
|
| 1 |
---
|
| 2 |
title: Maze Environment Server
|
| 3 |
+
emoji: 🖱️
|
| 4 |
+
colorFrom: indigo
|
| 5 |
+
colorTo: purple
|
| 6 |
sdk: docker
|
| 7 |
pinned: false
|
| 8 |
app_port: 8000
|
pyproject.toml
CHANGED
|
@@ -17,7 +17,7 @@ dependencies = [
|
|
| 17 |
# Core OpenEnv runtime (provides FastAPI server + HTTP client types)
|
| 18 |
# install from github
|
| 19 |
"openenv-core[core] @ git+https://github.com/meta-pytorch/OpenEnv.git",
|
| 20 |
-
#
|
| 21 |
# Environment-specific dependencies
|
| 22 |
# Add all dependencies needed for your environment here
|
| 23 |
# Examples:
|
|
|
|
| 17 |
# Core OpenEnv runtime (provides FastAPI server + HTTP client types)
|
| 18 |
# install from github
|
| 19 |
"openenv-core[core] @ git+https://github.com/meta-pytorch/OpenEnv.git",
|
| 20 |
+
#"openenv-core[core]>=0.2.0",
|
| 21 |
# Environment-specific dependencies
|
| 22 |
# Add all dependencies needed for your environment here
|
| 23 |
# Examples:
|
server/maze_environment.py
CHANGED
|
@@ -1,42 +1,85 @@
|
|
|
|
|
| 1 |
from openenv.core.env_server.interfaces import Environment
|
| 2 |
from models import MazeAction, MazeObservation, MazeState
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
class MazeEnvironment(Environment):
|
| 5 |
-
"""Grid-based maze environment
|
| 6 |
SUPPORTS_CONCURRENT_SESSIONS: bool = True
|
| 7 |
|
| 8 |
def __init__(self):
|
| 9 |
-
self.
|
| 10 |
-
self.
|
|
|
|
|
|
|
|
|
|
| 11 |
self._step_count, self._episode_id = 0, None
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
@property
|
| 15 |
def state(self) -> MazeState:
|
| 16 |
-
return MazeState(maze=self._maze, agent_pos=self._agent_pos,
|
| 17 |
-
goal_pos=self._goal_pos, episode_id=self._episode_id,
|
| 18 |
step_count=self._step_count)
|
| 19 |
|
| 20 |
def reset(self, seed=None, episode_id=None, **kwargs) -> MazeObservation:
|
| 21 |
-
|
|
|
|
|
|
|
| 22 |
return MazeObservation(position=self._agent_pos, grid_view=self._render(), done=False, reward=0)
|
| 23 |
|
| 24 |
def step(self, action: MazeAction, timeout_s=None, **kwargs) -> MazeObservation:
|
| 25 |
-
if action.direction in ["up","down","left","right"]:
|
|
|
|
| 26 |
self._step_count += 1
|
| 27 |
done = self._agent_pos == self._goal_pos
|
| 28 |
-
return MazeObservation(position=self._agent_pos, grid_view=self._render(),
|
| 29 |
done=done, reward=10 if done else -1)
|
| 30 |
|
| 31 |
def _move(self, d):
|
| 32 |
i, j = self._agent_pos
|
| 33 |
-
if d=='up': i-=1
|
| 34 |
-
elif d=='down': i+=1
|
| 35 |
-
elif d=='left': j-=1
|
| 36 |
-
elif d=='right': j+=1
|
| 37 |
-
if 0<=i<self.row and 0<=j<self.col and self._maze[i][j]:
|
|
|
|
| 38 |
|
| 39 |
def _render(self) -> str:
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import random
|
| 2 |
from openenv.core.env_server.interfaces import Environment
|
| 3 |
from models import MazeAction, MazeObservation, MazeState
|
| 4 |
+
from mazelib import Maze
|
| 5 |
+
from mazelib.generate.BacktrackingGenerator import BacktrackingGenerator
|
| 6 |
+
from mazelib.solve.ShortestPath import ShortestPath
|
| 7 |
+
|
| 8 |
+
class MazeGenerator:
|
| 9 |
+
def __init__(self, w_range=(3, 5), h_range=(3, 5)):
|
| 10 |
+
self.w_range, self.h_range = w_range, h_range
|
| 11 |
+
|
| 12 |
+
def generate(self, max_attempts=100):
|
| 13 |
+
w, h = random.randint(*self.w_range), random.randint(*self.h_range)
|
| 14 |
+
min_path_len = (w + h) * 2 + random.randint(-3, 5)
|
| 15 |
+
|
| 16 |
+
m = Maze()
|
| 17 |
+
m.generator = BacktrackingGenerator(w, h)
|
| 18 |
+
m.solver = ShortestPath()
|
| 19 |
+
|
| 20 |
+
for _ in range(max_attempts):
|
| 21 |
+
m.generate()
|
| 22 |
+
m.generate_entrances()
|
| 23 |
+
m.solve()
|
| 24 |
+
if len(m.solutions[0]) >= min_path_len:
|
| 25 |
+
break
|
| 26 |
+
|
| 27 |
+
return (1 - m.grid).tolist(), list(m.start), list(m.end)
|
| 28 |
|
| 29 |
class MazeEnvironment(Environment):
|
| 30 |
+
"""Grid-based maze environment with random maze generation."""
|
| 31 |
SUPPORTS_CONCURRENT_SESSIONS: bool = True
|
| 32 |
|
| 33 |
def __init__(self):
|
| 34 |
+
self.generator = MazeGenerator()
|
| 35 |
+
self._generate_new_maze()
|
| 36 |
+
|
| 37 |
+
def _generate_new_maze(self):
|
| 38 |
+
self._maze, self._agent_pos, self._goal_pos = self.generator.generate()
|
| 39 |
self._step_count, self._episode_id = 0, None
|
| 40 |
+
|
| 41 |
+
@property
|
| 42 |
+
def row(self): return len(self._maze)
|
| 43 |
+
@property
|
| 44 |
+
def col(self): return len(self._maze[0])
|
| 45 |
|
| 46 |
@property
|
| 47 |
def state(self) -> MazeState:
|
| 48 |
+
return MazeState(maze=self._maze, agent_pos=self._agent_pos,
|
| 49 |
+
goal_pos=self._goal_pos, episode_id=self._episode_id,
|
| 50 |
step_count=self._step_count)
|
| 51 |
|
| 52 |
def reset(self, seed=None, episode_id=None, **kwargs) -> MazeObservation:
|
| 53 |
+
if seed: random.seed(seed)
|
| 54 |
+
self._generate_new_maze()
|
| 55 |
+
self._episode_id = episode_id
|
| 56 |
return MazeObservation(position=self._agent_pos, grid_view=self._render(), done=False, reward=0)
|
| 57 |
|
| 58 |
def step(self, action: MazeAction, timeout_s=None, **kwargs) -> MazeObservation:
|
| 59 |
+
if action.direction in ["up", "down", "left", "right"]:
|
| 60 |
+
self._move(action.direction)
|
| 61 |
self._step_count += 1
|
| 62 |
done = self._agent_pos == self._goal_pos
|
| 63 |
+
return MazeObservation(position=self._agent_pos, grid_view=self._render(),
|
| 64 |
done=done, reward=10 if done else -1)
|
| 65 |
|
| 66 |
def _move(self, d):
|
| 67 |
i, j = self._agent_pos
|
| 68 |
+
if d == 'up': i -= 1
|
| 69 |
+
elif d == 'down': i += 1
|
| 70 |
+
elif d == 'left': j -= 1
|
| 71 |
+
elif d == 'right': j += 1
|
| 72 |
+
if 0 <= i < self.row and 0 <= j < self.col and self._maze[i][j]:
|
| 73 |
+
self._agent_pos = [i, j]
|
| 74 |
|
| 75 |
def _render(self) -> str:
|
| 76 |
+
symbols = {0: '#', 1: '.'}
|
| 77 |
+
lines = []
|
| 78 |
+
for i in range(self.row):
|
| 79 |
+
row = []
|
| 80 |
+
for j in range(self.col):
|
| 81 |
+
if [i, j] == self._agent_pos: row.append("A")
|
| 82 |
+
elif [i, j] == self._goal_pos: row.append("G")
|
| 83 |
+
else: row.append(symbols[self._maze[i][j]])
|
| 84 |
+
lines.append(" ".join(row))
|
| 85 |
+
return "\n".join(lines)
|