Repository navigation
Add minesweeper env and example #236
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
acharyaanusha
wants to merge
33
commits into
openenv:main
Choose a base branch
from
acharyaanusha:feature/minesweeper_env
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+2,058
−0
Open
Changes from 31 commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
e3cda7d
Add Minesweeper environment core implementation
acharyaanusha 9730c27
Add Docker support and example for Minesweeper environment
acharyaanusha e147894
Add tests and CI/CD integration for Minesweeper environment
acharyaanusha 1469cc8
Update minesweeper environment to align with OpenEnv standards
acharyaanusha 98bf1d4
Refactor Minesweeper environment tests and Dockerfile CMD for improve…
acharyaanusha 2b38813
Merge branch 'main' into feature/minesweeper_env
acharyaanusha 100833d
Merge branch 'main' into feature/minesweeper_env
burtenshaw ab02918
Merge branch 'main' into feature/minesweeper_env
acharyaanusha d54657e
Merge branch 'main' into feature/minesweeper_env
acharyaanusha fe25387
Merge branch 'main' into feature/minesweeper_env
acharyaanusha 0601bab
Fix minesweeper tests: close WebSocket clients to prevent session cap…
acharyaanusha f94968f
Convert minesweeper tests to async to work with async EnvClient
acharyaanusha ae12c52
Merge branch 'main' into feature/minesweeper_env
acharyaanusha 1dde181
Fix IndexError: auto-reset environment in __init__ so board is playab…
acharyaanusha 67eda74
Merge branch 'main' into feature/minesweeper_env
acharyaanusha a9a0d6f
Merge branch 'main' into feature/minesweeper_env
acharyaanusha 2a06cd1
Merge branch 'main' into feature/minesweeper_env
acharyaanusha 58e1b68
Merge branch 'main' into feature/minesweeper_env
acharyaanusha f90158e
Merge branch 'main' into feature/minesweeper_env
acharyaanusha 7ed5ac3
Merge branch 'main' into feature/minesweeper_env
acharyaanusha faf4e51
Merge branch 'main' into feature/minesweeper_env
acharyaanusha fa03d71
Address PR review: remove no-op try/except shims and tidy Tier 1 issues
acharyaanusha 84a565d
Move minesweeper env to envs/, align with project conventions
acharyaanusha 41836c9
Fix win-condition bug and address PR review follow-ups
acharyaanusha 0b9b3d5
Merge branch 'main' into feature/minesweeper_env
acharyaanusha 09e31e2
Merge branch 'main' into feature/minesweeper_env
acharyaanusha e4697e4
fix(minesweeper): support seeded reset with session-local RNG
burtenshaw 546769c
Merge remote-tracking branch 'origin/main' into t3/pr236-r2
burtenshaw 16783a1
fix(minesweeper): repair runtime entry points and validate board conf…
burtenshaw c53c2c6
Merge remote-tracking branch 'origin/main' into t3/pr236-r2
burtenshaw cf53636
fix(minesweeper): bound flag rewards and sync package documentation
burtenshaw e80510f
Fix Minesweeper flood fill stack overflow
burtenshaw 0ab38b5
test(minesweeper): wait for server readiness and surface startup fail…
burtenshaw File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| <!-- openenv-source: minesweeper_env --> | ||
| # Minesweeper Environment | ||
|
|
||
| A Minesweeper game environment for reinforcement learning agents. The environment consists of a grid with hidden mines where the agent must reveal all non-mine cells without triggering any mines. | ||
|
|
||
| ## Overview | ||
|
|
||
| The agent can perform two types of actions: | ||
| - Reveal cells to uncover numbers indicating adjacent mines | ||
| - Place or remove flags on suspected mine locations | ||
|
|
||
| The game ends when all non-mine cells are revealed (win) or a mine is revealed (loss). | ||
|
|
||
| ## Quick Start | ||
|
|
||
| ```python | ||
| from minesweeper_env import MinesweeperAction, MinesweeperEnv | ||
|
|
||
| # Create environment from Docker image | ||
| minesweeper_env = MinesweeperEnv.from_docker_image("minesweeper-env:latest").sync() | ||
|
|
||
| try: | ||
| # Reset the environment | ||
| result = minesweeper_env.reset() | ||
| print(f"Board size: {result.observation.board_height}x{result.observation.board_width}") | ||
| print(f"Number of mines: {result.observation.num_mines}") | ||
|
|
||
| # Reveal a cell | ||
| result = minesweeper_env.step(MinesweeperAction(row=2, col=2, action_type="reveal")) | ||
| print(f"Cells revealed: {result.observation.cells_revealed}") | ||
| print(f"Reward: {result.observation.reward}") | ||
|
|
||
| # Place a flag | ||
| result = minesweeper_env.step(MinesweeperAction(row=1, col=1, action_type="flag")) | ||
| print(f"Flags placed: {result.observation.flags_placed}") | ||
|
|
||
| finally: | ||
| minesweeper_env.close() | ||
| ``` | ||
|
|
||
| ## Building the Docker Image | ||
|
|
||
| Build the Docker image from the project root: | ||
|
|
||
| ```bash | ||
| docker build -t minesweeper-env:latest -f envs/minesweeper_env/server/Dockerfile envs/minesweeper_env | ||
| ``` | ||
|
|
||
| Or use the build script: | ||
|
|
||
| ```bash | ||
| cd envs/minesweeper_env/server | ||
| ./build_docker.sh latest | ||
| ``` | ||
|
|
||
| ## Environment Details | ||
|
|
||
| ### Action | ||
|
|
||
| **MinesweeperAction**: Specifies the cell and action type | ||
| - `row` (int) - Row index (0-indexed) | ||
| - `col` (int) - Column index (0-indexed) | ||
| - `action_type` (str) - Either "reveal" or "flag" | ||
|
|
||
| ### Observation | ||
|
|
||
| **MinesweeperObservation**: Current board state and game information | ||
| - `board` (list[list]) - 2D grid showing the current state of each cell: | ||
| - `-1`: Unrevealed cell | ||
| - `0-8`: Number of adjacent mines (revealed cell) | ||
| - `'F'`: Flagged cell | ||
| - `'*'`: Mine (only shown when game is lost) | ||
| - `num_mines` (int) - Total number of mines on the board | ||
| - `flags_placed` (int) - Number of flags currently placed | ||
| - `cells_revealed` (int) - Number of cells that have been revealed | ||
| - `game_status` (GameStatus) - Current game status (ONGOING, WON, or LOST) | ||
| - `done` (bool) - Whether the game has ended | ||
| - `reward` (float) - Reward from the last action | ||
| - `metadata` (dict) - Additional information | ||
|
|
||
| ### Rewards | ||
|
|
||
| - Revealing a safe cell: +1.0 | ||
| - Placing a flag on a mine: +0.5 once per mine per episode. Removing or replacing a previously rewarded flag gives 0; reset restores bonus eligibility. | ||
| - Revealing a mine (game over): -10.0 | ||
| - Revealing an already revealed cell: -0.05 | ||
| - Invalid action: -0.1 | ||
|
|
||
| ### Game Status | ||
|
|
||
| - `GameStatus.ONGOING`: Game is still in progress | ||
| - `GameStatus.WON`: All non-mine cells have been revealed | ||
| - `GameStatus.LOST`: A mine was revealed | ||
|
|
||
| ## Configuration | ||
|
|
||
| The default configuration is: | ||
| - Board height: 5 | ||
| - Board width: 5 | ||
| - Number of mines: 5 | ||
|
|
||
| These can be configured when initializing the environment server. | ||
|
|
||
| ## Connecting to an Existing Server | ||
|
|
||
| If you have a server already running: | ||
|
|
||
| ```python | ||
| from minesweeper_env import MinesweeperEnv | ||
|
|
||
| # Connect to existing server | ||
| minesweeper_env = MinesweeperEnv(base_url="http://localhost:8000") | ||
|
|
||
| # Use as normal | ||
| result = minesweeper_env.reset() | ||
| ``` | ||
|
|
||
| Note: When connecting to an existing server, `close()` will not stop the server. | ||
|
|
||
| ## Running Tests | ||
|
|
||
| Run the test suite: | ||
|
|
||
| ```bash | ||
| python tests/envs/test_minesweeper_env.py | ||
| ``` | ||
|
|
||
| ## Project Structure | ||
|
|
||
| ``` | ||
| minesweeper_env/ | ||
| ├── __init__.py # Module exports | ||
| ├── README.md # This file | ||
| ├── client.py # MinesweeperEnv client implementation | ||
| ├── models.py # Action, Observation, and State models | ||
| ├── openenv.yaml # Environment configuration | ||
| ├── pyproject.toml # Package dependencies | ||
| └── server/ | ||
| ├── __init__.py # Server module exports | ||
| ├── minesweeper_environment.py # Core game logic | ||
| ├── app.py # FastAPI application | ||
| ├── Dockerfile # Container image definition | ||
| └── build_docker.sh # Build script | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,143 @@ | ||
| # Minesweeper Environment | ||
|
|
||
| A Minesweeper game environment for reinforcement learning agents. The environment consists of a grid with hidden mines where the agent must reveal all non-mine cells without triggering any mines. | ||
|
|
||
| ## Overview | ||
|
|
||
| The agent can perform two types of actions: | ||
| - Reveal cells to uncover numbers indicating adjacent mines | ||
| - Place or remove flags on suspected mine locations | ||
|
|
||
| The game ends when all non-mine cells are revealed (win) or a mine is revealed (loss). | ||
|
|
||
| ## Quick Start | ||
|
|
||
| ```python | ||
| from minesweeper_env import MinesweeperAction, MinesweeperEnv | ||
|
|
||
| # Create environment from Docker image | ||
| minesweeper_env = MinesweeperEnv.from_docker_image("minesweeper-env:latest").sync() | ||
|
|
||
| try: | ||
| # Reset the environment | ||
| result = minesweeper_env.reset() | ||
| print(f"Board size: {result.observation.board_height}x{result.observation.board_width}") | ||
| print(f"Number of mines: {result.observation.num_mines}") | ||
|
|
||
| # Reveal a cell | ||
| result = minesweeper_env.step(MinesweeperAction(row=2, col=2, action_type="reveal")) | ||
| print(f"Cells revealed: {result.observation.cells_revealed}") | ||
| print(f"Reward: {result.observation.reward}") | ||
|
|
||
| # Place a flag | ||
| result = minesweeper_env.step(MinesweeperAction(row=1, col=1, action_type="flag")) | ||
| print(f"Flags placed: {result.observation.flags_placed}") | ||
|
|
||
| finally: | ||
| minesweeper_env.close() | ||
| ``` | ||
|
|
||
| ## Building the Docker Image | ||
|
|
||
| Build the Docker image from the project root: | ||
|
|
||
| ```bash | ||
| docker build -t minesweeper-env:latest -f envs/minesweeper_env/server/Dockerfile envs/minesweeper_env | ||
| ``` | ||
|
|
||
| Or use the build script: | ||
|
|
||
| ```bash | ||
| cd envs/minesweeper_env/server | ||
| ./build_docker.sh latest | ||
| ``` | ||
|
|
||
| ## Environment Details | ||
|
|
||
| ### Action | ||
|
|
||
| **MinesweeperAction**: Specifies the cell and action type | ||
| - `row` (int) - Row index (0-indexed) | ||
| - `col` (int) - Column index (0-indexed) | ||
| - `action_type` (str) - Either "reveal" or "flag" | ||
|
|
||
| ### Observation | ||
|
|
||
| **MinesweeperObservation**: Current board state and game information | ||
| - `board` (list[list]) - 2D grid showing the current state of each cell: | ||
| - `-1`: Unrevealed cell | ||
| - `0-8`: Number of adjacent mines (revealed cell) | ||
| - `'F'`: Flagged cell | ||
| - `'*'`: Mine (only shown when game is lost) | ||
| - `num_mines` (int) - Total number of mines on the board | ||
| - `flags_placed` (int) - Number of flags currently placed | ||
| - `cells_revealed` (int) - Number of cells that have been revealed | ||
| - `game_status` (GameStatus) - Current game status (ONGOING, WON, or LOST) | ||
| - `done` (bool) - Whether the game has ended | ||
| - `reward` (float) - Reward from the last action | ||
| - `metadata` (dict) - Additional information | ||
|
|
||
| ### Rewards | ||
|
|
||
| - Revealing a safe cell: +1.0 | ||
| - Placing a flag on a mine: +0.5 once per mine per episode. Removing or replacing a previously rewarded flag gives 0; reset restores bonus eligibility. | ||
| - Revealing a mine (game over): -10.0 | ||
| - Revealing an already revealed cell: -0.05 | ||
| - Invalid action: -0.1 | ||
|
|
||
| ### Game Status | ||
|
|
||
| - `GameStatus.ONGOING`: Game is still in progress | ||
| - `GameStatus.WON`: All non-mine cells have been revealed | ||
| - `GameStatus.LOST`: A mine was revealed | ||
|
|
||
| ## Configuration | ||
|
|
||
| The default configuration is: | ||
| - Board height: 5 | ||
| - Board width: 5 | ||
| - Number of mines: 5 | ||
|
|
||
| These can be configured when initializing the environment server. | ||
|
|
||
| ## Connecting to an Existing Server | ||
|
|
||
| If you have a server already running: | ||
|
|
||
| ```python | ||
| from minesweeper_env import MinesweeperEnv | ||
|
|
||
| # Connect to existing server | ||
| minesweeper_env = MinesweeperEnv(base_url="http://localhost:8000") | ||
|
|
||
| # Use as normal | ||
| result = minesweeper_env.reset() | ||
| ``` | ||
|
|
||
| Note: When connecting to an existing server, `close()` will not stop the server. | ||
|
|
||
| ## Running Tests | ||
|
|
||
| Run the test suite: | ||
|
|
||
| ```bash | ||
| python tests/envs/test_minesweeper_env.py | ||
| ``` | ||
|
|
||
| ## Project Structure | ||
|
|
||
| ``` | ||
| minesweeper_env/ | ||
| ├── __init__.py # Module exports | ||
| ├── README.md # This file | ||
| ├── client.py # MinesweeperEnv client implementation | ||
| ├── models.py # Action, Observation, and State models | ||
| ├── openenv.yaml # Environment configuration | ||
| ├── pyproject.toml # Package dependencies | ||
| └── server/ | ||
| ├── __init__.py # Server module exports | ||
| ├── minesweeper_environment.py # Core game logic | ||
| ├── app.py # FastAPI application | ||
| ├── Dockerfile # Container image definition | ||
| └── build_docker.sh # Build script | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| # Copyright (c) Meta Platforms, Inc. and affiliates. | ||
| # All rights reserved. | ||
| # | ||
| # This source code is licensed under the BSD-style license found in the | ||
| # LICENSE file in the root directory of this source tree. | ||
|
|
||
| """Minesweeper Environment - a grid-based puzzle game for OpenEnv.""" | ||
|
|
||
| from .client import MinesweeperEnv | ||
| from .models import GameStatus, MinesweeperAction, MinesweeperObservation | ||
|
|
||
| __all__ = [ | ||
| "GameStatus", | ||
| "MinesweeperAction", | ||
| "MinesweeperEnv", | ||
| "MinesweeperObservation", | ||
| ] |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.