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:
Chanumask
2023-10-20 15:39:01 +02:00
41 changed files with 267 additions and 215 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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__()

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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}')

View File

@@ -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()

View File

@@ -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)])

View File

@@ -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 []

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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):

View File

@@ -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]:

View File

@@ -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)

View File

@@ -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