mettagrid 0.0.1__py3-none-any.whl → 0.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. README.md +75 -0
  2. build/lib.macosx-11.0-arm64-cpython-311/mettagrid/actions/actions.cpython-311-darwin.so +0 -0
  3. build/lib.macosx-11.0-arm64-cpython-311/mettagrid/actions/attack.cpython-311-darwin.so +0 -0
  4. build/lib.macosx-11.0-arm64-cpython-311/mettagrid/actions/gift.cpython-311-darwin.so +0 -0
  5. build/lib.macosx-11.0-arm64-cpython-311/mettagrid/actions/move.cpython-311-darwin.so +0 -0
  6. build/lib.macosx-11.0-arm64-cpython-311/mettagrid/actions/noop.cpython-311-darwin.so +0 -0
  7. build/lib.macosx-11.0-arm64-cpython-311/mettagrid/actions/rotate.cpython-311-darwin.so +0 -0
  8. build/lib.macosx-11.0-arm64-cpython-311/mettagrid/actions/shield.cpython-311-darwin.so +0 -0
  9. build/lib.macosx-11.0-arm64-cpython-311/mettagrid/actions/use.cpython-311-darwin.so +0 -0
  10. build/lib.macosx-11.0-arm64-cpython-311/mettagrid/mettagrid_c.cpython-311-darwin.so +0 -0
  11. build/lib.macosx-11.0-arm64-cpython-311/mettagrid/objects.cpython-311-darwin.so +0 -0
  12. build/mettagrid/actions/actions.cpp +33466 -0
  13. build/mettagrid/actions/attack.cpp +33253 -0
  14. build/mettagrid/actions/gift.cpp +32378 -0
  15. build/mettagrid/actions/move.cpp +32552 -0
  16. build/mettagrid/actions/noop.cpp +32376 -0
  17. build/mettagrid/actions/rotate.cpp +32394 -0
  18. build/mettagrid/actions/shield.cpp +32437 -0
  19. build/mettagrid/actions/use.cpp +32851 -0
  20. build/mettagrid/mettagrid.cpp +37718 -0
  21. build/mettagrid/objects.cpp +36083 -0
  22. mettagrid/actions/actions.cpython-311-darwin.so +0 -0
  23. mettagrid/actions/actions.pxd +2 -2
  24. mettagrid/actions/actions.pyx +19 -5
  25. mettagrid/actions/attack.cpython-311-darwin.so +0 -0
  26. mettagrid/actions/attack.pyx +12 -3
  27. mettagrid/actions/gift.cpython-311-darwin.so +0 -0
  28. mettagrid/actions/gift.pyx +4 -1
  29. mettagrid/actions/move.cpython-311-darwin.so +0 -0
  30. mettagrid/actions/move.pyx +16 -6
  31. mettagrid/actions/noop.cpython-311-darwin.so +0 -0
  32. mettagrid/actions/noop.pxd +4 -0
  33. mettagrid/actions/noop.pyx +25 -0
  34. mettagrid/actions/rotate.cpython-311-darwin.so +0 -0
  35. mettagrid/actions/rotate.pyx +5 -3
  36. mettagrid/actions/shield.cpython-311-darwin.so +0 -0
  37. mettagrid/actions/shield.pyx +10 -3
  38. mettagrid/actions/use.cpython-311-darwin.so +0 -0
  39. mettagrid/actions/use.pyx +9 -4
  40. mettagrid/mettagrid.pyx +35 -1
  41. mettagrid/mettagrid_c.cpython-311-darwin.so +0 -0
  42. mettagrid/mettagrid_env.py +44 -72
  43. mettagrid/objects.cpython-311-darwin.so +0 -0
  44. mettagrid/objects.pxd +25 -12
  45. mettagrid/objects.pyx +19 -21
  46. mettagrid/renderer/assets/agent.png +0 -0
  47. mettagrid/renderer/assets/altar.png +0 -0
  48. mettagrid/renderer/assets/arial.ttf +0 -0
  49. mettagrid/renderer/assets/converter.png +0 -0
  50. mettagrid/renderer/assets/generator.png +0 -0
  51. mettagrid/renderer/json_renderer.py +0 -0
  52. mettagrid/renderer/raylib_renderer.py +410 -0
  53. mettagrid/renderer/render_code_example.py +56 -0
  54. mettagrid-0.0.3.dist-info/LICENSE +21 -0
  55. mettagrid-0.0.3.dist-info/METADATA +96 -0
  56. mettagrid-0.0.3.dist-info/RECORD +81 -0
  57. setup.py +91 -0
  58. test_perf.py +107 -0
  59. mettagrid/renderer/raylib_client.py +0 -180
  60. mettagrid-0.0.1.dist-info/METADATA +0 -23
  61. mettagrid-0.0.1.dist-info/RECORD +0 -38
  62. /mettagrid-0.0.1.dist-info/LICENSE → /LICENSE +0 -0
  63. /mettagrid/renderer/assets/{tiny_galaxy_items.png → items.png} +0 -0
  64. /mettagrid/renderer/assets/{tiny_galaxy_monsters.png → monsters.png} +0 -0
  65. /mettagrid/renderer/assets/{wall1-0.png → wall.png} +0 -0
  66. {mettagrid-0.0.1.dist-info → mettagrid-0.0.3.dist-info}/WHEEL +0 -0
