File size: 7,943 Bytes
989fa32
60fafb1
 
 
 
989fa32
 
60fafb1
 
 
 
 
989fa32
 
60fafb1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
---
title: Snake Environment Server
emoji: 🐉
colorFrom: blue
colorTo: green
sdk: docker
pinned: false
app_port: 8000
base_path: /web
tags:
  - openenv-0.10.0
  - openenv
---

# Snake Environment

A multi-agent snake game environment for OpenEnv, based on [marlenv](https://github.com/kc-ml2/marlenv)'s Snake-v1. This environment provides a single-agent interface to the classic snake game where the snake must navigate a grid, eat fruits, and avoid walls and its own body.

![Snake web playground](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/openenv/snake.png)

*The `/web` playground after a few steps: the snake, the fruit and one button per move.*

## Overview

The Snake environment wraps the marlenv Snake-v1 environment to provide a clean OpenEnv-compatible interface. Multiple snakes can battle on a fixed size grid map, but this implementation focuses on single-agent gameplay.

### Features

- **Grid-based gameplay**: Configurable grid size (default: 20x20)
- **Fruit collection**: Snake grows when eating fruits
- **Partial observability**: Optional vision range for limited field of view
- **Customizable rewards**: Configurable reward function for different game aspects
- **Two control modes**:
  - `snake`: Relative actions (turn left/right)
  - `human`: Global directions (up/down/left/right)

### Game Rules

- Snake dies when its head hits a wall or its own body
- Snake grows by one unit when it eats a fruit
- Episode ends when the snake dies or reaches maximum steps
- Rewards can be customized for: eating fruits, survival time, and death penalty

## Quick Start

### Using Docker (Recommended)

```python
from envs.snake_env import SnakeAction, SnakeEnv

# Start environment from Docker image
client = SnakeEnv.from_docker_image("snake-env:latest")

# Reset to start new episode
result = client.reset()
print(f"Snake alive: {result.observation.alive}")
print(f"Grid shape: {len(result.observation.grid)}x{len(result.observation.grid[0])}")

# Take actions
result = client.step(SnakeAction(action=0))  # Continue straight
print(f"Reward: {result.reward}")
print(f"Score: {result.observation.episode_score}")

result = client.step(SnakeAction(action=1))  # Turn left
result = client.step(SnakeAction(action=2))  # Turn right

# Check game state
state = client.state()
print(f"Episode: {state.episode_id}")
print(f"Steps: {state.step_count}")

# Cleanup
client.close()
```

### Using Local Server

```bash
# Install dependencies
cd envs/snake_env
pip install -e .

# Run server
uv run --project . server
```

Then connect from another terminal:

```python
from envs.snake_env import SnakeAction, SnakeEnv

# Connect to running server
client = SnakeEnv(base_url="http://localhost:8000")
result = client.reset()
result = client.step(SnakeAction(action=0))
```

## Actions

The action space depends on the `observer` mode:

### Snake Mode (Default)
Relative actions based on current direction:
- `0`: No-op (continue in same direction)
- `1`: Turn left (90 degrees counterclockwise)
- `2`: Turn right (90 degrees clockwise)

### Human Mode
Global directional actions:
- `0`: No-op
- `1`: Move left
- `2`: Move right
- `3`: Move down
- `4`: Move up

## Observations

Each observation includes:

- `grid`: The full game grid as a 2D array (height × width)
- `observation`: Encoded observation based on vision range
- `episode_score`: Cumulative score in current episode
- `episode_steps`: Number of steps taken
- `episode_fruits`: Number of fruits eaten
- `episode_kills`: Number of kills (always 0 in single-agent mode)
- `alive`: Whether the snake is still alive

## Configuration

### Environment Parameters

```python
from envs.snake_env.server.snake_environment import SnakeEnvironment

env = SnakeEnvironment(
    height=20,           # Grid height (default: 20)
    width=20,            # Grid width (default: 20)
    snake_length=3,      # Initial snake length (default: 3)
    vision_range=5,      # Partial observability (None for full grid)
    observer='snake',    # 'snake' or 'human' mode
    max_episode_steps=1000,  # Maximum steps per episode
    reward_dict={        # Custom reward function
        'fruit': 1.0,    # Reward for eating fruit
        'kill': 0.0,     # Reward for kills (multi-agent)
        'lose': -1.0,    # Penalty for death
        'win': 0.0,      # Reward for winning (multi-agent)
        'time': 0.0,     # Reward per timestep
    }
)
```

### Custom Rewards

You can customize the reward function to encourage different behaviors:

```python
# Encourage survival
reward_dict = {
    'fruit': 1.0,
    'lose': -10.0,
    'time': 0.01,  # Small reward for staying alive
}

# Fast fruit collection
reward_dict = {
    'fruit': 10.0,
    'lose': -1.0,
    'time': -0.01,  # Penalty for taking too long
}
```

## Building and Deployment

### Build Docker Image

From the repository root:

```bash
# Build base image first (if not already built)
docker build -t openenv-base:latest -f src/openenv/core/containers/images/Dockerfile .

# Build snake environment image
docker build -t snake-env:latest -f envs/snake_env/server/Dockerfile .
```

The Dockerfile uses `pip install` with `requirements.txt` for maximum compatibility.

### Run Docker Container

```bash
# Run the container
docker run -p 8000:8000 snake-env:latest

# Or with environment variables
docker run -p 8000:8000 \
  -e ENABLE_WEB_INTERFACE=true \
  snake-env:latest
```

### Web Interface

When `ENABLE_WEB_INTERFACE=true` is set, you can access the web interface at `http://localhost:8000/web` to interact with the environment through your browser.

## Dependencies

The snake environment requires:

- `marlenv`: Multi-agent snake game implementation
- `gym==0.24.1`: OpenAI Gym (required by marlenv)
- `numpy`: Numerical operations
- Standard OpenEnv dependencies (fastapi, pydantic, uvicorn)

These are automatically installed when using Docker or installing via pip.

## Example Training Loop

```python
from envs.snake_env import SnakeAction, SnakeEnv
import random

# Connect to environment
env = SnakeEnv.from_docker_image("snake-env:latest")

# Training loop
for episode in range(10):
    result = env.reset()
    total_reward = 0
    done = False

    while not done:
        # Simple random policy (replace with your agent)
        action = SnakeAction(action=random.randint(0, 2))
        result = env.step(action)

        total_reward += result.reward
        done = result.done

    print(f"Episode {episode}: Reward={total_reward}, "
          f"Fruits={result.observation.episode_fruits}, "
          f"Steps={result.observation.episode_steps}")

env.close()
```

## Troubleshooting

### marlenv Installation Issues

If you encounter issues installing marlenv, you can install it from source:

```bash
pip install git+https://github.com/kc-ml2/marlenv.git
```

### Import Errors

Make sure you're in the correct directory when running the server:

```bash
cd envs/snake_env
uv run --project . server
```

### Docker Build Issues

Ensure the base image is built first:

```bash
docker build -t openenv-base:latest -f src/openenv/core/containers/images/Dockerfile .
```

## Citation

The underlying snake game is from marlenv:

```bibtex
@MISC{marlenv2021,
    author = {ML2},
    title = {Marlenv, Multi-agent Reinforcement Learning Environment},
    howpublished = {\url{http://github.com/kc-ml2/marlenv}},
    year = {2021}
}
```

## License

BSD 3-Clause License - See LICENSE file in the root directory.

## Hugging Face Space Deployment

This Space is built from OpenEnv environment `snake_env`.

- Space URL: `https://huggingface.co/spaces/openenv/snake_env`
- OpenEnv pinned ref: `0.10.0`
- Hub tag: `openenv`

### Connecting from Code

```bash
pip install git+https://huggingface.co/spaces/openenv/snake_env
```

```python
from snake_env import SnakeEnv

with SnakeEnv(base_url="https://openenv-snake-env.hf.space").sync() as env:
    result = env.reset()
```