new rules, new spawn logic, small fixes, default and narrow corridor debugged

This commit is contained in:
Steffen Illium
2023-11-09 17:50:20 +01:00
parent 9b9c6e0385
commit 06a5130b25
67 changed files with 768 additions and 921 deletions

View File

@ -1,10 +1,15 @@
from marl_factory_grid.environment.entity.agent import Agent
from marl_factory_grid.environment.groups.collection import Collection
from marl_factory_grid.environment.rules import SpawnAgents
class Agents(Collection):
_entity = Agent
@property
def spawn_rule(self):
return {SpawnAgents.__name__: {}}
@property
def var_is_blocking_light(self):
return False

View File

@ -1,18 +1,25 @@
from typing import List, Tuple, Union
from typing import List, Tuple, Union, Dict
from marl_factory_grid.environment.entity.entity import Entity
from marl_factory_grid.environment.groups.objects import _Objects
# noinspection PyProtectedMember
from marl_factory_grid.environment.entity.object import _Object
import marl_factory_grid.environment.constants as c
from marl_factory_grid.utils.results import Result
class Collection(_Objects):
_entity = _Object # entity?
symbol = None
@property
def var_is_blocking_light(self):
return False
@property
def var_is_blocking_pos(self):
return False
@property
def var_can_collide(self):
return False
@ -23,29 +30,61 @@ class Collection(_Objects):
@property
def var_has_position(self):
return False
# @property
# def var_has_bound(self):
# return False # batteries, globalpos, inventories true
@property
def var_can_be_bound(self):
return False
return True
@property
def encodings(self):
return [x.encoding for x in self]
def __init__(self, size, *args, **kwargs):
super(Collection, self).__init__(*args, **kwargs)
self.size = size
def spawn(self, coords_or_quantity: Union[int, List[Tuple[(int, int)]]], *entity_args): # woihn mit den args
if isinstance(coords_or_quantity, int):
self.add_items([self._entity() for _ in range(coords_or_quantity)])
@property
def spawn_rule(self):
"""Prevent SpawnRule creation if Objects are spawned by map, Doors e.g."""
if self.symbol:
return None
elif self._spawnrule:
return self._spawnrule
else:
self.add_items([self._entity(pos) for pos in coords_or_quantity])
return {c.SPAWN_ENTITY_RULE: dict(collection=self, coords_or_quantity=self._coords_or_quantity)}
def __init__(self, size, *args, coords_or_quantity: int = None, ignore_blocking=False,
spawnrule: Union[None, Dict[str, dict]] = None,
**kwargs):
super(Collection, self).__init__(*args, **kwargs)
self._coords_or_quantity = coords_or_quantity
self.size = size
self._spawnrule = spawnrule
self._ignore_blocking = ignore_blocking
def trigger_spawn(self, state, *entity_args, coords_or_quantity=None, ignore_blocking=False, **entity_kwargs):
coords_or_quantity = coords_or_quantity if coords_or_quantity else self._coords_or_quantity
if self.var_has_position:
if isinstance(coords_or_quantity, int):
if ignore_blocking or self._ignore_blocking:
coords_or_quantity = state.entities.floorlist[:coords_or_quantity]
else:
coords_or_quantity = state.get_n_random_free_positions(coords_or_quantity)
self.spawn(coords_or_quantity, *entity_args, **entity_kwargs)
state.print(f'{len(coords_or_quantity)} new {self.name} have been spawned at {coords_or_quantity}')
return Result(identifier=f'{self.name}_spawn', validity=c.VALID, value=len(coords_or_quantity))
else:
if isinstance(coords_or_quantity, int):
self.spawn(coords_or_quantity, *entity_args, **entity_kwargs)
state.print(f'{coords_or_quantity} new {self.name} have been spawned randomly.')
return Result(identifier=f'{self.name}_spawn', validity=c.VALID, value=coords_or_quantity)
else:
raise ValueError(f'{self._entity.__name__} has no position!')
def spawn(self, coords_or_quantity: Union[int, List[Tuple[(int, int)]]], *entity_args, **entity_kwargs):
if self.var_has_position:
if isinstance(coords_or_quantity, int):
raise ValueError(f'{self._entity.__name__} should have a position!')
else:
self.add_items([self._entity(pos, *entity_args, **entity_kwargs) for pos in coords_or_quantity])
else:
if isinstance(coords_or_quantity, int):
self.add_items([self._entity(*entity_args, **entity_kwargs) for _ in range(coords_or_quantity)])
else:
raise ValueError(f'{self._entity.__name__} has no position!')
return c.VALID
def despawn(self, items: List[_Object]):
@ -115,7 +154,7 @@ class Collection(_Objects):
except StopIteration:
pass
except ValueError:
print()
pass
@property
def positions(self):

View File

