Skip to main content

Generals.io environment compliant with PettingZoo API standard powered by Numpy.

Project description

Generals-Zoo logo

Generals.io RL

generals.io is a real-time strategy game where players compete to conquer their opponents' generals on a 2D grid. While the goal is simple — capture the enemy general — the gameplay involves a lot of depth. Players need to employ strategic planning, deception, and manage both micro and macro mechanics throughout the game. The combination of these elements makes the game highly engaging and complex.

This repository aims to make bot development more accessible, especially for Machine Learning based agents.

Highlights:

  • 🚀 Fast & Lightweight simulator powered by numpy (thousands of steps per second)
  • 🦁 Compatibility with Reinforcement-Learning API standard PettingZoo
  • 🔧 Easy customization of environments
  • 🔬 Analysis tools such as replays

Generals.io has interesting properties:

  • 👀 Partial observability
  • 🏃‍♂️ Long action sequences and large action spaces
  • 🧠 Requires strategical planning
  • ⏱️ Real-time gameplay

📦 Installation

Stable release version is available through pip:

pip install generals (not working now)

Alternatively, you can install latest version via git

git clone https://github.com/strakam/Generals-RL
cd Generals-RL
pip install -e .

Usage example

from generals.env import generals_v0
from generals.agents import RandomAgent
from generals.config import GameConfig

# Initialize agents - their names are then called for actions
agents = {
    "red": RandomAgent("red"),
    "blue": RandomAgent("blue")
}

game_config = GameConfig(
    grid_size=4,
    agent_names=list(agents.keys())
)

# Create environment
env = generals_v0(game_config, render_mode="none")
observations, info = env.reset()

while not env.game.is_done():
    actions = {}
    for agent in env.agents:
        # Ask agent for action
        actions[agent] = agents[agent].play(observations[agent])
    # All agents perform their actions
    observations, rewards, terminated, truncated, info = env.step(actions)

🎨 Customization

The environment can be customized via GridConfig class or by creating a custom map.

🗺️ Random maps

from generals.env import generals_v0
from generals.config import GameConfig

game_config = GameConfig(
    grid_size=16,                         # Edge length of the square grid
    mountain_density=0.2                  # Probability of mountain in a cell
    town_density=0.05                     # Probability of town in a cell
    general_positions=[(0,3),(5,7)]       # Positions of generals (i, j)
    agent_names=['Human.exe','Agent007']  # Names of the agents that will be called to play the game
)

# Create environment
env = generals_v0(game_config, render_mode="none")
observations, info = env.reset()

🗺️ Custom maps

Maps can be described by strings. We can either load them directly from a string or from a file.

from generals.env import generals_v0
from generals.config import GameConfig

game_config = GameConfig(
    agent_names=['Human.exe','Agent007']  # Names of the agents that will be called to play the game
)
map = """
.3.#
#..A
#..#
.#.B
"""

env.reset(map=map) # Here map related settings from game_config are overridden

Maps are encoded using these symbols:

  • . for passable terrain
  • # for non-passable terrain
  • A,B are positions of generals
  • digits 0-9 represent cost of cities calculated as (40 + digit)

🔬 Replay analysis

We can store replays and then analyze them.

Storing a replay

from generals.env import generals_v0
from generals.config import GameConfig

game_config = GameConfig()
options = {"replay_file": "replay_001"}
env.reset(options=options) # encodes the next game into a "replay_001" file

Loading a replay

import generals.utils

generals.utils.run_teplay("replay_001")

🕹️ Replay Controls

  • q — quit/close the replay
  • ←/→ — increase/decrease the replay speed
  • h/l — to control replay frames
  • spacebar — to pause
  • Mouse click on the player's row — toggle the FOV (Field Of View) of the given player

POMDP - 🔭 Observations, ⚡ Actions and 🎁 Rewards

🔭 Observation

An observation for one player is a dictionary of 8 key/value pairs. Each value is a 2D np.array containing information for each cell. Values are (binary) masked so that only information about cells that an agent can see can be non-zero.

Key Shape Description
army (N,N,1) Number of units in a cell regardless of owner
general (N,N,1) Mask of cells that are visible to the agent
city (N,N,1) Mask saying whether a city is in a cell
ownership (N,N,1) Mask indicating cells controlled by the agent
ownership_opponent (N,N,1) Mask indicating cells owned by the opponent
ownership_neutral (N,N,1) Mask indicating cells that are not owned by agents
structure (N,N,1) Mask indicating whether cells contain cities or mountains, even out of FoV
action_mask (N,N,4) Mask where [i,j,k] indicates whether you can move from a cell [i,j] to direction k where directions are in order (UP, DOWN, LEFT, RIGHT)

ℹ️ Information

The environment also returns information dictionary for each agent, but it is the same for everyone.

Key Type Description
army Int Total number of units that the agent controls
land Int Total number of cells that the agent controls
is_winner Bool Boolean indicator saying whether agent won

Example:

print(info['red_agent']['army'])

⚡ Action

Action is an np.array([i,j,k]) indicating that you want to move units from cell [i,j] in a direction k.

🎁 Reward

It is possible to implement custom reward function. The default is 1 for winner and -1 for loser, otherwise 0.

def custom_reward_fn(observation, info):
    # Give agent a reward based on the number of cells they own
    return {
        agent: info[agent]["land"]
        for agent in observation.keys()
    }

env = generals_v0(reward_fn=custom_reward_fn)
observations, info = env.reset()

🔨 Coming soon:

  • Extend action space to sending half of units to another square
  • Examples and baselines using RL
  • Add human control to play against
  • New analysis tools

Requests for useful features and additions are welcome 🤗.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

generals-0.0.1.tar.gz (383.2 kB view details)

Uploaded Source

Built Distribution

generals-0.0.1-py3-none-any.whl (381.8 kB view details)

Uploaded Python 3

File details

Details for the file generals-0.0.1.tar.gz.

File metadata

  • Download URL: generals-0.0.1.tar.gz
  • Upload date:
  • Size: 383.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.11.0

File hashes

Hashes for generals-0.0.1.tar.gz
Algorithm Hash digest
SHA256 55143b0e85609f77a54cf759538d8a163f55322436f485dfe17ba1ce728388c4
MD5 91afae3b88cde7b76c1fea4010802047
BLAKE2b-256 8fd78ad4f5ee7b587cebf3ad72a6ae5bb3ce421f7d141ba6a2b8decf30d85e7a

See more details on using hashes here.

File details

Details for the file generals-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: generals-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 381.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.11.0

File hashes

Hashes for generals-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4a66b0a4cd4d4ec361a92befcced442ab1d12577744f8d1c66c34969e23d23be
MD5 9bbe9daa19f728c25547b892dabdd6ff
BLAKE2b-256 648ae2fd3df90adc8774c0a245479b43210112ab713edb1b3d0ad35d9bb7fde5

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page