Skip to content

Commit

Permalink
Added initial pygame-web WASM code (working locally)
Browse files Browse the repository at this point in the history
  • Loading branch information
elliottower committed Mar 9, 2023
1 parent 312c53a commit 7a0e3ac
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 4 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# https://pre-commit.com
# This GitHub Action assumes that the repo contains a valid .pre-commit-config.yaml file.
---
name: pre-commit
on:
pull_request:
push:
branches: [master]

permissions:
contents: read

jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
- run: pip install pre-commit
- run: pre-commit --version
- run: pre-commit install
- run: pre-commit run --all-files
21 changes: 21 additions & 0 deletions .github/workflows/pygbag.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

name: pygbag_build
on: [workflow_dispatch]


jobs:
build-pygbag:
name: Build for Emscripten pygbag runtime
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Checkout
run: |
python -m pip install pygbag
python -m pygbag --build $GITHUB_WORKSPACE/main.py
- name : "Upload to GitHub pages branch gh-pages"
uses: JamesIves/github-pages-deploy-action@4.1.7
with:
branch: gh-pages
folder: build/web
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,7 @@ gobblet/game/__PYCACHE__/*
/gobblet/examples/example_cleanRL_batch.py
/tests/test.py
*.gif
*/__pycache__/
gobblet/__pycache__/
/build/
/modules/

Binary file removed gobblet/__pycache__/__init__.cpython-39.pyc
Binary file not shown.
Binary file removed gobblet/__pycache__/gobblet_v1.cpython-38.pyc
Binary file not shown.
5 changes: 2 additions & 3 deletions gobblet/examples/example_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ def get_args() -> argparse.Namespace:
)

if args.render_mode == "human":
time.sleep(
0.5
) # Wait .5 seconds between moves so the user can follow the sequence of moves
# Wait .5 seconds between moves so the user can follow the sequence of moves
time.sleep(0.5)

env.step(action)
8 changes: 8 additions & 0 deletions install_wasm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash
mkdir -p modules
cd modules

python -m pip download pettingzoo==1.22.3 # tianshou==0.4.1 torch==1.13.1

unzip -o '*.whl'
rm *.whl
41 changes: 41 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import asyncio
import sys

sys.path.append("modules")

import numpy as np # noqa: E402 F401
import time # noqa: E402
from gobblet import gobblet_v1 # noqa: E402


PLAYER = 0
DEPTH = 2
RENDER_MODE = "human"
RENDER_DELAY = 0.1

async def main() -> None:
env = gobblet_v1.env(render_mode="human", args=None)
env.reset()
env.render() # need to render the environment before pygame can take user input

for agent in env.agent_iter():
observation, reward, termination, truncation, info = env.last()

if termination or truncation:
print(f"Agent: ({agent}), Reward: {reward}, info: {info}")
break

action_mask = observation["action_mask"]
action = np.random.choice(
np.arange(len(action_mask)), p=action_mask / np.sum(action_mask)
)

# Wait .5 seconds between moves so the user can follow the sequence of moves
time.sleep(0.5)
env.step(action)

await asyncio.sleep(0) # Very important, and keep it 0


if __name__ == "__main__":
asyncio.run(main())
39 changes: 39 additions & 0 deletions tutorials/PygameWASM/pygame_wasm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Tutorial
This tutorial provides a working example of using Pygame with WebAssembly to run and render a Gobblet environment locally in the browser.

The script displays a game of chess between two random agents.
Features such as loading trained models or using interactive environments may be added in the future.

It can be deployed to github-pages via a workflow (see `.github/workflows/pygbag.yml`).

## Pygame & WebAssembly (WASM)

[WebAssembly](https://webassembly.org/) (WASM) allows many languages to run locally in the browser with near-native performance. The python package [Pygbag](https://github.com/pygame-web/pygbag) allows us to run python scripts in the web using WebAssembly--including [Pygame](https://github.com/pygame/pygame), which is used for rendering PettingZoo environments.

For more information and example scripts, see [pygame-web](https://github.com/pygame-web/pygame-web.github.io)

Packages may not all work natively using Pygbag, so any issues can be reported to [pkg-porting-wasm](https://github.com/pygame-web/pkg-porting-wasm)

Pygbag works via a virtual environment, and all dependencies must be downloaded locally as wheels and unzipped. `install.sh` script does this and moves the unzipped packages into `/modules` which needs to be added to the system path before importing. Pygbag only allows a single file `main.py` to be used, and requires a specific structure using `asyncio` (see [pygame-web](https://github.com/pygame-web/pygame-web.github.io))



## Usage:

1. (Optional) Create a virtual environment: `conda create -n pygame-wasm python=3.10`
2. (Optional) Activate the virtual environment: `conda activate pygame-wasm`
3. Install requirements: `pip install -r requirements.txt`
4. Run `bash install.sh` in order to download and unzip dependencies to be used in the WASM virtual machine.
5. Change directory to parent of root project directory: `cd ../../..`
6. Run pygbag on this directory: pygbag PygameWASM `
7. Open your browser and go to `http://localhost:8000/` (for debugging info: http://localhost:8000/#debug)

## Modifying:
Dependencies and versions can be changed in `install.sh`, which can be re-run (although it is safest to delete `/modules` and ensure there are not multiple versions of the same package)

## Debugging:

- Python 3.11 is recommended for WASM, but is currently not supported by PettingZoo, which may lead to errors.

- Calling certain sub-modules (e.g., `package.submodule`) without explicitly importing them can also cause errors. For example, in `connect_four.py`, line 281 ` observation = np.array(pygame.surfarray.pixels3d(self.screen))` raises an error.
- This can be solved by explicitly importing the sub-module: add the line `import pygame.surfarray` to `main.py` (no need to modify the original file it was called in)
5 changes: 5 additions & 0 deletions tutorials/PygameWASM/requirements_wasm.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
numpy==1.23.5
pettingzoo==1.22.3
asyncio==3.4.3
pygbag==0.7.1
token-utils==0.1.8

0 comments on commit 7a0e3ac

Please sign in to comment.