oxwhirl / smac

SMAC: The StarCraft Multi-Agent Challenge
MIT License
1.08k stars 228 forks source link

Provide state in structured form as a dict and features names in a list #55

Closed douglasrizzo closed 3 years ago

douglasrizzo commented 4 years ago

A few months ago, I talked in #28 about the possibility of providing the state as structured data, so that users can distinguish individual features from individual units and use them for their own purposes. In this PR, I have implemented this by creating a method that provides the state as a Python dict, isolating allied and enemy unit types and features as well as the last actions of allied units. Basically, everything that was provided in the original state, but in a dict. The original get_state() method simply calls the new get_state_dict() method and organizes the information as was done previously.

Furthermore, I have devised a way of providing the names of features in lists which are created when the environment is initialized and returned either as class attributes or in get_env_info(). These lists are created dynamically (e.g. depending on whether the user has chosen for previous actions to be present in the state, or if units have shields or not, these feature names are either present or not in the lists).

I myself have been using these modifications for a few months, so I hope they are welcome.

I also believe this partially addresses #50.

douglasrizzo commented 3 years ago

@samvelyan Thanks for the heads-up. I'll do some debugging and try to provide a patch ASAP.

douglasrizzo commented 3 years ago

I used a small script to get the dimensions of the state and observation returned by the environment, both in this branch (after the most recent commits) and on master. I got the same results (in the table below) in both branches.

map agents agent_obs state
3m 3 30 48
8m 8 80 168
25m 25 250 950
5m_vs_6m 5 55 98
8m_vs_9m 8 85 179
10m_vs_11m 10 105 243
27m_vs_30m 27 285 1170
MMM 10 160 290
MMM2 10 176 322
2s3z 5 80 120
3s5z 8 128 216
3s5z_vs_3s6z 8 136 230
3s_vs_3z 3 36 54
3s_vs_4z 3 42 61
3s_vs_5z 3 48 68
1c3s5z 9 162 270
2m_vs_1z 2 16 26
corridor 6 156 282
6h_vs_8z 6 78 140
2s_vs_1sc 2 17 27
so_many_baneling 7 202 397
bane_vs_bane 24 336 984
2c_vs_64zg 2 332 342

Here is the script I used.

from smac.env.starcraft2.maps import smac_maps
from smac.env.starcraft2.starcraft2 import StarCraft2Env

map_names = smac_maps.get_smac_map_registry().keys()

print("map", "agents", "agent_obs", "state")

for map_name in map_names:
   env = StarCraft2Env(map_name=map_name)
   obs, state = env.reset()
   env.close()

   print(map_name, len(obs), len(obs[0]), len(state))
samvelyan commented 3 years ago

@douglasrizzo I've applied the small changes and merged the PR. Thanks a lot for your contribution.