@@ -18,13 +18,13 @@ cdef class MettaActionHandler(ActionHandler):
18
18
  cdef string action_name
19
19
  cdef int action_cost
20
20
 
21
- cdef char handle_action(
21
+ cdef bint handle_action(
22
22
  self,
23
23
  unsigned int actor_id,
24
24
  GridObjectId actor_object_id,
25
25
  ActionArg arg)
26
26
 
27
- cdef char _handle_action(
27
+ cdef bint _handle_action(
28
28
  self,
29
29
  unsigned int actor_id,
30
30
  Agent * actor,
@@ -11,7 +11,7 @@ cdef extern from "<string>" namespace "std":
11
11
  string to_string(int val)
12
12
 
13
13
  cdef class MettaActionHandler(ActionHandler):
14
- def __init__(self, cfg: OmegaConf, action_name, action_cost=0):
14
+ def __init__(self, cfg: OmegaConf, action_name):
15
15
  self.action_name = action_name
16
16
 
17
17
  self._stats.action = "action." + action_name
@@ -23,7 +23,7 @@ cdef class MettaActionHandler(ActionHandler):
23
23
 
24
24
  self.action_cost = cfg.cost
25
25
 
26
- cdef char handle_action(
26
+ cdef bint handle_action(
27
27
  self,
28
28
  unsigned int actor_id,
29
29
  GridObjectId actor_object_id,
@@ -31,7 +31,17 @@ cdef class MettaActionHandler(ActionHandler):
31
31
 
32
32
  cdef Agent *actor = <Agent*>self.env._grid.object(actor_object_id)
33
33
 
34
- if actor.frozen:
34
+ if actor.shield:
35
+ actor.energy -= actor.shield_upkeep
36
+ self.env._stats.agent_add(actor_id, "shield_upkeep", actor.shield_upkeep)
37
+ self.env._stats.agent_incr(actor_id, "status.shield.ticks")
38
+ if actor.energy <= 0:
39
+ actor.shield = False
40
+ actor.energy = 0
41
+
42
+ if actor.frozen > 0:
43
+ self.env._stats.agent_incr(actor_id, "status.frozen.ticks")
44
+ actor.frozen -= 1
35
45
  return False
36
46
 
37
47
  if actor.energy < self.action_cost:
@@ -40,14 +50,18 @@ cdef class MettaActionHandler(ActionHandler):
40
50
  actor.energy -= self.action_cost
41
51
  self.env._stats.agent_add(actor_id, self._stats.action_energy.c_str(), self.action_cost)
42
52
 
43
- cdef char result = self._handle_action(actor_id, actor, arg)
53
+ cdef bint result = self._handle_action(actor_id, actor, arg)
44
54
 
45
55
  if result:
46
56
  self.env._stats.agent_incr(actor_id, self._stats.action.c_str())
47
57
 
58
+ if actor.energy < 0:
59
+ actor.energy = 0
60
+ self.env._stats.agent_incr(actor_id, "error.negative_energy")
61
+
48
62
  return result
49
63
 
50
- cdef char _handle_action(
64
+ cdef bint _handle_action(
51
65
  self,
52
66
  unsigned int actor_id,
53
67
  Agent * actor,
@@ -12,7 +12,10 @@ cdef class Attack(MettaActionHandler):
12
12
  def __init__(self, cfg: OmegaConf):
13
13
  MettaActionHandler.__init__(self, cfg, "attack")
14
14
 
15
- cdef char _handle_action(
15
+ cdef unsigned char max_arg(self):
16
+ return 9
17
+
18
+ cdef bint _handle_action(
16
19
  self,
17
20
  unsigned int actor_id,
18
21
  Agent * actor,
@@ -24,7 +27,7 @@ cdef class Attack(MettaActionHandler):
24
27
  cdef short distance = 0
25
28
  cdef short offset = 0
26
29
  distance = 1 + (arg - 1) // 3
27
- offset = (arg - 1) % 3 - 1
30
+ offset = -((arg - 1) % 3 - 1)
28
31
 
29
32
  cdef GridLocation target_loc = self.env._grid.relative_location(
30
33
  actor.location,
@@ -42,8 +45,14 @@ cdef class Attack(MettaActionHandler):
42
45
  self.env._stats.agent_add(actor_id, "shield_damage", agent_target.energy)
43
46
  agent_target.energy = 0
44
47
  agent_target.shield = False
45
- agent_target.frozen = True
48
+ agent_target.frozen = agent_target.freeze_duration
46
49
  self.env._stats.agent_incr(actor_id, "attack.frozen")
50
+ for item in range(InventoryItem.InventoryCount):
51
+ actor.update_inventory(item, agent_target.inventory[item])
52
+ self.env._stats.agent_add(actor_id, InventoryItemNames[item] + ".stolen", agent_target.inventory[item])
53
+ self.env._stats.agent_add(actor_id, InventoryItemNames[item] + ".gained", agent_target.inventory[item])
54
+ agent_target.inventory[item] = 0
55
+
47
56
  return True
48
57
 
49
58
  target_loc.layer = GridLayer.Object_Layer
@@ -13,7 +13,10 @@ cdef class Gift(MettaActionHandler):
13
13
  def __init__(self, cfg: OmegaConf):
14
14
  MettaActionHandler.__init__(self, cfg, "gift")
15
15
 
16
- cdef char _handle_action(
16
+ cdef unsigned char max_arg(self):
17
+ return 1
18
+
19
+ cdef bint _handle_action(
17
20
  self,
18
21
  unsigned int actor_id,
19
22
  Agent * actor,
@@ -1,4 +1,3 @@
1
-
2
1
  from libc.stdio cimport printf
3
2
 
4
3
  from omegaconf import OmegaConf
@@ -13,19 +12,30 @@ cdef class Move(MettaActionHandler):
13
12
  def __init__(self, cfg: OmegaConf):
14
13
  MettaActionHandler.__init__(self, cfg, "move")
15
14
 
16
- cdef char _handle_action(
15
+ cdef unsigned char max_arg(self):
16
+ return 1
17
+
18
+ cdef bint _handle_action(
17
19
  self,
18
20
  unsigned int actor_id,
19
21
  Agent * actor,
20
22
  ActionArg arg):
21
23
 
22
24
  cdef unsigned short direction = arg
23
- if direction >= 2:
24
- return False
25
25
 
26
- cdef Orientation orientation = <Orientation>((actor.orientation + 2*(direction)) % 4)
26
+ cdef Orientation orientation = <Orientation>(actor.orientation)
27
+ if direction == 1:
28
+ if orientation == Orientation.Up:
29
+ orientation = Orientation.Down
30
+ elif orientation == Orientation.Down:
31
+ orientation = Orientation.Up
32
+ elif orientation == Orientation.Left:
33
+ orientation = Orientation.Right
34
+ elif orientation == Orientation.Right:
35
+ orientation = Orientation.Left
36
+
27
37
  cdef GridLocation old_loc = actor.location
28
38
  cdef GridLocation new_loc = self.env._grid.relative_location(old_loc, orientation)
29
39
  if not self.env._grid.is_empty(new_loc.r, new_loc.c):
30
- return False
40
+ return 0
31
41
  return self.env._grid.move_object(actor.id, new_loc)
@@ -0,0 +1,4 @@
1
+ from mettagrid.actions.actions cimport MettaActionHandler
2
+
3
+ cdef class Noop(MettaActionHandler):
4
+ pass
@@ -0,0 +1,25 @@
1
+ from libc.stdio cimport printf
2
+
3
+ from omegaconf import OmegaConf
4
+
5
+ from puffergrid.grid_object cimport GridLocation, GridObjectId, GridObject, Orientation
6
+ from puffergrid.action cimport ActionHandler, ActionArg
7
+ from mettagrid.objects cimport MettaObject, ObjectType, Usable, Altar, Agent, Events, GridLayer
8
+ from mettagrid.objects cimport Generator, Converter, InventoryItem, ObjectTypeNames, InventoryItemNames
9
+ from mettagrid.actions.actions cimport MettaActionHandler
10
+
11
+ cdef class Noop(MettaActionHandler):
12
+ def __init__(self, cfg: OmegaConf):
13
+ MettaActionHandler.__init__(self, cfg, "noop")
14
+
15
+ cdef unsigned char max_arg(self):
16
+ return 0
17
+
18
+ cdef bint _handle_action(
19
+ self,
20
+ unsigned int actor_id,
21
+ Agent * actor,
22
+ ActionArg arg):
23
+
24
+ return 1
25
+
@@ -14,15 +14,17 @@ cdef class Rotate(MettaActionHandler):
14
14
  def __init__(self, cfg: OmegaConf):
15
15
  MettaActionHandler.__init__(self, cfg, "rotate")
16
16
 
17
- cdef char _handle_action(
17
+ cdef unsigned char max_arg(self):
18
+ return 3
19
+
20
+
21
+ cdef bint _handle_action(
18
22
  self,
19
23
  unsigned int actor_id,
20
24
  Agent * actor,
21
25
  ActionArg arg):
22
26
 
23
27
  cdef unsigned short orientation = arg
24
- if orientation >= 4:
25
- return False
26
28
 
27
29
  actor.orientation = orientation
28
30
  return True
@@ -13,14 +13,21 @@ cdef class Shield(MettaActionHandler):
13
13
  def __init__(self, cfg: OmegaConf):
14
14
  MettaActionHandler.__init__(self, cfg, "shield")
15
15
 
16
- cdef char _handle_action(
16
+ cdef unsigned char max_arg(self):
17
+ return 0
18
+
19
+
20
+ cdef bint _handle_action(
17
21
  self,
18
22
  unsigned int actor_id,
19
23
  Agent * actor,
20
24
  ActionArg arg):
21
25
 
22
26
  if actor.shield:
23
- actor.shield = True
24
- else:
25
27
  actor.shield = False
28
+ elif actor.energy >= actor.shield_upkeep:
29
+ actor.shield = True
30
+
31
+ return True
32
+
26
33
 
mettagrid/actions/use.pyx CHANGED
@@ -13,7 +13,10 @@ cdef class Use(MettaActionHandler):
13
13
  def __init__(self, cfg: OmegaConf):
14
14
  MettaActionHandler.__init__(self, cfg, "use")
15
15
 
16
- cdef char _handle_action(
16
+ cdef unsigned char max_arg(self):
17
+ return 0
18
+
19
+ cdef bint _handle_action(
17
20
  self,
18
21
  unsigned int actor_id,
19
22
  Agent * actor,
@@ -52,15 +55,17 @@ cdef class Use(MettaActionHandler):
52
55
  self.env._stats.game_incr("r1.harvested")
53
56
 
54
57
  cdef Converter *converter
58
+ cdef unsigned int energy_gain = 0
55
59
  if target._type_id == ObjectType.ConverterT:
56
60
  converter = <Converter*>target
57
61
  actor.update_inventory(converter.input_resource, -1)
58
62
  self.env._stats.agent_incr(actor_id, InventoryItemNames[converter.input_resource] + ".used")
59
63
 
60
64
  actor.update_inventory(converter.output_resource, 1)
61
- self.env._stats.agent_incr(actor_id, InventoryItemNames[converter.input_resource] + ".gained")
65
+ self.env._stats.agent_incr(actor_id, InventoryItemNames[converter.output_resource] + ".gained")
62
66
 
63
- actor.energy += converter.output_energy
64
- self.env._stats.agent_add(actor_id, "energy.gained", converter.output_energy)
67
+ energy_gain = min(actor.max_energy - actor.energy, converter.output_energy)
68
+ actor.energy += energy_gain
69
+ self.env._stats.agent_add(actor_id, "energy.gained", energy_gain)
65
70
 
66
71
  return True
mettagrid/mettagrid.pyx CHANGED
@@ -1,11 +1,16 @@
1
1
 
2
2
  from libc.stdio cimport printf
3
3
 
4
+
4
5
  import numpy as np
6
+ cimport numpy as cnp
5
7
  import gymnasium as gym
6
8
  from omegaconf import OmegaConf
9
+ from types import SimpleNamespace
7
10
 
8
11
  from puffergrid.grid_env cimport GridEnv
12
+ from puffergrid.grid_object cimport GridObject
13
+ from puffergrid.observation_encoder cimport ObsType
9
14
 
10
15
  from mettagrid.objects cimport ObjectLayers, Agent, ResetHandler, Wall, Generator, Converter, Altar
11
16
  from mettagrid.objects cimport MettaObservationEncoder
@@ -15,6 +20,9 @@ from mettagrid.actions.use import Use
15
20
  from mettagrid.actions.attack import Attack
16
21
  from mettagrid.actions.shield import Shield
17
22
  from mettagrid.actions.gift import Gift
23
+ from mettagrid.actions.noop import Noop
24
+
25
+ obs_np_type = np.uint8
18
26
 
19
27
  cdef class MettaGrid(GridEnv):
20
28
  cdef:
@@ -33,6 +41,7 @@ cdef class MettaGrid(GridEnv):
33
41
  cfg.obs_width, cfg.obs_height,
34
42
  MettaObservationEncoder(),
35
43
  [
44
+ Noop(SimpleNamespace(cost=0)),
36
45
  Move(cfg.actions.move),
37
46
  Rotate(cfg.actions.rotate),
38
47
  Use(cfg.actions.use),
@@ -45,7 +54,6 @@ cdef class MettaGrid(GridEnv):
45
54
  ]
46
55
  )
47
56
 
48
-
49
57
  cdef Agent *agent
50
58
  for r in range(map.shape[0]):
51
59
  for c in range(map.shape[1]):
@@ -76,3 +84,29 @@ cdef class MettaGrid(GridEnv):
76
84
  @property
77
85
  def action_space(self):
78
86
  return gym.spaces.MultiDiscrete((self.num_actions(), 10), dtype=np.uint32)
87
+
88
+ cpdef grid_objects(self):
89
+ cdef GridObject *obj
90
+ cdef ObsType[:] obj_data = np.zeros(len(self._obs_encoder.feature_names()), dtype=obs_np_type)
91
+ cdef unsigned int obj_id, i
92
+ cdef MettaObservationEncoder obs_encoder = <MettaObservationEncoder>self._obs_encoder
93
+ objects = {}
94
+ for obj_id in range(1, self._grid.objects.size()):
95
+ obj = self._grid.object(obj_id)
96
+ if obj == NULL:
97
+ continue
98
+ objects[obj_id] = {
99
+ "id": obj_id,
100
+ "type": obj._type_id,
101
+ "r": obj.location.r,
102
+ "c": obj.location.c,
103
+ "layer": obj.location.layer
104
+ }
105
+ obs_encoder._encode(obj, obj_data, 0)
106
+ for i, name in enumerate(obs_encoder._type_feature_names[obj._type_id]):
107
+ objects[obj_id][name] = obj_data[i]
108
+
109
+ for agent_idx in range(self._agents.size()):
110
+ objects[self._agents[agent_idx].id]["agent_id"] = agent_idx
111
+
112
+ return objects
@@ -1,19 +1,13 @@
1
1
  from typing import Any, Dict
2
2
 
3
- import pufferlib
4
3
  import numpy as np
4
+ import pufferlib
5
5
  from omegaconf import OmegaConf
6
6
 
7
7
  from mettagrid.config.game_builder import MettaGridGameBuilder
8
- from mettagrid.renderer.raylib_client import MettaRaylibClient
9
8
  from mettagrid.config.sample_config import sample_config
10
- from mettagrid.mettagrid_c import MettaGrid
11
- from pufferlib.environments.ocean.render import GridRender
9
+ from mettagrid.mettagrid_c import MettaGrid # pylint: disable=E0611
12
10
 
13
- class GridClient:
14
- def __init__(self, width, height):
15
- self._width = width
16
- self._height = height
17
11
 
18
12
  class MettaGridEnv(pufferlib.PufferEnv):
19
13
  def __init__(self, render_mode: str, **cfg):
@@ -23,20 +17,17 @@ class MettaGridEnv(pufferlib.PufferEnv):
23
17
  self._cfg = OmegaConf.create(cfg)
24
18
  self.make_env()
25
19
 
26
- if render_mode == "human":
27
- self._renderer = MettaRaylibClient(
28
- self._env.map_width(), self._env.map_height(),
29
- )
30
- elif render_mode == "raylib":
31
- self._renderer = GridRender(
32
- self._env.map_width(), self._env.map_height(),
33
- fps=10
34
- )
20
+ self._renderer = None
21
+
22
+ self.done = False
23
+ self.buf = None
35
24
 
36
25
 
37
26
  def make_env(self):
38
- game_cfg = OmegaConf.create(sample_config(self._cfg.game))
39
- self._game_builder = MettaGridGameBuilder(**game_cfg)
27
+ scfg = sample_config(self._cfg.game)
28
+ assert isinstance(scfg, Dict)
29
+ game_cfg = OmegaConf.create(scfg)
30
+ self._game_builder = MettaGridGameBuilder(**scfg) # type: ignore
40
31
  level = self._game_builder.level()
41
32
  self._c_env = MettaGrid(game_cfg, level)
42
33
  self._grid_env = self._c_env
@@ -52,9 +43,9 @@ class MettaGridEnv(pufferlib.PufferEnv):
52
43
  #self._env = FeatureMasker(self._env, self._cfg.hidden_features)
53
44
  self.done = False
54
45
 
55
- def reset(self, **kwargs):
46
+ def reset(self, seed=None):
56
47
  self.make_env()
57
- if hasattr(self, "buf"):
48
+ if hasattr(self, "buf") and self.buf is not None:
58
49
  self._c_env.set_buffers(
59
50
  self.buf.observations,
60
51
  self.buf.terminals,
@@ -70,60 +61,37 @@ class MettaGridEnv(pufferlib.PufferEnv):
70
61
  def step(self, actions):
71
62
  obs, rewards, terminated, truncated, infos = self._c_env.step(actions.astype(np.int32))
72
63
 
73
- rewards_sum = rewards.sum()
74
- if rewards_sum != 0:
75
- reward_mean = rewards_sum / self._num_agents
76
- rewards -= reward_mean
64
+ if self._cfg.normalize_rewards:
65
+ rewards -= rewards.mean()
77
66
 
67
+ infos = {}
78
68
  if terminated.all() or truncated.all():
79
69
  self.done = True
80
-
81
- stats = self._c_env.get_episode_stats()
82
- episode_rewards = self._c_env.get_episode_rewards()
83
- episode_rewards_sum = episode_rewards.sum()
84
- episode_rewards_mean = episode_rewards_sum / self._num_agents
85
-
86
- infos = {
87
- "episode/reward.sum": episode_rewards_sum,
88
- "episode/reward.mean": episode_rewards_mean,
89
- "episode/reward.min": episode_rewards.min(),
90
- "episode/reward.max": episode_rewards.max(),
91
- "episode_length": self._c_env.current_timestep(),
92
- }
93
-
94
- agent_stats = {}
95
- for a_stats in stats["agent_stats"]:
96
- for k, v in a_stats.items():
97
- if k not in agent_stats:
98
- agent_stats[k] = 0
99
- agent_stats[k] += v
100
-
101
- for k, v in agent_stats.items():
102
- infos[f"agent_stats/{k}"] = float(v) / self._num_agents
103
-
70
+ self.process_episode_stats(infos)
104
71
  return obs, list(rewards), terminated.all(), truncated.all(), infos
105
72
 
106
- def process_episode_stats(self, episode_stats: Dict[str, Any]):
107
- for agent_stats in episode_stats["agent_stats"]:
108
- extra_stats = {}
109
- for stat_name in agent_stats.keys():
110
- if stat_name.startswith("action_"):
111
- extra_stats[stat_name + "_pct"] = agent_stats[stat_name] / self._grid_env.current_timestep
112
-
113
-
114
- # for object in self._game_builder.object_configs.keys():
115
- # if stat_name.startswith(f"stats_{object}_") and object != "agent":
116
- # symbol = self._game_builder._objects[object].symbol
117
- # num_obj = self._griddly_yaml["Environment"]["Levels"][0].count(symbol)
118
- # if num_obj == 0:
119
- # num_obj = 1
120
- # extra_stats[stat_name + "_pct"] = agent_stats[stat_name] / num_obj
121
-
122
- agent_stats.update(extra_stats)
123
- agent_stats.update(episode_stats["game_stats"])
124
- # agent_stats["level_max_energy"] = self._max_level_energy
125
- # agent_stats["level_max_energy_per_agent"] = self._max_level_energy_per_agent
126
- # agent_stats["level_max_reward_per_agent"] = self._max_level_reward_per_agent
73
+ def process_episode_stats(self, infos: Dict[str, Any]):
74
+ episode_rewards = self._c_env.get_episode_rewards()
75
+ episode_rewards_sum = episode_rewards.sum()
76
+ episode_rewards_mean = episode_rewards_sum / self._num_agents
77
+ infos.update({
78
+ "episode/reward.sum": episode_rewards_sum,
79
+ "episode/reward.mean": episode_rewards_mean,
80
+ "episode/reward.min": episode_rewards.min(),
81
+ "episode/reward.max": episode_rewards.max(),
82
+ "episode_length": self._c_env.current_timestep(),
83
+ })
84
+ stats = self._c_env.get_episode_stats()
85
+
86
+ infos["episode_rewards"] = episode_rewards
87
+ infos["agent_raw"] = stats["agent"]
88
+ infos["game"] = stats["game"]
89
+ infos["agent"] = {}
90
+ for agent_stats in stats["agent"]:
91
+ for n, v in agent_stats.items():
92
+ infos["agent"][n] = infos["agent"].get(n, 0) + v
93
+ for n, v in infos["agent"].items():
94
+ infos["agent"][n] = v / self._num_agents
127
95
 
128
96
  def _compute_max_energy(self):
129
97
  pass
@@ -163,9 +131,13 @@ class MettaGridEnv(pufferlib.PufferEnv):
163
131
  def player_count(self):
164
132
  return self._num_agents
165
133
 
166
- def render(self, *args, **kwargs):
134
+ def render(self):
135
+ if self._renderer is None:
136
+ return None
137
+
167
138
  return self._renderer.render(
168
- self._c_env.grid_objects(),
139
+ self._c_env.current_timestep(),
140
+ self._c_env.grid_objects()
169
141
  )
170
142
 
171
143
  @property
Binary file
mettagrid/objects.pxd CHANGED
@@ -1,5 +1,6 @@
1
1
  # distutils: language=c++
2
2
  # cython: warn.undeclared=False
3
+ # cython: c_api_binop_methods=True
3
4
 
4
5
  cimport cython
5
6
 
@@ -24,10 +25,7 @@ cdef cppclass MettaObject(GridObject):
24
25
  inline void init_mo(ObjectConfig cfg):
25
26
  this.hp = cfg[b"hp"]
26
27
 
27
- inline char usable(const Agent *actor):
28
- return False
29
-
30
- inline char attackable():
28
+ inline bint usable(const Agent *actor):
31
29
  return False
32
30
 
33
31
  cdef cppclass Usable(MettaObject):
@@ -40,7 +38,7 @@ cdef cppclass Usable(MettaObject):
40
38
  this.cooldown = cfg[b"cooldown"]
41
39
  this.ready = 1
42
40
 
43
- inline char usable(const Agent *actor):
41
+ inline bint usable(const Agent *actor):
44
42
  return this.ready and this.use_cost <= actor.energy
45
43
 
46
44
  cdef enum ObjectType:
@@ -63,22 +61,32 @@ cdef vector[string] InventoryItemNames # defined in objects.pyx
63
61
 
64
62
 
65
63
  cdef cppclass Agent(MettaObject):
66
- char frozen
67
- unsigned int energy
64
+ unsigned int frozen
65
+ unsigned int freeze_duration
66
+ unsigned char energy
68
67
  unsigned int orientation
69
- char shield
70
- vector[unsigned short] inventory
68
+ unsigned char shield
69
+ unsigned char shield_upkeep
70
+ vector[unsigned char] inventory
71
+ unsigned char max_items
72
+ unsigned char max_energy
71
73
 
72
74
  inline Agent(GridCoord r, GridCoord c, ObjectConfig cfg):
73
75
  GridObject.init(ObjectType.AgentT, GridLocation(r, c, GridLayer.Agent_Layer))
74
76
  MettaObject.init_mo(cfg)
75
- this.frozen = False
77
+ this.frozen = 0
78
+ this.freeze_duration = cfg[b"freeze_duration"]
76
79
  this.energy = cfg[b"initial_energy"]
80
+ this.max_energy = cfg[b"max_energy"]
81
+ this.shield_upkeep = cfg[b"upkeep.shield"]
77
82
  this.orientation = 0
78
83
  this.inventory.resize(InventoryItem.InventoryCount)
84
+ this.max_items = cfg[b"max_inventory"]
79
85
 
80
86
  inline void update_inventory(InventoryItem item, short amount):
81
87
  this.inventory[<InventoryItem>item] += amount
88
+ if this.inventory[<InventoryItem>item] > this.max_items:
89
+ this.inventory[<InventoryItem>item] = this.max_items
82
90
 
83
91
  inline void obs(ObsType[:] obs):
84
92
  obs[0] = 1
@@ -123,7 +131,7 @@ cdef cppclass Generator(Usable):
123
131
  Usable.init_usable(cfg)
124
132
  this.r1 = cfg[b"initial_resources"]
125
133
 
126
- inline char usable(const Agent *actor):
134
+ inline bint usable(const Agent *actor):
127
135
  return Usable.usable(actor) and this.r1 > 0
128
136
 
129
137
  inline void obs(ObsType[:] obs):
@@ -150,7 +158,7 @@ cdef cppclass Converter(Usable):
150
158
  this.output_resource = InventoryItem.r2
151
159
  this.output_energy = cfg[b"energy_output.r1"]
152
160
 
153
- inline char usable(const Agent *actor):
161
+ inline bint usable(const Agent *actor):
154
162
  return Usable.usable(actor) and actor.inventory[this.input_resource] > 0
155
163
 
156
164
  inline obs(ObsType[:] obs):
@@ -185,6 +193,9 @@ cdef map[TypeId, GridLayer] ObjectLayers
185
193
  cdef class ResetHandler(EventHandler):
186
194
  cdef inline void handle_event(self, GridObjectId obj_id, EventArg arg):
187
195
  cdef Usable *usable = <Usable*>self.env._grid.object(obj_id)
196
+ if usable is NULL:
197
+ return
198
+
188
199
  usable.ready = True
189
200
  self.env._stats.game_incr("resets." + ObjectTypeNames[usable._type_id])
190
201
 
@@ -192,6 +203,8 @@ cdef enum Events:
192
203
  Reset = 0
193
204
 
194
205
  cdef class MettaObservationEncoder(ObservationEncoder):
206
+ cdef _encode(self, GridObject *obj, ObsType[:] obs, unsigned int offset)
195
207
  cdef vector[short] _offsets
196
208
  cdef vector[string] _feature_names
209
+ cdef vector[vector[string]] _type_feature_names
197
210