mettagrid 0.0.1__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.

Potentially problematic release.


This version of mettagrid might be problematic. Click here for more details.

mettagrid/__init__.py ADDED
File without changes
File without changes
@@ -0,0 +1,31 @@
1
+
2
+ from libc.stdio cimport printf
3
+ from libcpp.string cimport string
4
+ from libcpp.map cimport map
5
+
6
+ from puffergrid.grid_object cimport TypeId, GridObjectId
7
+ from puffergrid.action cimport ActionHandler, ActionArg
8
+ from mettagrid.objects cimport Agent
9
+
10
+ cdef struct StatNames:
11
+ string action
12
+ string action_energy
13
+ map[TypeId, string] target
14
+ map[TypeId, string] target_energy
15
+
16
+ cdef class MettaActionHandler(ActionHandler):
17
+ cdef StatNames _stats
18
+ cdef string action_name
19
+ cdef int action_cost
20
+
21
+ cdef char handle_action(
22
+ self,
23
+ unsigned int actor_id,
24
+ GridObjectId actor_object_id,
25
+ ActionArg arg)
26
+
27
+ cdef char _handle_action(
28
+ self,
29
+ unsigned int actor_id,
30
+ Agent * actor,
31
+ ActionArg arg)
@@ -0,0 +1,59 @@
1
+
2
+ from libc.stdio cimport printf
3
+
4
+ from omegaconf import OmegaConf
5
+
6
+ from puffergrid.grid_object cimport GridObjectId
7
+ from puffergrid.action cimport ActionHandler, ActionArg
8
+ from mettagrid.objects cimport Agent, ObjectTypeNames
9
+
10
+ cdef extern from "<string>" namespace "std":
11
+ string to_string(int val)
12
+
13
+ cdef class MettaActionHandler(ActionHandler):
14
+ def __init__(self, cfg: OmegaConf, action_name, action_cost=0):
15
+ self.action_name = action_name
16
+
17
+ self._stats.action = "action." + action_name
18
+ self._stats.action_energy = "action." + action_name + ".energy"
19
+
20
+ for t, n in enumerate(ObjectTypeNames):
21
+ self._stats.target[t] = self._stats.action + "." + n
22
+ self._stats.target_energy[t] = self._stats.action_energy + "." + n
23
+
24
+ self.action_cost = cfg.cost
25
+
26
+ cdef char handle_action(
27
+ self,
28
+ unsigned int actor_id,
29
+ GridObjectId actor_object_id,
30
+ ActionArg arg):
31
+
32
+ cdef Agent *actor = <Agent*>self.env._grid.object(actor_object_id)
33
+
34
+ if actor.frozen:
35
+ return False
36
+
37
+ if actor.energy < self.action_cost:
38
+ return False
39
+
40
+ actor.energy -= self.action_cost
41
+ self.env._stats.agent_add(actor_id, self._stats.action_energy.c_str(), self.action_cost)
42
+
43
+ cdef char result = self._handle_action(actor_id, actor, arg)
44
+
45
+ if result:
46
+ self.env._stats.agent_incr(actor_id, self._stats.action.c_str())
47
+
48
+ return result
49
+
50
+ cdef char _handle_action(
51
+ self,
52
+ unsigned int actor_id,
53
+ Agent * actor,
54
+ ActionArg arg):
55
+ return False
56
+
57
+
58
+
59
+
@@ -0,0 +1,6 @@
1
+ from mettagrid.actions.actions cimport MettaActionHandler
2
+
3
+ cdef class Attack(MettaActionHandler):
4
+ cdef public int damage
5
+
6
+ pass
@@ -0,0 +1,61 @@
1
+
2
+ from libc.stdio cimport printf
3
+ from omegaconf import OmegaConf
4
+
5
+ from puffergrid.grid_object cimport GridLocation, GridObjectId, Orientation, GridObject
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 Attack(MettaActionHandler):
12
+ def __init__(self, cfg: OmegaConf):
13
+ MettaActionHandler.__init__(self, cfg, "attack")
14
+
15
+ cdef char _handle_action(
16
+ self,
17
+ unsigned int actor_id,
18
+ Agent * actor,
19
+ ActionArg arg):
20
+
21
+ if arg > 9 or arg < 1:
22
+ return False
23
+
24
+ cdef short distance = 0
25
+ cdef short offset = 0
26
+ distance = 1 + (arg - 1) // 3
27
+ offset = (arg - 1) % 3 - 1
28
+
29
+ cdef GridLocation target_loc = self.env._grid.relative_location(
30
+ actor.location,
31
+ <Orientation>actor.orientation,
32
+ distance, offset)
33
+
34
+ target_loc.layer = GridLayer.Agent_Layer
35
+ cdef Agent * agent_target = <Agent *>self.env._grid.object_at(target_loc)
36
+ if agent_target:
37
+ self.env._stats.agent_incr(actor_id, self._stats.target[agent_target._type_id].c_str())
38
+ if agent_target.shield and agent_target.energy >= self.damage:
39
+ agent_target.energy -= self.damage
40
+ self.env._stats.agent_add(actor_id, "shield_damage", self.damage)
41
+ else:
42
+ self.env._stats.agent_add(actor_id, "shield_damage", agent_target.energy)
43
+ agent_target.energy = 0
44
+ agent_target.shield = False
45
+ agent_target.frozen = True
46
+ self.env._stats.agent_incr(actor_id, "attack.frozen")
47
+ return True
48
+
49
+ target_loc.layer = GridLayer.Object_Layer
50
+ cdef MettaObject * object_target = <MettaObject *>self.env._grid.object_at(target_loc)
51
+ if object_target:
52
+ self.env._stats.agent_incr(actor_id, self._stats.target[object_target._type_id].c_str())
53
+ object_target.hp -= 1
54
+ self.env._stats.agent_incr(actor_id, "damage." + ObjectTypeNames[object_target._type_id])
55
+ if object_target.hp <= 0:
56
+ self.env._grid.remove_object(object_target)
57
+ self.env._stats.agent_incr(actor_id, "destroyed." + ObjectTypeNames[object_target._type_id])
58
+
59
+ return True
60
+
61
+ return False
@@ -0,0 +1,4 @@
1
+ from mettagrid.actions.actions cimport MettaActionHandler
2
+
3
+ cdef class Gift(MettaActionHandler):
4
+ pass
@@ -0,0 +1,24 @@
1
+
2
+ from libc.stdio cimport printf
3
+ from omegaconf import OmegaConf
4
+
5
+ from puffergrid.grid_object cimport GridLocation, GridObjectId, Orientation, GridObject
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
+
12
+ cdef class Gift(MettaActionHandler):
13
+ def __init__(self, cfg: OmegaConf):
14
+ MettaActionHandler.__init__(self, cfg, "gift")
15
+
16
+ cdef char _handle_action(
17
+ self,
18
+ unsigned int actor_id,
19
+ Agent * actor,
20
+ ActionArg arg):
21
+ return False
22
+
23
+
24
+
@@ -0,0 +1,4 @@
1
+ from mettagrid.actions.actions cimport MettaActionHandler
2
+
3
+ cdef class Move(MettaActionHandler):
4
+ pass
@@ -0,0 +1,31 @@
1
+
2
+ from libc.stdio cimport printf
3
+
4
+ from omegaconf import OmegaConf
5
+
6
+ from puffergrid.grid_object cimport GridLocation, GridObjectId, GridObject, Orientation
7
+ from puffergrid.action cimport ActionHandler, ActionArg
8
+ from mettagrid.objects cimport MettaObject, ObjectType, Usable, Altar, Agent, Events, GridLayer
9
+ from mettagrid.objects cimport Generator, Converter, InventoryItem, ObjectTypeNames, InventoryItemNames
10
+ from mettagrid.actions.actions cimport MettaActionHandler
11
+
12
+ cdef class Move(MettaActionHandler):
13
+ def __init__(self, cfg: OmegaConf):
14
+ MettaActionHandler.__init__(self, cfg, "move")
15
+
16
+ cdef char _handle_action(
17
+ self,
18
+ unsigned int actor_id,
19
+ Agent * actor,
20
+ ActionArg arg):
21
+
22
+ cdef unsigned short direction = arg
23
+ if direction >= 2:
24
+ return False
25
+
26
+ cdef Orientation orientation = <Orientation>((actor.orientation + 2*(direction)) % 4)
27
+ cdef GridLocation old_loc = actor.location
28
+ cdef GridLocation new_loc = self.env._grid.relative_location(old_loc, orientation)
29
+ if not self.env._grid.is_empty(new_loc.r, new_loc.c):
30
+ return False
31
+ 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 Rotate(MettaActionHandler):
4
+ pass
@@ -0,0 +1,28 @@
1
+
2
+ from libc.stdio cimport printf
3
+
4
+ from omegaconf import OmegaConf
5
+
6
+ from puffergrid.grid_object cimport GridLocation, GridObjectId, Orientation, GridObject
7
+ from puffergrid.action cimport ActionHandler, ActionArg
8
+ from mettagrid.objects cimport MettaObject, ObjectType, Usable, Altar, Agent, Events, GridLayer
9
+ from mettagrid.objects cimport Generator, Converter, InventoryItem, ObjectTypeNames, InventoryItemNames
10
+ from mettagrid.actions.actions cimport MettaActionHandler
11
+
12
+
13
+ cdef class Rotate(MettaActionHandler):
14
+ def __init__(self, cfg: OmegaConf):
15
+ MettaActionHandler.__init__(self, cfg, "rotate")
16
+
17
+ cdef char _handle_action(
18
+ self,
19
+ unsigned int actor_id,
20
+ Agent * actor,
21
+ ActionArg arg):
22
+
23
+ cdef unsigned short orientation = arg
24
+ if orientation >= 4:
25
+ return False
26
+
27
+ actor.orientation = orientation
28
+ return True
@@ -0,0 +1,4 @@
1
+ from mettagrid.actions.actions cimport MettaActionHandler
2
+
3
+ cdef class Shield(MettaActionHandler):
4
+ pass
@@ -0,0 +1,26 @@
1
+
2
+ from libc.stdio cimport printf
3
+
4
+ from omegaconf import OmegaConf
5
+
6
+ from puffergrid.grid_object cimport GridLocation, GridObjectId, Orientation, GridObject
7
+ from puffergrid.action cimport ActionHandler, ActionArg
8
+ from mettagrid.objects cimport MettaObject, ObjectType, Usable, Altar, Agent, Events, GridLayer
9
+ from mettagrid.objects cimport Generator, Converter, InventoryItem, ObjectTypeNames, InventoryItemNames
10
+ from mettagrid.actions.actions cimport MettaActionHandler
11
+
12
+ cdef class Shield(MettaActionHandler):
13
+ def __init__(self, cfg: OmegaConf):
14
+ MettaActionHandler.__init__(self, cfg, "shield")
15
+
16
+ cdef char _handle_action(
17
+ self,
18
+ unsigned int actor_id,
19
+ Agent * actor,
20
+ ActionArg arg):
21
+
22
+ if actor.shield:
23
+ actor.shield = True
24
+ else:
25
+ actor.shield = False
26
+
@@ -0,0 +1,4 @@
1
+ from mettagrid.actions.actions cimport MettaActionHandler
2
+
3
+ cdef class Use(MettaActionHandler):
4
+ pass
@@ -0,0 +1,66 @@
1
+
2
+ from libc.stdio cimport printf
3
+
4
+ from omegaconf import OmegaConf
5
+
6
+ from puffergrid.grid_object cimport GridLocation, GridObjectId, Orientation, GridObject
7
+ from puffergrid.action cimport ActionHandler, ActionArg
8
+ from mettagrid.objects cimport MettaObject, ObjectType, Usable, Altar, Agent, Events, GridLayer
9
+ from mettagrid.objects cimport Generator, Converter, InventoryItem, ObjectTypeNames, InventoryItemNames
10
+ from mettagrid.actions.actions cimport MettaActionHandler
11
+
12
+ cdef class Use(MettaActionHandler):
13
+ def __init__(self, cfg: OmegaConf):
14
+ MettaActionHandler.__init__(self, cfg, "use")
15
+
16
+ cdef char _handle_action(
17
+ self,
18
+ unsigned int actor_id,
19
+ Agent * actor,
20
+ ActionArg arg):
21
+
22
+ cdef GridLocation target_loc = self.env._grid.relative_location(
23
+ actor.location,
24
+ <Orientation>actor.orientation
25
+ )
26
+ target_loc.layer = GridLayer.Object_Layer
27
+ cdef MettaObject *target = <MettaObject*>self.env._grid.object_at(target_loc)
28
+ if target == NULL:
29
+ return False
30
+
31
+ if not target.usable(actor):
32
+ return False
33
+
34
+ cdef Usable *usable = <Usable*> target
35
+ actor.energy -= usable.use_cost
36
+
37
+ usable.ready = 0
38
+ self.env._event_manager.schedule_event(Events.Reset, usable.cooldown, usable.id, 0)
39
+
40
+ self.env._stats.agent_incr(actor_id, self._stats.target[target._type_id].c_str())
41
+ self.env._stats.agent_add(actor_id, self._stats.target_energy[target._type_id].c_str(), usable.use_cost + self.action_cost)
42
+
43
+ if target._type_id == ObjectType.AltarT:
44
+ self.env._rewards[actor_id] += 1
45
+
46
+ cdef Generator *generator
47
+ if target._type_id == ObjectType.GeneratorT:
48
+ generator = <Generator*>target
49
+ generator.r1 -= 1
50
+ actor.update_inventory(InventoryItem.r1, 1)
51
+ self.env._stats.agent_incr(actor_id, "r1.gained")
52
+ self.env._stats.game_incr("r1.harvested")
53
+
54
+ cdef Converter *converter
55
+ if target._type_id == ObjectType.ConverterT:
56
+ converter = <Converter*>target
57
+ actor.update_inventory(converter.input_resource, -1)
58
+ self.env._stats.agent_incr(actor_id, InventoryItemNames[converter.input_resource] + ".used")
59
+
60
+ actor.update_inventory(converter.output_resource, 1)
61
+ self.env._stats.agent_incr(actor_id, InventoryItemNames[converter.input_resource] + ".gained")
62
+
63
+ actor.energy += converter.output_energy
64
+ self.env._stats.agent_add(actor_id, "energy.gained", converter.output_energy)
65
+
66
+ return True
@@ -0,0 +1,101 @@
1
+ from typing import Dict, List
2
+ import numpy as np
3
+ import yaml
4
+ from omegaconf import OmegaConf
5
+
6
+ class NoAliasDumper(yaml.Dumper):
7
+ def ignore_aliases(self, data):
8
+ return True
9
+
10
+ class MettaGridGameBuilder():
11
+ def __init__(
12
+ self,
13
+ obs_width: int,
14
+ obs_height: int,
15
+ tile_size: int,
16
+ max_steps: int,
17
+ num_agents: int,
18
+ no_energy_steps: int,
19
+ objects,
20
+ actions,
21
+ map):
22
+
23
+ self.obs_width = obs_width
24
+ self.obs_height = obs_height
25
+ self.tile_size = tile_size
26
+ self.num_agents = num_agents
27
+ self.max_steps = max_steps
28
+
29
+ self._symbols = {
30
+ "agent": "A",
31
+ "altar": "a",
32
+ "converter": "c",
33
+ "generator": "g",
34
+ "wall": "w",
35
+ "empty": " ",
36
+ }
37
+
38
+ self.no_energy_steps = no_energy_steps
39
+ objects = OmegaConf.create(objects)
40
+ self.object_configs = objects
41
+ actions = OmegaConf.create(actions)
42
+ self.action_configs = actions
43
+ self.map_config = OmegaConf.create(map)
44
+
45
+
46
+ def level(self):
47
+ layout = self.map_config.layout
48
+
49
+ if "rooms" in layout:
50
+ return self.build_map(layout.rooms)
51
+ else:
52
+ return self.build_map(
53
+ [["room"] * layout.rooms_x] * layout.rooms_y)
54
+
55
+ def build_map(self, rooms):
56
+ num_agents = 0
57
+ layers = []
58
+ for layer in rooms:
59
+ rooms = []
60
+ for room_name in layer:
61
+ room_config = self.map_config[room_name]
62
+ rooms.append(self.build_room(room_config, num_agents + 1))
63
+ num_agents += room_config.objects.agent
64
+ layers.append(np.concatenate(rooms, axis=1))
65
+ level = np.concatenate(layers, axis=0)
66
+ assert num_agents == self.num_agents, f"Number of agents in map ({num_agents}) does not match num_agents ({self.num_agents})"
67
+
68
+ footer = np.full((1, level.shape[1]), "W", dtype="U6")
69
+ footer[0, 0] = "q"
70
+
71
+ level = np.concatenate([level, footer], axis=0)
72
+ return level
73
+
74
+ def build_room(self, room_config, starting_agent=1):
75
+ symbols = []
76
+ content_width = room_config.width - 2*room_config.border
77
+ content_height = room_config.height - 2*room_config.border
78
+ area = content_width * content_height
79
+
80
+ for obj_name, count in room_config.objects.items():
81
+ symbol = self._symbols[obj_name]
82
+ if obj_name == "agent":
83
+ symbols.extend([f"{symbol}{i+starting_agent}" for i in range(count)])
84
+ else:
85
+ symbols.extend([symbol] * count)
86
+
87
+ assert(len(symbols) <= area), f"Too many objects in room: {len(symbols)} > {area}"
88
+ symbols.extend(["."] * (area - len(symbols)))
89
+ symbols = np.array(symbols).astype("U8")
90
+ np.random.shuffle(symbols)
91
+ content = symbols.reshape(content_height, content_width)
92
+ room = np.full((room_config.height, room_config.width), "W", dtype="U6")
93
+ room[room_config.border:room_config.border+content_height,
94
+ room_config.border:room_config.border+content_width] = content
95
+
96
+ return room
97
+
98
+ def termination_conditions(self):
99
+ return {
100
+ "Win": [ {"lt": ["game:max_steps", "game:step"]} ],
101
+ }
@@ -0,0 +1,27 @@
1
+
2
+
3
+ import numpy as np
4
+ from omegaconf import DictConfig, ListConfig
5
+
6
+
7
+ def sample_config(value):
8
+ if isinstance(value, int):
9
+ return value
10
+ if isinstance(value, float):
11
+ return value
12
+ if isinstance(value, DictConfig):
13
+ return {
14
+ key: sample_config(value)
15
+ for key, value in value.items()
16
+ }
17
+ if isinstance(value, ListConfig):
18
+ if len(value) == 0:
19
+ return value
20
+ if isinstance(value[0], int):
21
+ assert len(value) == 2, f"Found a list with length != 2 {value}"
22
+ return np.random.randint(value[0], value[1])
23
+ if isinstance(value[0], float):
24
+ assert len(value) == 2, f"Found a list with length != 2 {value}"
25
+ return np.random.uniform(value[0], value[1])
26
+ return value
27
+ return value
@@ -0,0 +1,78 @@
1
+
2
+ from libc.stdio cimport printf
3
+
4
+ import numpy as np
5
+ import gymnasium as gym
6
+ from omegaconf import OmegaConf
7
+
8
+ from puffergrid.grid_env cimport GridEnv
9
+
10
+ from mettagrid.objects cimport ObjectLayers, Agent, ResetHandler, Wall, Generator, Converter, Altar
11
+ from mettagrid.objects cimport MettaObservationEncoder
12
+ from mettagrid.actions.move import Move
13
+ from mettagrid.actions.rotate import Rotate
14
+ from mettagrid.actions.use import Use
15
+ from mettagrid.actions.attack import Attack
16
+ from mettagrid.actions.shield import Shield
17
+ from mettagrid.actions.gift import Gift
18
+
19
+ cdef class MettaGrid(GridEnv):
20
+ cdef:
21
+ object _cfg
22
+
23
+ def __init__(self, cfg: OmegaConf, map: np.ndarray):
24
+ self._cfg = cfg
25
+
26
+ GridEnv.__init__(
27
+ self,
28
+ cfg.num_agents,
29
+ map.shape[1],
30
+ map.shape[0],
31
+ cfg.max_steps,
32
+ dict(ObjectLayers).values(),
33
+ cfg.obs_width, cfg.obs_height,
34
+ MettaObservationEncoder(),
35
+ [
36
+ Move(cfg.actions.move),
37
+ Rotate(cfg.actions.rotate),
38
+ Use(cfg.actions.use),
39
+ Attack(cfg.actions.attack),
40
+ Shield(cfg.actions.shield),
41
+ Gift(cfg.actions.gift),
42
+ ],
43
+ [
44
+ ResetHandler()
45
+ ]
46
+ )
47
+
48
+
49
+ cdef Agent *agent
50
+ for r in range(map.shape[0]):
51
+ for c in range(map.shape[1]):
52
+ if map[r,c] == "W":
53
+ self._grid.add_object(new Wall(r, c, cfg.objects.wall))
54
+ self._stats.game_incr("objects.wall")
55
+ elif map[r,c] == "g":
56
+ self._grid.add_object(new Generator(r, c, cfg.objects.generator))
57
+ self._stats.game_incr("objects.generator")
58
+ elif map[r,c] == "c":
59
+ self._grid.add_object(new Converter(r, c, cfg.objects.converter))
60
+ self._stats.game_incr("objects.converter")
61
+ elif map[r,c] == "a":
62
+ self._grid.add_object(new Altar(r, c, cfg.objects.altar))
63
+ self._stats.game_incr("objects.altar")
64
+ elif map[r,c][0] == "A":
65
+ agent = new Agent(r, c, cfg.objects.agent)
66
+ self._grid.add_object(agent)
67
+ self.add_agent(agent)
68
+ self._stats.game_incr("objects.agent")
69
+
70
+
71
+ def render(self):
72
+ grid = self.render_ascii(["A", "#", "g", "c", "a"])
73
+ for r in grid:
74
+ print("".join(r))
75
+
76
+ @property
77
+ def action_space(self):
78
+ return gym.spaces.MultiDiscrete((self.num_actions(), 10), dtype=np.uint32)