Item and Dirt Factory Working again
This commit is contained in:
@ -1,8 +1,6 @@
|
||||
import abc
|
||||
import enum
|
||||
import time
|
||||
from collections import defaultdict
|
||||
from enum import Enum
|
||||
from itertools import chain
|
||||
from pathlib import Path
|
||||
from typing import List, Union, Iterable, Dict
|
||||
@ -13,8 +11,8 @@ from gym import spaces
|
||||
from gym.wrappers import FrameStack
|
||||
|
||||
from environments.factory.base.shadow_casting import Map
|
||||
from environments.helpers import Constants as c, Constants
|
||||
from environments import helpers as h
|
||||
from environments.helpers import Constants as c
|
||||
from environments.factory.base.objects import Agent, Tile, Action
|
||||
from environments.factory.base.registers import Actions, Entities, Agents, Doors, FloorTiles, WallTiles, PlaceHolders, \
|
||||
GlobalPositions
|
||||
@ -53,10 +51,9 @@ class BaseFactory(gym.Env):
|
||||
_, named_obs = self._build_observations()
|
||||
if self.n_agents > 1:
|
||||
# Only return the first named obs space, as their structure at the moment is same.
|
||||
return [{key.name: val for key, val in named_ob.items()} for named_ob in named_obs.values()][0]
|
||||
return named_obs[list(named_obs.keys())[0]]
|
||||
else:
|
||||
return {key.name: val for key, val in named_obs.items()}
|
||||
|
||||
return named_obs
|
||||
|
||||
@property
|
||||
def pomdp_diameter(self):
|
||||
@ -143,27 +140,27 @@ class BaseFactory(gym.Env):
|
||||
|
||||
# Walls
|
||||
walls = WallTiles.from_argwhere_coordinates(
|
||||
np.argwhere(level_array == c.OCCUPIED_CELL.value),
|
||||
np.argwhere(level_array == c.OCCUPIED_CELL),
|
||||
self._level_shape
|
||||
)
|
||||
self._entities.register_additional_items({c.WALLS: walls})
|
||||
|
||||
# Floor
|
||||
floor = FloorTiles.from_argwhere_coordinates(
|
||||
np.argwhere(level_array == c.FREE_CELL.value),
|
||||
np.argwhere(level_array == c.FREE_CELL),
|
||||
self._level_shape
|
||||
)
|
||||
self._entities.register_additional_items({c.FLOOR: floor})
|
||||
|
||||
# NOPOS
|
||||
self._NO_POS_TILE = Tile(c.NO_POS.value, None)
|
||||
self._NO_POS_TILE = Tile(c.NO_POS, None)
|
||||
|
||||
# Doors
|
||||
if self.parse_doors:
|
||||
parsed_doors = h.one_hot_level(self._parsed_level, c.DOOR)
|
||||
parsed_doors = np.pad(parsed_doors, self.obs_prop.pomdp_r, 'constant', constant_values=0)
|
||||
if np.any(parsed_doors):
|
||||
door_tiles = [floor.by_pos(tuple(pos)) for pos in np.argwhere(parsed_doors == c.OCCUPIED_CELL.value)]
|
||||
door_tiles = [floor.by_pos(tuple(pos)) for pos in np.argwhere(parsed_doors == c.OCCUPIED_CELL)]
|
||||
doors = Doors.from_tiles(door_tiles, self._level_shape,
|
||||
entity_kwargs=dict(context=floor)
|
||||
)
|
||||
@ -209,7 +206,7 @@ class BaseFactory(gym.Env):
|
||||
if self.obs_prop.show_global_position_info:
|
||||
global_positions = GlobalPositions(self._level_shape)
|
||||
obs_shape_2d = self._level_shape if not self._pomdp_r else ((self.pomdp_diameter,) * 2)
|
||||
global_positions.spawn_GlobalPositionObjects(obs_shape_2d, self[c.AGENT])
|
||||
global_positions.spawn_global_position_objects(obs_shape_2d, self[c.AGENT])
|
||||
self._entities.register_additional_items({c.GLOBAL_POSITION: global_positions})
|
||||
|
||||
# Return
|
||||
@ -239,8 +236,8 @@ class BaseFactory(gym.Env):
|
||||
for action, agent in zip(actions, self[c.AGENT]):
|
||||
agent.clear_temp_state()
|
||||
action_obj = self._actions[int(action)]
|
||||
# self.print(f'Action #{action} has been resolved to: {action_obj}')
|
||||
if h.MovingAction.is_member(action_obj):
|
||||
# cls.print(f'Action #{action} has been resolved to: {action_obj}')
|
||||
if h.EnvActions.is_move(action_obj):
|
||||
valid = self._move_or_colide(agent, action_obj)
|
||||
elif h.EnvActions.NOOP == agent.temp_action:
|
||||
valid = c.VALID
|
||||
@ -338,12 +335,12 @@ class BaseFactory(gym.Env):
|
||||
obs_dict[c.AGENT_PLACEHOLDER] = placeholder_obs
|
||||
obs_dict[c.DOORS] = door_obs
|
||||
obs_dict.update(add_obs_dict)
|
||||
observations = np.vstack(list(obs_dict.values()))
|
||||
obsn = np.vstack(list(obs_dict.values()))
|
||||
if self.obs_prop.pomdp_r:
|
||||
observations = self._do_pomdp_cutout(agent, observations)
|
||||
obsn = self._do_pomdp_cutout(agent, obsn)
|
||||
|
||||
raw_obs = self._additional_raw_observations(agent)
|
||||
observations = np.vstack((observations, *list(raw_obs.values())))
|
||||
raw_obs = self._additional_per_agent_raw_observations(agent)
|
||||
obsn = np.vstack((obsn, *list(raw_obs.values())))
|
||||
|
||||
keys = list(chain(obs_dict.keys(), raw_obs.keys()))
|
||||
idxs = np.cumsum([x.shape[0] for x in chain(obs_dict.values(), raw_obs.values())]) - 1
|
||||
@ -365,7 +362,7 @@ class BaseFactory(gym.Env):
|
||||
print(e)
|
||||
raise e
|
||||
if self.obs_prop.cast_shadows:
|
||||
obs_block_light = observations[light_block_obs] != c.OCCUPIED_CELL.value
|
||||
obs_block_light = obsn[light_block_obs] != c.OCCUPIED_CELL
|
||||
door_shadowing = False
|
||||
if self.parse_doors:
|
||||
if doors := self[c.DOORS]:
|
||||
@ -395,11 +392,11 @@ class BaseFactory(gym.Env):
|
||||
light_block_map[xs, ys] = 0
|
||||
agent.temp_light_map = light_block_map.copy()
|
||||
|
||||
observations[shadowed_obs] = ((observations[shadowed_obs] * light_block_map) + 0.) - (1 - light_block_map)
|
||||
obsn[shadowed_obs] = ((obsn[shadowed_obs] * light_block_map) + 0.) - (1 - light_block_map)
|
||||
else:
|
||||
pass
|
||||
|
||||
per_agent_obsn[agent.name] = observations
|
||||
per_agent_obsn[agent.name] = obsn
|
||||
|
||||
if self.n_agents == 1:
|
||||
agent_name = self[c.AGENT][0].name
|
||||
@ -450,7 +447,7 @@ class BaseFactory(gym.Env):
|
||||
tiles_with_collisions.append(tile)
|
||||
return tiles_with_collisions
|
||||
|
||||
def _move_or_colide(self, agent: Agent, action: Action) -> Constants:
|
||||
def _move_or_colide(self, agent: Agent, action: Action) -> bool:
|
||||
new_tile, valid = self._check_agent_move(agent, action)
|
||||
if valid:
|
||||
# Does not collide width level boundaries
|
||||
@ -624,7 +621,7 @@ class BaseFactory(gym.Env):
|
||||
return []
|
||||
|
||||
@property
|
||||
def additional_entities(self) -> Dict[(Enum, Entities)]:
|
||||
def additional_entities(self) -> Dict[(str, Entities)]:
|
||||
"""
|
||||
When heriting from this Base Class, you musst implement this methode!!!
|
||||
|
||||
@ -652,11 +649,11 @@ class BaseFactory(gym.Env):
|
||||
return False
|
||||
|
||||
@abc.abstractmethod
|
||||
def _additional_observations(self) -> Dict[Constants, np.typing.ArrayLike]:
|
||||
def _additional_observations(self) -> Dict[str, np.typing.ArrayLike]:
|
||||
return {}
|
||||
|
||||
@abc.abstractmethod
|
||||
def _additional_raw_observations(self, agent) -> Dict[Constants, np.typing.ArrayLike]:
|
||||
def _additional_per_agent_raw_observations(self, agent) -> Dict[str, np.typing.ArrayLike]:
|
||||
additional_raw_observations = {}
|
||||
if self.obs_prop.show_global_position_info:
|
||||
additional_raw_observations.update({c.GLOBAL_POSITION: self[c.GLOBAL_POSITION].by_entity(agent).as_array()})
|
||||
|
@ -1,5 +1,4 @@
|
||||
from collections import defaultdict
|
||||
from enum import Enum
|
||||
from typing import Union
|
||||
|
||||
import networkx as nx
|
||||
@ -29,24 +28,18 @@ class Object:
|
||||
|
||||
@property
|
||||
def identifier(self):
|
||||
if self._enum_ident is not None:
|
||||
return self._enum_ident
|
||||
elif self._str_ident is not None:
|
||||
if self._str_ident is not None:
|
||||
return self._str_ident
|
||||
else:
|
||||
return self._name
|
||||
|
||||
def __init__(self, str_ident: Union[str, None] = None, enum_ident: Union[Enum, None] = None,
|
||||
is_blocking_light=False, **kwargs):
|
||||
def __init__(self, str_ident: Union[str, None] = None, is_blocking_light=False, **kwargs):
|
||||
|
||||
self._str_ident = str_ident
|
||||
self._enum_ident = enum_ident
|
||||
|
||||
if self._enum_ident is not None and self._str_ident is None:
|
||||
self._name = f'{self.__class__.__name__}[{self._enum_ident.name}]'
|
||||
elif self._str_ident is not None and self._enum_ident is None:
|
||||
if self._str_ident is not None:
|
||||
self._name = f'{self.__class__.__name__}[{self._str_ident}]'
|
||||
elif self._str_ident is None and self._enum_ident is None:
|
||||
elif self._str_ident is None:
|
||||
self._name = f'{self.__class__.__name__}#{Object._u_idx[self.__class__.__name__]}'
|
||||
Object._u_idx[self.__class__.__name__] += 1
|
||||
else:
|
||||
@ -60,16 +53,7 @@ class Object:
|
||||
return f'{self.name}'
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
if self._enum_ident is not None:
|
||||
if isinstance(other, Enum):
|
||||
return other == self._enum_ident
|
||||
elif isinstance(other, Object):
|
||||
return other._enum_ident == self._enum_ident
|
||||
else:
|
||||
raise ValueError('Must be evaluated against an Enunm Identifier or Object with such.')
|
||||
else:
|
||||
assert isinstance(other, Object), ' This Object can only be compared to other Objects.'
|
||||
return other.name == self.name
|
||||
return other == self.identifier
|
||||
|
||||
|
||||
class EnvObject(Object):
|
||||
@ -80,14 +64,17 @@ class EnvObject(Object):
|
||||
|
||||
@property
|
||||
def encoding(self):
|
||||
return c.OCCUPIED_CELL.value
|
||||
return c.OCCUPIED_CELL
|
||||
|
||||
def __init__(self, register, **kwargs):
|
||||
super(EnvObject, self).__init__(**kwargs)
|
||||
self._register = register
|
||||
|
||||
def change_register(self, register):
|
||||
self._register = register
|
||||
|
||||
class BoundingMixin:
|
||||
|
||||
class BoundingMixin(Object):
|
||||
|
||||
@property
|
||||
def bound_entity(self):
|
||||
@ -163,7 +150,7 @@ class MoveableEntity(Entity):
|
||||
if self._last_tile:
|
||||
return self._last_tile.pos
|
||||
else:
|
||||
return c.NO_POS.value
|
||||
return c.NO_POS
|
||||
|
||||
@property
|
||||
def direction_of_view(self):
|
||||
@ -218,30 +205,27 @@ class PlaceHolder(Object):
|
||||
return "PlaceHolder"
|
||||
|
||||
|
||||
class GlobalPosition(EnvObject):
|
||||
class GlobalPosition(EnvObject, BoundingMixin):
|
||||
|
||||
def belongs_to_entity(self, entity):
|
||||
return self._agent == entity
|
||||
@property
|
||||
def encoding(self):
|
||||
if self._normalized:
|
||||
return tuple(np.diff(self._bound_entity.pos, self._level_shape))
|
||||
else:
|
||||
return self.bound_entity.pos
|
||||
|
||||
def __init__(self, level_shape, *args, normalized: bool = True, **kwargs):
|
||||
super(GlobalPosition, self).__init__(self, *args, **kwargs)
|
||||
|
||||
def __init__(self, level_shape, obs_shape, agent, normalized: bool = True):
|
||||
super(GlobalPosition, self).__init__(self)
|
||||
self._obs_shape = (1, *obs_shape) if len(obs_shape) == 2 else obs_shape
|
||||
self._agent = agent
|
||||
self._level_shape = level_shape
|
||||
self._normalized = normalized
|
||||
|
||||
def as_array(self):
|
||||
pos_array = np.zeros(self._obs_shape)
|
||||
for xy in range(1):
|
||||
pos_array[0, 0, xy] = self._agent.pos[xy] / self._level_shape[xy]
|
||||
return pos_array
|
||||
|
||||
|
||||
class Tile(EnvObject):
|
||||
|
||||
@property
|
||||
def encoding(self):
|
||||
return c.FREE_CELL.value
|
||||
return c.FREE_CELL
|
||||
|
||||
@property
|
||||
def guests_that_can_collide(self):
|
||||
@ -302,7 +286,7 @@ class Wall(Tile):
|
||||
|
||||
@property
|
||||
def encoding(self):
|
||||
return c.OCCUPIED_CELL.value
|
||||
return c.OCCUPIED_CELL
|
||||
|
||||
pass
|
||||
|
||||
@ -319,7 +303,7 @@ class Door(Entity):
|
||||
@property
|
||||
def encoding(self):
|
||||
# This is important as it shadow is checked by occupation value
|
||||
return c.OCCUPIED_CELL.value if self.is_closed else 2
|
||||
return c.OCCUPIED_CELL if self.is_closed else 2
|
||||
|
||||
@property
|
||||
def str_state(self):
|
||||
@ -403,7 +387,7 @@ class Agent(MoveableEntity):
|
||||
|
||||
# noinspection PyAttributeOutsideInit
|
||||
def clear_temp_state(self):
|
||||
# for attr in self.__dict__:
|
||||
# for attr in cls.__dict__:
|
||||
# if attr.startswith('temp'):
|
||||
self.temp_collisions = []
|
||||
self.temp_valid = None
|
||||
|
@ -4,6 +4,7 @@ from abc import ABC
|
||||
from typing import List, Union, Dict, Tuple
|
||||
|
||||
import numpy as np
|
||||
import six
|
||||
|
||||
from environments.factory.base.objects import Entity, Tile, Agent, Door, Action, Wall, PlaceHolder, GlobalPosition, \
|
||||
Object, EnvObject
|
||||
@ -56,7 +57,7 @@ class ObjectRegister:
|
||||
def _get_index(self, item):
|
||||
try:
|
||||
return next(i for i, v in enumerate(self._register.values()) if v == item)
|
||||
except (StopIteration, AssertionError):
|
||||
except StopIteration:
|
||||
return None
|
||||
|
||||
def __getitem__(self, item):
|
||||
@ -73,24 +74,30 @@ class ObjectRegister:
|
||||
return None
|
||||
|
||||
def __repr__(self):
|
||||
return f'{self.__class__.__name__}({self._register})'
|
||||
return f'{self.__class__.__name__}[{self._register}]'
|
||||
|
||||
|
||||
class EnvObjectRegister(ObjectRegister):
|
||||
|
||||
_accepted_objects = EnvObject
|
||||
|
||||
def __init__(self, obs_shape: (int, int), *args, **kwargs):
|
||||
@property
|
||||
def encodings(self):
|
||||
return [x.encoding for x in self]
|
||||
|
||||
def __init__(self, obs_shape: (int, int), *args, individual_slices: bool = False, **kwargs):
|
||||
super(EnvObjectRegister, self).__init__(*args, **kwargs)
|
||||
self._shape = obs_shape
|
||||
self._array = None
|
||||
self.hide_from_obs_builder = False
|
||||
self._individual_slices = individual_slices
|
||||
self._lazy_eval_transforms = []
|
||||
|
||||
def register_item(self, other: EnvObject):
|
||||
super(EnvObjectRegister, self).register_item(other)
|
||||
if self._array is None:
|
||||
self._array = np.zeros((1, *self._shape))
|
||||
if self._individual_slices:
|
||||
self._array = np.vstack((self._array, np.zeros((1, *self._shape))))
|
||||
self.notify_change_to_value(other)
|
||||
|
||||
def as_array(self):
|
||||
@ -105,7 +112,7 @@ class EnvObjectRegister(ObjectRegister):
|
||||
return [val.summarize_state(n_steps=n_steps) for val in self.values()]
|
||||
|
||||
def notify_change_to_free(self, env_object: EnvObject):
|
||||
self._array_change_notifyer(env_object, value=c.FREE_CELL.value)
|
||||
self._array_change_notifyer(env_object, value=c.FREE_CELL)
|
||||
|
||||
def notify_change_to_value(self, env_object: EnvObject):
|
||||
self._array_change_notifyer(env_object)
|
||||
@ -114,9 +121,28 @@ class EnvObjectRegister(ObjectRegister):
|
||||
pos = self._get_index(env_object)
|
||||
value = value if value is not None else env_object.encoding
|
||||
self._lazy_eval_transforms.append((pos, value))
|
||||
if self._individual_slices:
|
||||
idx = (self._get_index(env_object) * np.prod(self._shape[1:]), value)
|
||||
self._lazy_eval_transforms.append((idx, value))
|
||||
else:
|
||||
self._lazy_eval_transforms.append((pos, value))
|
||||
|
||||
def _refresh_arrays(self):
|
||||
poss, values = zip(*[(idx, x.encoding) for idx,x in enumerate(self.values())])
|
||||
for pos, value in zip(poss, values):
|
||||
self._lazy_eval_transforms.append((pos, value))
|
||||
|
||||
def __delitem__(self, name):
|
||||
self.notify_change_to_free(self._register[name])
|
||||
idx, obj = next((i, obj) for i, obj in enumerate(self) if obj.name == name)
|
||||
if self._individual_slices:
|
||||
self._array = np.delete(self._array, idx, axis=0)
|
||||
else:
|
||||
self.notify_change_to_free(self._register[name])
|
||||
# Dirty Hack to check if not beeing subclassed. In that case we need to refresh the array since positions
|
||||
# in the observation array are result of enumeration. They can overide each other.
|
||||
# Todo: Find a better solution
|
||||
if not issubclass(self.__class__, EntityRegister) and issubclass(self.__class__, EnvObjectRegister):
|
||||
self._refresh_arrays()
|
||||
del self._register[name]
|
||||
|
||||
def delete_env_object(self, env_object: EnvObject):
|
||||
@ -153,26 +179,19 @@ class EntityRegister(EnvObjectRegister, ABC):
|
||||
def tiles(self):
|
||||
return [entity.tile for entity in self]
|
||||
|
||||
@property
|
||||
def encodings(self):
|
||||
return [x.encoding for x in self]
|
||||
|
||||
def __init__(self, level_shape, *args,
|
||||
is_blocking_light: bool = False,
|
||||
can_be_shadowed: bool = True,
|
||||
individual_slices: bool = False, **kwargs):
|
||||
**kwargs):
|
||||
super(EntityRegister, self).__init__(level_shape, *args, **kwargs)
|
||||
self._lazy_eval_transforms = []
|
||||
self.can_be_shadowed = can_be_shadowed
|
||||
self.individual_slices = individual_slices
|
||||
self.is_blocking_light = is_blocking_light
|
||||
|
||||
def __delitem__(self, name):
|
||||
idx, obj = next((i, obj) for i, obj in enumerate(self) if obj.name == name)
|
||||
obj.tile.leave(obj)
|
||||
super(EntityRegister, self).__delitem__(name)
|
||||
if self.individual_slices:
|
||||
self._array = np.delete(self._array, idx, axis=0)
|
||||
|
||||
def as_array(self):
|
||||
if self._lazy_eval_transforms:
|
||||
@ -188,7 +207,7 @@ class EntityRegister(EnvObjectRegister, ABC):
|
||||
pos = pos if pos is not None else entity.pos
|
||||
value = value if value is not None else entity.encoding
|
||||
x, y = pos
|
||||
if self.individual_slices:
|
||||
if self._individual_slices:
|
||||
idx = (self._get_index(entity), x, y)
|
||||
else:
|
||||
idx = (0, x, y)
|
||||
@ -203,19 +222,12 @@ class EntityRegister(EnvObjectRegister, ABC):
|
||||
|
||||
class BoundRegisterMixin(EnvObjectRegister, ABC):
|
||||
|
||||
@classmethod
|
||||
def from_entities_to_bind(self, entitites):
|
||||
def from_values(cls, values: Union[str, numbers.Number, List[Union[str, numbers.Number]]],
|
||||
*args, object_kwargs=None, **kwargs):
|
||||
# objects_name = cls._accepted_objects.__name__
|
||||
if isinstance(values, (str, numbers.Number)):
|
||||
values = [values]
|
||||
register_obj = cls(*args, **kwargs)
|
||||
objects = [cls._accepted_objects(register_obj, str_ident=i, fill_value=value,
|
||||
**object_kwargs if object_kwargs is not None else {})
|
||||
for i, value in enumerate(values)]
|
||||
register_obj.register_additional_items(objects)
|
||||
return register_obj
|
||||
def __init__(self, entity_to_be_bound, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._bound_entity = entity_to_be_bound
|
||||
|
||||
def belongs_to_entity(self, entity):
|
||||
return self._bound_entity == entity
|
||||
|
||||
|
||||
class MovingEntityObjectRegister(EntityRegister, ABC):
|
||||
@ -225,9 +237,9 @@ class MovingEntityObjectRegister(EntityRegister, ABC):
|
||||
|
||||
def notify_change_to_value(self, entity):
|
||||
super(MovingEntityObjectRegister, self).notify_change_to_value(entity)
|
||||
if entity.last_pos != c.NO_POS.value:
|
||||
if entity.last_pos != c.NO_POS:
|
||||
try:
|
||||
self._array_change_notifyer(entity, entity.last_pos, value=c.FREE_CELL.value)
|
||||
self._array_change_notifyer(entity, entity.last_pos, value=c.FREE_CELL)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
@ -238,20 +250,26 @@ class MovingEntityObjectRegister(EntityRegister, ABC):
|
||||
|
||||
|
||||
class GlobalPositions(EnvObjectRegister):
|
||||
|
||||
_accepted_objects = GlobalPosition
|
||||
|
||||
is_blocking_light = False
|
||||
can_be_shadowed = False
|
||||
hide_from_obs_builder = True
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(GlobalPositions, self).__init__(*args, is_per_agent=True, individual_slices=True, **kwargs)
|
||||
|
||||
def as_array(self):
|
||||
# Todo make this lazy?
|
||||
# FIXME DEBUG!!! make this lazy?
|
||||
return np.stack([gp.as_array() for inv_idx, gp in enumerate(self)])
|
||||
|
||||
def spawn_GlobalPositionObjects(self, obs_shape, agents):
|
||||
global_positions = [self._accepted_objects(self._shape, obs_shape, agent)
|
||||
def as_array_by_entity(self, entity):
|
||||
# FIXME DEBUG!!! make this lazy?
|
||||
return np.stack([gp.as_array() for inv_idx, gp in enumerate(self)])
|
||||
|
||||
def spawn_global_position_objects(self, agents):
|
||||
# Todo, change to 'from xy'-form
|
||||
global_positions = [self._accepted_objects(self._shape, agent)
|
||||
for _, agent in enumerate(agents)]
|
||||
# noinspection PyTypeChecker
|
||||
self.register_additional_items(global_positions)
|
||||
@ -276,7 +294,7 @@ class PlaceHolders(EnvObjectRegister):
|
||||
_accepted_objects = PlaceHolder
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
assert not 'individual_slices' in kwargs, 'Keyword - "individual_slices": "True" and must not be altered'
|
||||
assert 'individual_slices' not in kwargs, 'Keyword - "individual_slices": "True" and must not be altered'
|
||||
kwargs.update(individual_slices=False)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@ -316,10 +334,6 @@ class Entities(ObjectRegister):
|
||||
def arrays(self):
|
||||
return {key: val.as_array() for key, val in self.items()}
|
||||
|
||||
@property
|
||||
def obs_arrays(self):
|
||||
return {key: val.as_array() for key, val in self.items() if not val.hide_from_obs_builder}
|
||||
|
||||
@property
|
||||
def names(self):
|
||||
return list(self._register.keys())
|
||||
@ -347,24 +361,20 @@ class Entities(ObjectRegister):
|
||||
class WallTiles(EntityRegister):
|
||||
_accepted_objects = Wall
|
||||
_light_blocking = True
|
||||
hide_from_obs_builder = True
|
||||
|
||||
def as_array(self):
|
||||
if not np.any(self._array):
|
||||
# Which is Faster?
|
||||
# indices = [x.pos for x in self]
|
||||
# np.put(self._array, [np.ravel_multi_index((0, *x), self._array.shape) for x in indices], self.encodings)
|
||||
# indices = [x.pos for x in cls]
|
||||
# np.put(cls._array, [np.ravel_multi_index((0, *x), cls._array.shape) for x in indices], cls.encodings)
|
||||
x, y = zip(*[x.pos for x in self])
|
||||
self._array[0, x, y] = self.encoding
|
||||
self._array[0, x, y] = self._value
|
||||
return self._array
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(WallTiles, self).__init__(*args, is_blocking_light=self._light_blocking, individual_slices=False,
|
||||
**kwargs)
|
||||
|
||||
@property
|
||||
def encoding(self):
|
||||
return c.OCCUPIED_CELL.value
|
||||
self._value = c.OCCUPIED_CELL
|
||||
|
||||
@classmethod
|
||||
def from_argwhere_coordinates(cls, argwhere_coordinates, *args, **kwargs):
|
||||
@ -393,10 +403,7 @@ class FloorTiles(WallTiles):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(FloorTiles, self).__init__(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def encoding(self):
|
||||
return c.FREE_CELL.value
|
||||
self._value = c.FREE_CELL
|
||||
|
||||
@property
|
||||
def occupied_tiles(self):
|
||||
@ -422,23 +429,8 @@ class FloorTiles(WallTiles):
|
||||
class Agents(MovingEntityObjectRegister):
|
||||
_accepted_objects = Agent
|
||||
|
||||
def __init__(self, *args, hide_from_obs_builder=False, **kwargs):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.hide_from_obs_builder = hide_from_obs_builder
|
||||
|
||||
@DeprecationWarning
|
||||
def Xas_array(self):
|
||||
# Super Safe Version
|
||||
# self._array[:] = c.FREE_CELL.value
|
||||
indices = list(zip(range(len(self)), *zip(*[x.last_pos for x in self])))
|
||||
np.put(self._array, [np.ravel_multi_index(x, self._array.shape) for x in indices], c.FREE_CELL.value)
|
||||
indices = list(zip(range(len(self)), *zip(*[x.pos for x in self])))
|
||||
np.put(self._array, [np.ravel_multi_index(x, self._array.shape) for x in indices], self.encodings)
|
||||
|
||||
if self.individual_slices:
|
||||
return self._array
|
||||
else:
|
||||
return self._array.sum(axis=0, keepdims=True)
|
||||
|
||||
@property
|
||||
def positions(self):
|
||||
@ -484,17 +476,18 @@ class Actions(ObjectRegister):
|
||||
self.can_use_doors = can_use_doors
|
||||
super(Actions, self).__init__()
|
||||
|
||||
# Move this to Baseclass, Env init?
|
||||
if self.allow_square_movement:
|
||||
self.register_additional_items([self._accepted_objects(enum_ident=direction)
|
||||
for direction in h.MovingAction.square()])
|
||||
self.register_additional_items([self._accepted_objects(str_ident=direction)
|
||||
for direction in h.EnvActions.square_move()])
|
||||
if self.allow_diagonal_movement:
|
||||
self.register_additional_items([self._accepted_objects(enum_ident=direction)
|
||||
for direction in h.MovingAction.diagonal()])
|
||||
self.register_additional_items([self._accepted_objects(str_ident=direction)
|
||||
for direction in h.EnvActions.diagonal_move()])
|
||||
self._movement_actions = self._register.copy()
|
||||
if self.can_use_doors:
|
||||
self.register_additional_items([self._accepted_objects(enum_ident=h.EnvActions.USE_DOOR)])
|
||||
self.register_additional_items([self._accepted_objects(str_ident=h.EnvActions.USE_DOOR)])
|
||||
if self.allow_no_op:
|
||||
self.register_additional_items([self._accepted_objects(enum_ident=h.EnvActions.NOOP)])
|
||||
self.register_additional_items([self._accepted_objects(str_ident=h.EnvActions.NOOP)])
|
||||
|
||||
def is_moving_action(self, action: Union[int]):
|
||||
return action in self.movement_actions.values()
|
||||
@ -504,7 +497,7 @@ class Zones(ObjectRegister):
|
||||
|
||||
@property
|
||||
def accounting_zones(self):
|
||||
return [self[idx] for idx, name in self.items() if name != c.DANGER_ZONE.value]
|
||||
return [self[idx] for idx, name in self.items() if name != c.DANGER_ZONE]
|
||||
|
||||
def __init__(self, parsed_level):
|
||||
raise NotImplementedError('This needs a Rework')
|
||||
@ -513,9 +506,9 @@ class Zones(ObjectRegister):
|
||||
self._accounting_zones = list()
|
||||
self._danger_zones = list()
|
||||
for symbol in np.unique(parsed_level):
|
||||
if symbol == c.WALL.value:
|
||||
if symbol == c.WALL:
|
||||
continue
|
||||
elif symbol == c.DANGER_ZONE.value:
|
||||
elif symbol == c.DANGER_ZONE:
|
||||
self + symbol
|
||||
slices.append(h.one_hot_level(parsed_level, symbol))
|
||||
self._danger_zones.append(symbol)
|
||||
|
@ -16,14 +16,14 @@ class Map(object):
|
||||
def __init__(self, map_array: np.typing.ArrayLike, diamond_slope: float = 0.9):
|
||||
self.data = map_array
|
||||
self.width, self.height = map_array.shape
|
||||
self.light = np.full_like(self.data, c.FREE_CELL.value)
|
||||
self.flag = c.FREE_CELL.value
|
||||
self.light = np.full_like(self.data, c.FREE_CELL)
|
||||
self.flag = c.FREE_CELL
|
||||
self.d_slope = diamond_slope
|
||||
|
||||
def blocked(self, x, y):
|
||||
return (x < 0 or y < 0
|
||||
or x >= self.width or y >= self.height
|
||||
or self.data[x, y] == c.OCCUPIED_CELL.value)
|
||||
or self.data[x, y] == c.OCCUPIED_CELL)
|
||||
|
||||
def lit(self, x, y):
|
||||
return self.light[x, y] == self.flag
|
||||
@ -46,14 +46,14 @@ class Map(object):
|
||||
# Translate the dx, dy coordinates into map coordinates:
|
||||
X, Y = cx + dx * xx + dy * xy, cy + dx * yx + dy * yy
|
||||
# l_slope and r_slope store the slopes of the left and right
|
||||
# extremities of the square we're considering:
|
||||
# extremities of the square_move we're considering:
|
||||
l_slope, r_slope = (dx-self.d_slope)/(dy+self.d_slope), (dx+self.d_slope)/(dy-self.d_slope)
|
||||
if start < r_slope:
|
||||
continue
|
||||
elif end > l_slope:
|
||||
break
|
||||
else:
|
||||
# Our light beam is touching this square; light it:
|
||||
# Our light beam is touching this square_move; light it:
|
||||
if dx*dx + dy*dy < radius_squared:
|
||||
self.set_lit(X, Y)
|
||||
if blocked:
|
||||
@ -66,12 +66,12 @@ class Map(object):
|
||||
start = new_start
|
||||
else:
|
||||
if self.blocked(X, Y) and j < radius:
|
||||
# This is a blocking square, start a child scan:
|
||||
# This is a blocking square_move, start a child scan:
|
||||
blocked = True
|
||||
self._cast_light(cx, cy, j+1, start, l_slope,
|
||||
radius, xx, xy, yx, yy, id+1)
|
||||
new_start = r_slope
|
||||
# Row is scanned; do next row unless last square was blocked:
|
||||
# Row is scanned; do next row unless last square_move was blocked:
|
||||
if blocked:
|
||||
break
|
||||
|
||||
|
Reference in New Issue
Block a user