mirror of
https://github.com/illiumst/marl-factory-grid.git
synced 2025-09-15 23:37:14 +02:00
Merge branch 'main' into refactor_rename
# Conflicts: # marl_factory_grid/environment/entity/entity.py # marl_factory_grid/modules/destinations/entitites.py # marl_factory_grid/modules/doors/entitites.py # marl_factory_grid/modules/items/groups.py
This commit is contained in:
@@ -2,7 +2,7 @@ from marl_factory_grid.environment.entity.mixin import BoundEntityMixin
|
||||
from marl_factory_grid.environment.entity.object import EnvObject, Object
|
||||
from marl_factory_grid.environment.entity.entity import Entity
|
||||
from marl_factory_grid.environment import constants as c
|
||||
from marl_factory_grid.utils.render import RenderEntity
|
||||
from marl_factory_grid.utils.utility_classes import RenderEntity
|
||||
|
||||
from marl_factory_grid.modules.batteries import constants as b
|
||||
|
||||
|
@@ -70,8 +70,8 @@ class PodRules(Rule):
|
||||
|
||||
def on_init(self, state, lvl_map):
|
||||
pod_collection = state[b.CHARGE_PODS]
|
||||
empty_tiles = state[c.FLOORS].empty_tiles[:self.n_pods]
|
||||
pods = pod_collection.from_coordinates(empty_tiles, entity_kwargs=dict(
|
||||
empty_positions = state.entities.empty_positions()
|
||||
pods = pod_collection.from_coordinates(empty_positions, entity_kwargs=dict(
|
||||
multi_charge=self.multi_charge, charge_rate=self.charge_rate)
|
||||
)
|
||||
pod_collection.add_items(pods)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
from numpy import random
|
||||
|
||||
from marl_factory_grid.environment.entity.entity import Entity
|
||||
from marl_factory_grid.utils.render import RenderEntity
|
||||
from marl_factory_grid.utils.utility_classes import RenderEntity
|
||||
from marl_factory_grid.modules.clean_up import constants as d
|
||||
|
||||
|
||||
|
@@ -1,6 +1,5 @@
|
||||
from marl_factory_grid.environment.groups.collection import Collection
|
||||
from marl_factory_grid.environment.groups.mixins import PositionMixin
|
||||
from marl_factory_grid.environment.entity.wall_floor import Floor
|
||||
from marl_factory_grid.modules.clean_up.entitites import DirtPile
|
||||
|
||||
from marl_factory_grid.environment import constants as c
|
||||
@@ -31,8 +30,6 @@ class DirtPiles(PositionMixin, Collection):
|
||||
self.max_local_amount = max_local_amount
|
||||
|
||||
def spawn(self, then_dirty_positions, amount) -> bool:
|
||||
# if isinstance(then_dirty_tiles, Floor):
|
||||
# then_dirty_tiles = [then_dirty_tiles]
|
||||
for pos in then_dirty_positions:
|
||||
if not self.amount > self.max_global_amount:
|
||||
if dirt := self.by_pos(pos):
|
||||
@@ -56,8 +53,8 @@ class DirtPiles(PositionMixin, Collection):
|
||||
|
||||
var = self.dirt_spawn_r_var
|
||||
new_spawn = abs(self.initial_dirt_ratio + (state.rng.uniform(-var, var) if initial_spawn else 0))
|
||||
n_dirt_tiles = max(0, int(new_spawn * len(free_for_dirt)))
|
||||
return self.spawn(free_for_dirt[:n_dirt_tiles], self.initial_amount)
|
||||
n_dirty_positions = max(0, int(new_spawn * len(free_for_dirt)))
|
||||
return self.spawn(free_for_dirt[:n_dirty_positions], self.initial_amount)
|
||||
|
||||
def __repr__(self):
|
||||
s = super(DirtPiles, self).__repr__()
|
||||
|
@@ -4,7 +4,7 @@ from marl_factory_grid.environment.entity.agent import Agent
|
||||
from marl_factory_grid.environment.entity.entity import Entity
|
||||
from marl_factory_grid.environment import constants as c
|
||||
from marl_factory_grid.environment.entity.mixin import BoundEntityMixin
|
||||
from marl_factory_grid.utils.render import RenderEntity
|
||||
from marl_factory_grid.utils.utility_classes import RenderEntity
|
||||
from marl_factory_grid.modules.destinations import constants as d
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ class Destination(Entity):
|
||||
def var_can_be_bound(self):
|
||||
return True
|
||||
|
||||
@property
|
||||
def was_reached(self):
|
||||
return self._was_reached
|
||||
|
||||
@@ -52,12 +51,10 @@ class Destination(Entity):
|
||||
self._per_agent_actions[agent.name] += 1
|
||||
return c.VALID
|
||||
|
||||
@property
|
||||
def has_just_been_reached(self):
|
||||
if self.was_reached:
|
||||
def has_just_been_reached(self, state):
|
||||
if self.was_reached():
|
||||
return False
|
||||
agent_at_position = any(
|
||||
c.AGENT.lower() in x.name.lower() for x in state.entities.pos_dict[self.pos] if x.var_can_collide)
|
||||
agent_at_position = any(state[c.AGENT].by_pos(self.pos))
|
||||
|
||||
if self.bound_entity:
|
||||
return ((agent_at_position and not self.action_counts)
|
||||
@@ -75,7 +72,7 @@ class Destination(Entity):
|
||||
return state_summary
|
||||
|
||||
def render(self):
|
||||
if self.was_reached:
|
||||
if self.was_reached():
|
||||
return None
|
||||
else:
|
||||
return RenderEntity(d.DESTINATION, self.pos)
|
||||
|
@@ -16,28 +16,29 @@ class DestinationReachAll(Rule):
|
||||
|
||||
def tick_step(self, state) -> List[TickResult]:
|
||||
results = []
|
||||
reached = False
|
||||
for dest in state[d.DESTINATION]:
|
||||
if dest.has_just_been_reached and not dest.was_reached:
|
||||
# Dest has just been reached, some agent needs to stand here, grab any first.
|
||||
if dest.has_just_been_reached(state) and not dest.was_reached():
|
||||
# Dest has just been reached, some agent needs to stand here
|
||||
for agent in state[c.AGENT].by_pos(dest.pos):
|
||||
if dest.bound_entity:
|
||||
if dest.bound_entity == agent:
|
||||
results.append(TickResult(self.name, validity=c.VALID, reward=r.DEST_REACHED, entity=agent))
|
||||
reached = True
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
results.append(TickResult(self.name, validity=c.VALID, reward=r.DEST_REACHED, entity=agent))
|
||||
state.print(f'{dest.name} is reached now, mark as reached...')
|
||||
dest.mark_as_reached()
|
||||
reached = True
|
||||
else:
|
||||
pass
|
||||
if reached:
|
||||
state.print(f'{dest.name} is reached now, mark as reached...')
|
||||
dest.mark_as_reached()
|
||||
results.append(TickResult(self.name, validity=c.VALID, reward=r.DEST_REACHED, entity=agent))
|
||||
return results
|
||||
|
||||
def tick_post_step(self, state) -> List[TickResult]:
|
||||
return []
|
||||
|
||||
def on_check_done(self, state) -> List[DoneResult]:
|
||||
if all(x.was_reached for x in state[d.DESTINATION]):
|
||||
if all(x.was_reached() for x in state[d.DESTINATION]):
|
||||
return [DoneResult(self.name, validity=c.VALID, reward=r.DEST_REACHED)]
|
||||
return [DoneResult(self.name, validity=c.NOT_VALID, reward=0)]
|
||||
|
||||
@@ -48,7 +49,7 @@ class DestinationReachAny(DestinationReachAll):
|
||||
super(DestinationReachAny, self).__init__()
|
||||
|
||||
def on_check_done(self, state) -> List[DoneResult]:
|
||||
if any(x.was_reached for x in state[d.DESTINATION]):
|
||||
if any(x.was_reached() for x in state[d.DESTINATION]):
|
||||
return [DoneResult(self.name, validity=c.VALID, reward=r.DEST_REACHED)]
|
||||
return []
|
||||
|
||||
@@ -63,7 +64,7 @@ class DestinationSpawn(Rule):
|
||||
|
||||
def on_init(self, state, lvl_map):
|
||||
# noinspection PyAttributeOutsideInit
|
||||
self.trigger_destination_spawn(self.n_dests, state)
|
||||
state[d.DESTINATION].trigger_destination_spawn(self.n_dests, state)
|
||||
pass
|
||||
|
||||
def tick_pre_step(self, state) -> List[TickResult]:
|
||||
@@ -72,24 +73,14 @@ class DestinationSpawn(Rule):
|
||||
def tick_step(self, state) -> List[TickResult]:
|
||||
if n_dest_spawn := max(0, self.n_dests - len(state[d.DESTINATION])):
|
||||
if self.spawn_mode == d.MODE_GROUPED and n_dest_spawn == self.n_dests:
|
||||
validity = self.trigger_destination_spawn(n_dest_spawn, state)
|
||||
validity = state[d.DESTINATION].trigger_destination_spawn(n_dest_spawn, state)
|
||||
return [TickResult(self.name, validity=validity, entity=None, value=n_dest_spawn)]
|
||||
elif self.spawn_mode == d.MODE_SINGLE and n_dest_spawn:
|
||||
validity = self.trigger_destination_spawn(n_dest_spawn, state)
|
||||
validity = state[d.DESTINATION].trigger_destination_spawn(n_dest_spawn, state)
|
||||
return [TickResult(self.name, validity=validity, entity=None, value=n_dest_spawn)]
|
||||
else:
|
||||
pass
|
||||
|
||||
def trigger_destination_spawn(self, n_dests, state):
|
||||
empty_positions = state[c.FLOORS].empty_tiles[:n_dests]
|
||||
if destinations := [Destination(pos) for pos in empty_positions]:
|
||||
state[d.DESTINATION].add_items(destinations)
|
||||
state.print(f'{n_dests} new destinations have been spawned')
|
||||
return c.VALID
|
||||
else:
|
||||
state.print('No Destiantions are spawning, limit is reached.')
|
||||
return c.NOT_VALID
|
||||
|
||||
|
||||
class FixedDestinationSpawn(Rule):
|
||||
def __init__(self, per_agent_positions: Dict[str, List[Tuple[int, int]]]):
|
||||
@@ -99,11 +90,17 @@ class FixedDestinationSpawn(Rule):
|
||||
def on_init(self, state, lvl_map):
|
||||
for (agent_name, position_list) in self.per_agent_positions.items():
|
||||
agent = next(x for x in state[c.AGENT] if agent_name in x.name) # Fixme: Ugly AF
|
||||
position_list = position_list.copy()
|
||||
shuffle(position_list)
|
||||
while True:
|
||||
pos = position_list.pop()
|
||||
if pos != agent.pos and not state[d.DESTINATION].by_pos(pos):
|
||||
destination = Destination(state[c.FLOORS].by_pos(pos), bind_to=agent)
|
||||
try:
|
||||
pos = position_list.pop()
|
||||
except IndexError:
|
||||
print(f"Could not spawn Destinations at: {self.per_agent_positions[agent_name]}")
|
||||
print(f'Check your agent palcement: {state[c.AGENT]} ... Exit ...')
|
||||
exit(9999)
|
||||
if (not pos == agent.pos) and (not state[d.DESTINATION].by_pos(pos)):
|
||||
destination = Destination(pos, bind_to=agent)
|
||||
break
|
||||
else:
|
||||
continue
|
||||
|
@@ -1,4 +1,4 @@
|
||||
from .actions import DoorUse
|
||||
from .entitites import Door, DoorIndicator
|
||||
from .groups import Doors
|
||||
from .rule_door_auto_close import DoorAutoClose
|
||||
from .rules import DoorAutoClose, DoorIndicateArea
|
||||
|
@@ -13,8 +13,9 @@ class DoorUse(Action):
|
||||
|
||||
def do(self, entity, state) -> Union[None, ActionResult]:
|
||||
# Check if agent really is standing on a door:
|
||||
e = state.entities.get_near_pos(entity.pos)
|
||||
e = state.entities.get_entities_near_pos(entity.pos)
|
||||
try:
|
||||
# Only one door opens TODO introcude loop
|
||||
door = next(x for x in e if x.name.startswith(d.DOOR))
|
||||
valid = door.use()
|
||||
state.print(f'{entity.name} just used a {door.name} at {door.pos}')
|
||||
|
@@ -1,5 +1,5 @@
|
||||
from marl_factory_grid.environment.entity.entity import Entity
|
||||
from marl_factory_grid.utils.render import RenderEntity
|
||||
from marl_factory_grid.utils.utility_classes import RenderEntity
|
||||
from marl_factory_grid.environment import constants as c
|
||||
|
||||
from marl_factory_grid.modules.doors import constants as d
|
||||
@@ -41,7 +41,7 @@ class Door(Entity):
|
||||
def str_state(self):
|
||||
return 'open' if self.is_open else 'closed'
|
||||
|
||||
def __init__(self, *args, closed_on_init=True, auto_close_interval=10, indicate_area=False, **kwargs):
|
||||
def __init__(self, *args, closed_on_init=True, auto_close_interval=10, **kwargs):
|
||||
self._status = d.STATE_CLOSED
|
||||
super(Door, self).__init__(*args, **kwargs)
|
||||
self.auto_close_interval = auto_close_interval
|
||||
@@ -50,8 +50,6 @@ class Door(Entity):
|
||||
self._open()
|
||||
else:
|
||||
self._close()
|
||||
if indicate_area:
|
||||
self._collection.add_items([DoorIndicator(x) for x in self.state.entities.neighboring_positions(self.pos)])
|
||||
|
||||
def summarize_state(self):
|
||||
state_dict = super().summarize_state()
|
||||
|
@@ -1,7 +1,8 @@
|
||||
from marl_factory_grid.environment.rules import Rule
|
||||
from marl_factory_grid.environment import constants as c
|
||||
from marl_factory_grid.utils.results import TickResult
|
||||
from marl_factory_grid.modules.doors import constants as d
|
||||
from . import constants as d
|
||||
from .entitites import DoorIndicator
|
||||
|
||||
|
||||
class DoorAutoClose(Rule):
|
||||
@@ -19,3 +20,13 @@ class DoorAutoClose(Rule):
|
||||
return [TickResult(self.name, validity=c.VALID, value=0)]
|
||||
state.print('There are no doors, but you loaded the corresponding Module')
|
||||
return []
|
||||
|
||||
|
||||
class DoorIndicateArea(Rule):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def on_init(self, state, lvl_map):
|
||||
for door in state[d.DOORS]:
|
||||
state[d.DOORS].add_items([DoorIndicator(x) for x in state.entities.neighboring_positions(door.pos)])
|
@@ -9,6 +9,8 @@ from marl_factory_grid.utils.results import TickResult
|
||||
class AgentSingleZonePlacementBeta(Rule):
|
||||
|
||||
def __init__(self):
|
||||
raise NotImplementedError()
|
||||
# TODO!!!! Is this concept needed any more?
|
||||
super().__init__()
|
||||
|
||||
def on_init(self, state, lvl_map):
|
||||
@@ -21,9 +23,9 @@ class AgentSingleZonePlacementBeta(Rule):
|
||||
coordinates = random.choices(self.coordinates, k=len(agents))
|
||||
else:
|
||||
raise ValueError
|
||||
tiles = [state[c.FLOORS].by_pos(pos) for pos in coordinates]
|
||||
for agent, tile in zip(agents, tiles):
|
||||
agent.move(tile, state)
|
||||
|
||||
for agent, pos in zip(agents, coordinates):
|
||||
agent.move(pos, state)
|
||||
|
||||
def tick_step(self, state):
|
||||
return []
|
||||
|
@@ -2,7 +2,7 @@ from collections import deque
|
||||
|
||||
from marl_factory_grid.environment.entity.entity import Entity
|
||||
from marl_factory_grid.environment import constants as c
|
||||
from marl_factory_grid.utils.render import RenderEntity
|
||||
from marl_factory_grid.utils.utility_classes import RenderEntity
|
||||
from marl_factory_grid.modules.items import constants as i
|
||||
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
from random import shuffle
|
||||
|
||||
from marl_factory_grid.modules.items import constants as i
|
||||
from marl_factory_grid.environment import constants as c
|
||||
|
||||
@@ -25,11 +27,12 @@ class Items(PositionMixin, Collection):
|
||||
@staticmethod
|
||||
def trigger_item_spawn(state, n_items, spawn_frequency):
|
||||
if item_to_spawns := max(0, (n_items - len(state[i.ITEM]))):
|
||||
floor_list = state.entities.floorlist[:item_to_spawns]
|
||||
state[i.ITEM].spawn(floor_list)
|
||||
state.print(
|
||||
f'{item_to_spawns} new items have been spawned; next spawn in {spawn_frequency}') # spawn in self._next_item_spawn ?
|
||||
return len(floor_list)
|
||||
position_list = [x for x in state.entities.floorlist]
|
||||
shuffle(position_list)
|
||||
position_list = state.entities.floorlist[:item_to_spawns]
|
||||
state[i.ITEM].spawn(position_list)
|
||||
state.print(f'{item_to_spawns} new items have been spawned; next spawn in {spawn_frequency}')
|
||||
return len(position_list)
|
||||
else:
|
||||
state.print('No Items are spawning, limit is reached.')
|
||||
return 0
|
||||
@@ -116,7 +119,7 @@ class DropOffLocations(PositionMixin, Collection):
|
||||
|
||||
@staticmethod
|
||||
def trigger_drop_off_location_spawn(state, n_locations):
|
||||
empty_tiles = state.entities.floorlist[:n_locations]
|
||||
empty_positions = state.entities.empty_positions()[:n_locations]
|
||||
do_entites = state[i.DROP_OFF]
|
||||
drop_offs = [DropOffLocation(tile) for tile in empty_tiles]
|
||||
drop_offs = [DropOffLocation(pos) for pos in empty_positions]
|
||||
do_entites.add_items(drop_offs)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
from marl_factory_grid.environment.entity.entity import Entity
|
||||
from marl_factory_grid.utils.render import RenderEntity
|
||||
from ...utils.utility_classes import RenderEntity
|
||||
from marl_factory_grid.environment import constants as c
|
||||
from marl_factory_grid.utils.results import TickResult
|
||||
|
||||
|
@@ -13,8 +13,8 @@ class MachineRule(Rule):
|
||||
self.n_machines = n_machines
|
||||
|
||||
def on_init(self, state, lvl_map):
|
||||
empty_tiles = state[c.FLOORS].empty_tiles[:self.n_machines]
|
||||
state[m.MACHINES].add_items(Machine(tile) for tile in empty_tiles)
|
||||
# TODO Move to spawn!!!
|
||||
state[m.MACHINES].add_items(Machine(pos) for pos in state.entities.empty_positions())
|
||||
|
||||
def tick_pre_step(self, state) -> List[TickResult]:
|
||||
pass
|
||||
|
@@ -8,7 +8,7 @@ from ...environment.entity.entity import Entity
|
||||
from ..doors import constants as do
|
||||
from ..maintenance import constants as mi
|
||||
from ...utils.helpers import MOVEMAP
|
||||
from ...utils.render import RenderEntity
|
||||
from ...utils.utility_classes import RenderEntity
|
||||
from ...utils.states import Gamestate
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class Maintainer(Entity):
|
||||
self._next = []
|
||||
self._last = []
|
||||
self._last_serviced = 'None'
|
||||
self._floortile_graph = points_to_graph(state[c.FLOORS].positions)
|
||||
self._floortile_graph = points_to_graph(state.entities.floorlist)
|
||||
|
||||
def tick(self, state):
|
||||
if found_objective := state[self.objective].by_pos(self.pos):
|
||||
|
@@ -14,7 +14,8 @@ class MaintenanceRule(Rule):
|
||||
self.n_maintainer = n_maintainer
|
||||
|
||||
def on_init(self, state: Gamestate, lvl_map):
|
||||
state[M.MAINTAINERS].spawn(state[c.FLOORS].empty_tiles[:self.n_maintainer], state)
|
||||
# Move to spawn? : #TODO
|
||||
state[M.MAINTAINERS].spawn(state.entities.empty_positions[:self.n_maintainer], state)
|
||||
pass
|
||||
|
||||
def tick_pre_step(self, state) -> List[TickResult]:
|
||||
|
@@ -3,8 +3,7 @@ from typing import List, Tuple
|
||||
|
||||
from marl_factory_grid.environment.entity.entity import Entity
|
||||
from marl_factory_grid.environment.entity.object import Object
|
||||
from marl_factory_grid.environment.entity.wall_floor import Floor
|
||||
from marl_factory_grid.utils.render import RenderEntity
|
||||
from marl_factory_grid.utils.utility_classes import RenderEntity
|
||||
from marl_factory_grid.environment import constants as c
|
||||
|
||||
from marl_factory_grid.modules.doors import constants as d
|
||||
@@ -21,5 +20,5 @@ class Zone(Object):
|
||||
self.coords = coords
|
||||
|
||||
@property
|
||||
def random_tile(self):
|
||||
def random_pos(self):
|
||||
return random.choice(self.coords)
|
||||
|
@@ -19,7 +19,7 @@ class ZoneInit(Rule):
|
||||
while z_idx:
|
||||
zone_positions = lvl_map.get_coordinates_for_symbol(z_idx)
|
||||
if len(zone_positions):
|
||||
zones.append(Zone([state[c.FLOORS].by_pos(pos) for pos in zone_positions]))
|
||||
zones.append(Zone(zone_positions))
|
||||
z_idx += 1
|
||||
else:
|
||||
z_idx = 0
|
||||
@@ -38,7 +38,7 @@ class AgentSingleZonePlacement(Rule):
|
||||
|
||||
z_idxs = choices(list(range(len(state[z.ZONES]))), k=n_agents)
|
||||
for agent in state[c.AGENT]:
|
||||
agent.move(state[z.ZONES][z_idxs.pop()].random_tile, state)
|
||||
agent.move(state[z.ZONES][z_idxs.pop()].random_pos, state)
|
||||
return []
|
||||
|
||||
def tick_step(self, state):
|
||||
@@ -65,10 +65,10 @@ class IndividualDestinationZonePlacement(Rule):
|
||||
other_zones = [x for x in state[z.ZONES] if x not in agent_zones]
|
||||
already_has_destination = True
|
||||
while already_has_destination:
|
||||
tile = choice(other_zones).random_tile
|
||||
if state[d.DESTINATION].by_pos(tile.pos) is None:
|
||||
pos = choice(other_zones).random_pos
|
||||
if state[d.DESTINATION].by_pos(pos) is None:
|
||||
already_has_destination = False
|
||||
destination = Destination(tile, bind_to=agent)
|
||||
destination = Destination(pos, bind_to=agent)
|
||||
|
||||
state[d.DESTINATION].add_item(destination)
|
||||
continue
|
||||
|
Reference in New Issue
Block a user