@ -1,6 +1,6 @@
from collections import defaultdict
from operator import itemgetter
from random import shuffle, random
from random import shuffle
from typing import Dict
from marl_factory_grid.environment.groups.objects import _Objects
@ -12,10 +12,10 @@ class Entities(_Objects):
@staticmethod
def neighboring_positions(pos):
return (POS_MASK + pos).reshape(-1, 2)
return [tuple(x) for x in (POS_MASK + pos).reshape(-1, 2)]
def get_entities_near_pos(self, pos):
return [y for x in itemgetter(*(tuple(x) for x in self.neighboring_positions(pos)))(self.pos_dict) for y in x]
return [y for x in itemgetter(*self.neighboring_positions(pos))(self.pos_dict) for y in x]
def render(self):
return [y for x in self for y in x.render() if x is not None]
@ -35,8 +35,9 @@ class Entities(_Objects):
super().__init__()
def guests_that_can_collide(self, pos):
return[x for val in self.pos_dict[pos] for x in val if x.var_can_collide]
return [x for val in self.pos_dict[pos] for x in val if x.var_can_collide]
@property
def empty_positions(self):
empty_positions = [key for key in self.floorlist if not self.pos_dict[key]]
shuffle(empty_positions)
@ -48,11 +49,23 @@ class Entities(_Objects):
shuffle(empty_positions)
return empty_positions
def is_blocked(self):
return[key for key, val in self.pos_dict.items() if any([x.var_is_blocking_pos for x in val])]
@property
def blocked_positions(self):
blocked_positions = [key for key, val in self.pos_dict.items() if any([x.var_is_blocking_pos for x in val])]
shuffle(blocked_positions)
return blocked_positions
def is_not_blocked(self):
return[key for key, val in self.pos_dict.items() if not all([x.var_is_blocking_pos for x in val])]
@property
def free_positions_generator(self):
generator = (
key for key in self.floorlist if all(not x.var_can_collide and not x.var_is_blocking_pos
for x in self.pos_dict[key])
)
return generator
@property
def free_positions_list(self):
return [x for x in self.free_positions_generator]
def iter_entities(self):
return iter((x for sublist in self.values() for x in sublist))
@ -92,3 +105,6 @@ class Entities(_Objects):
@property
def positions(self):
return [k for k, v in self.pos_dict.items() for _ in v]
def is_occupied(self, pos):
return len([x for x in self.pos_dict[pos] if x.var_can_collide or x.var_is_blocking_pos]) >= 1

View File

@ -4,10 +4,6 @@ from marl_factory_grid.environment import constants as c
# noinspection PyUnresolvedReferences,PyTypeChecker
class IsBoundMixin:
@property
def name(self):
return f'{self.__class__.__name__}({self._bound_entity.name})'
def __repr__(self):
return f'{self.__class__.__name__}#{self._bound_entity.name}({self._data})'

View File

@ -5,11 +5,16 @@ import numpy as np
from marl_factory_grid.environment.entity.object import _Object
import marl_factory_grid.environment.constants as c
from marl_factory_grid.utils import helpers as h
class _Objects:
_entity = _Object
@property
def var_can_be_bound(self):
return False
@property
def observers(self):
return self._observers
@ -148,12 +153,12 @@ class _Objects:
def by_entity(self, entity):
try:
return next((x for x in self if x.belongs_to_entity(entity)))
return h.get_first(self, filter_by=lambda x: x.belongs_to_entity(entity))
except (StopIteration, AttributeError):
return None
def idx_by_entity(self, entity):
try:
return next((idx for idx, x in enumerate(self) if x.belongs_to_entity(entity)))
return h.get_first_index(self, filter_by=lambda x: x.belongs_to_entity(entity))
except (StopIteration, AttributeError):
return None

View File

@ -1,7 +1,10 @@
from typing import List, Union
from marl_factory_grid.environment import constants as c
from marl_factory_grid.environment.entity.util import GlobalPosition
from marl_factory_grid.environment.groups.collection import Collection
from marl_factory_grid.utils.results import Result
from marl_factory_grid.utils.states import Gamestate
class Combined(Collection):
@ -36,17 +39,17 @@ class GlobalPositions(Collection):
_entity = GlobalPosition
@property
def var_is_blocking_light(self):
return False
@property
def var_can_collide(self):
return False
@property
def var_can_be_bound(self):
return True
var_is_blocking_light = False
var_can_be_bound = True
var_can_collide = False
var_has_position = False
def __init__(self, *args, **kwargs):
super(GlobalPositions, self).__init__(*args, **kwargs)
def spawn(self, agents, level_shape, *args, **kwargs):
self.add_items([self._entity(agent, level_shape, *args, **kwargs) for agent in agents])
return [Result(identifier=f'{self.name}_spawn', validity=c.VALID, value=len(self))]
def trigger_spawn(self, state: Gamestate, *args, **kwargs) -> [Result]:
return self.spawn(state[c.AGENT], state.lvl_shape, *args, **kwargs)

View File

@ -7,9 +7,12 @@ class Walls(Collection):
_entity = Wall
symbol = c.SYMBOL_WALL
@property
def var_has_position(self):
return True
var_can_collide = True
var_is_blocking_light = True
var_can_move = False
var_has_position = True
var_can_be_bound = False
var_is_blocking_pos = True
def __init__(self, *args, **kwargs):
super(Walls, self).__init__(*args, **kwargs)