4.1 - Static Info - Map Name, Size, and Start Locations
Before a single unit moves, your bot needs a complete understanding of the environment. The self.game_info
object is your access to this static blueprint. Think of it as the unchangeable physical game board: the map's size, terrain, and starting positions are all fixed at the beginning of the match and will not change.
This information is your foundation for all high-level strategy. It's available from on_start()
onwards and is essential for planning expansions, identifying chokepoints, and, most importantly, finding your enemy.
The Most Important Data: Start Locations
Locating the enemy is your first priority. The library provides several properties to help, and it's critical to understand the difference.
THE MAP (e.g., Acropolis LE)
+------------------------------------+
| P1 o | P1: Your bot's actual start
|(self.start_location) |
| |
| |
| |
| |
| o P3 | 2: The enemy's actual start
| (self.enemy_start_locations[0])|
+------------------------------------+
Property | What It Is | Common Use |
---|---|---|
self.start_location | Your exact starting Point2 . | Finding the center of your own base. |
self.enemy_start_locations | A list of your opponents' exact starting locations. | The primary way you find the enemy in a 1v1. |
The self.game_info
Attribute Table
This table details the core components of the battlefield blueprint and their strategic value.
Attribute | Data Type | Description & Practical Use Case |
---|---|---|
map_name | str | The name of the map file (e.g., "AbyssalReefLE"). Use: Log which maps your bot wins or loses on. |
map_size | Size | Dimensions (.width , .height ) of the map.Use: Judge travel times and estimate the size of your army. |
playable_area | Rect | A rectangle defining the map's playable boundaries. Use: Keep your units from getting stuck on unplayable edges. |
pathing_grid | PixelMap | A 2D array showing walkable terrain for ground units. Use (Advanced): Find chokepoints or wall-off locations by analyzing pathable tiles. |
placement_grid | PixelMap | A 2D array showing where buildings can be constructed. Use (Advanced): Find optimal, non-blocking spots for buildings. |
For RL Developers | N/A | This static data is perfect for an RL agent's observation space, as it only needs to be processed once, reducing the complexity of per-frame observations. |
Practical Application Checklist
Here is how you should think about using self.game_info
in your own projects:
- 1. Find the Enemy: Immediately grab
self.enemy_start_locations[0]
to get your primary target. - 2. Plan Expansions: Find the closest base location in
self.expansion_locations_list
(a helper property) to yourself.start_location
or useself.get_next_expansion()
that finds the closest, unoccupied expansion location to your existing bases. - 3. Determine Build Patterns: Use your start location to decide on safe places to build, like placing a Supply Depot behind your mineral line.
- 4. Set Rally Points: Calculate a safe rally point between your base and the enemy's for newly trained units.
Code Example: The Strategist Bot
This bot uses self.game_info
in on_start
to make several strategic decisions at the very beginning of the game.
# strategist_bot.py
from sc2.main import run_game
from sc2 import maps
from sc2.bot_ai import BotAI
from sc2.ids.unit_typeid import UnitTypeId
from sc2.player import Bot, Computer
from sc2.data import Difficulty, Race
class StrategistBot(BotAI):
"""A bot that uses static info to make initial strategic decisions."""
async def on_start(self):
"""Analyze the blueprint and set up a basic plan."""
print("--- Battlefield Blueprint Analysis ---")
# 1. Find the enemy's main base. This is our primary target.
self.enemy_main_base = self.enemy_start_locations[0]
print(f"Enemy main located at: {self.enemy_main_base.rounded}")
# 2. Find a safe position behind our mineral line to build depots.
# This uses vector math to move from our townhall away from the main ramp.
self.safe_build_position = self.start_location.towards(
self.main_base_ramp.top_center, -8
)
print(f"Designated safe building position: {self.safe_build_position.rounded}")
# 3. Designate a scout. We'll tag one worker for this role.
# Note: We store the tag, not the unit object, as the object can become stale.
self.scout_tag = self.workers.random.tag
print(f"Worker {self.scout_tag} has been assigned scouting duty.")
print("--- Analysis Complete ---")
async def on_step(self, iteration: int):
"""Execute the plan set in on_start."""
# Action 1: Send the designated scout to the enemy base on the first step.
if iteration == 0:
scout_unit = self.workers.by_tag(self.scout_tag)
if scout_unit:
scout_unit.attack(self.enemy_main_base)
print(f"ACTION: Scout {self.scout_tag} dispatched to enemy base.")
# Action 2: Build a Supply Depot when we are close to our supply cap.
# We also check if we can afford it and are not already building one.
if (
self.supply_left < 5
and self.can_afford(UnitTypeId.SUPPLYDEPOT)
and self.already_pending(UnitTypeId.SUPPLYDEPOT) == 0
):
# self.build is async, so it must be awaited.
await self.build(UnitTypeId.SUPPLYDEPOT, near=self.safe_build_position)
print(
f"ACTION: Building Supply Depot at safe location {self.safe_build_position.rounded}."
)
if __name__ == "__main__":
run_game(
maps.get("AbyssalReefLE"),
[Bot(Race.Terran, StrategistBot()), Computer(Race.Zerg, Difficulty.Easy)],
realtime=True,
)
Interactive Map Demonstration