def get_observation_space(self):
city_space = gymnasium.spaces.Dict({
# Common city fields
'id': gymnasium.spaces.Box(low=-1, high=32767, shape=(1,), dtype=np.int16),
'owner': gymnasium.spaces.Box(low=0, high=255, shape=(1,), dtype=np.uint8),
'size': gymnasium.spaces.Box(low=0, high=255, shape=(1,), dtype=np.uint8),
# TODO: may change this to actual map size
'x': gymnasium.spaces.Box(low=0, high=255, shape=(1,), dtype=np.uint8),
'y': gymnasium.spaces.Box(low=0, high=255, shape=(1,), dtype=np.uint8),
'name': gymnasium.spaces.Text(max_length=100),
# My city fields
'food_stock': gymnasium.spaces.Box(low=-1, high=32767, shape=(1,), dtype=np.int16),
'granary_size': gymnasium.spaces.Box(low=-1, high=32767, shape=(1,), dtype=np.int16),
'granary_turns': gymnasium.spaces.Box(low=-32768, high=32767, shape=(1,), dtype=np.int16),
'production_kind': gymnasium.spaces.Box(low=-1, high=127, shape=(1,), dtype=np.int8),
'production_value': gymnasium.spaces.Box(low=-1, high=127, shape=(1,), dtype=np.int8),
'city_radius_sq': gymnasium.spaces.Box(low=-1, high=127, shape=(1,), dtype=np.int8),
'buy_cost': gymnasium.spaces.Box(low=-1, high=32767, shape=(1,), dtype=np.int16),
'shield_stock': gymnasium.spaces.Box(low=-1, high=32767, shape=(1,), dtype=np.int16),
'disbanded_shields': gymnasium.spaces.Box(low=-1, high=32767, shape=(1,), dtype=np.int16),
'caravan_shields': gymnasium.spaces.Box(low=-1, high=32767, shape=(1,), dtype=np.int16),
'last_turns_shield_surplus': gymnasium.spaces.Box(low=-32768, high=32767, shape=(1,), dtype=np.int16),
'luxury': gymnasium.spaces.Box(low=-1, high=32767, shape=(1,), dtype=np.int16),
'science': gymnasium.spaces.Box(low=-1, high=32767, shape=(1,), dtype=np.int16),
'prod_food': gymnasium.spaces.Box(low=-1, high=32767, shape=(1,), dtype=np.int16),
'surplus_food': gymnasium.spaces.Box(low=-32768, high=32767, shape=(1,), dtype=np.int16),
'prod_gold': gymnasium.spaces.Box(low=-1, high=32767, shape=(1,), dtype=np.int16),
'surplus_gold': gymnasium.spaces.Box(low=-32768, high=32767, shape=(1,), dtype=np.int16),
'prod_shield': gymnasium.spaces.Box(low=-1, high=32767, shape=(1,), dtype=np.int16),
'surplus_shield': gymnasium.spaces.Box(low=-32768, high=32767, shape=(1,), dtype=np.int16),
'prod_trade': gymnasium.spaces.Box(low=-1, high=32767, shape=(1,), dtype=np.int16),
'surplus_trade': gymnasium.spaces.Box(low=-32768, high=32767, shape=(1,), dtype=np.int16),
'bulbs': gymnasium.spaces.Box(low=-1, high=32767, shape=(1,), dtype=np.int16),
'city_waste': gymnasium.spaces.Box(low=-1, high=32767, shape=(1,), dtype=np.int16),
'city_corruption': gymnasium.spaces.Box(low=-1, high=32767, shape=(1,), dtype=np.int16),
'city_pollution': gymnasium.spaces.Box(low=-1, high=32767, shape=(1,), dtype=np.int16),
# -1: None, 1: Disorder, 2: Peace, 3: Celebrating
'state': gymnasium.spaces.Box(low=-1, high=3, shape=(1,), dtype=np.int8),
'growth_in': gymnasium.spaces.Text(max_length=100),
'turns_to_prod_complete': gymnasium.spaces.Box(low=-32768, high=32767, shape=(1,), dtype=np.int16),
'prod_process': gymnasium.spaces.Box(low=-32768, high=32767, shape=(1,), dtype=np.int16),
'ppl_angry': gymnasium.spaces.Box(low=-1, high=127, shape=(1,), dtype=np.int8),
'ppl_unhappy': gymnasium.spaces.Box(low=-1, high=127, shape=(1,), dtype=np.int8),
'ppl_content': gymnasium.spaces.Box(low=-1, high=127, shape=(1,), dtype=np.int8),
'ppl_happy': gymnasium.spaces.Box(low=-1, high=127, shape=(1,), dtype=np.int8),
# Boolean vector
'can_build_unit': gymnasium.spaces.Box(low=0, high=1, shape=(self.rule_ctrl.ruleset_control['num_unit_types'],), dtype=np.int8),
# Boolean vector
'improvements': gymnasium.spaces.Box(low=0, high=1, shape=(self.rule_ctrl.ruleset_control['num_impr_types'],), dtype=np.int8),
'turn_last_built': gymnasium.spaces.Box(low=1, high=32767, shape=(1,), dtype=np.int16),
})
return gymnasium.spaces.Dict({city_id: city_space for city_id in self.city_dict.keys()})