From 467cc3f7931be22ef6aa2ee85c94a0f9e2d32bb4 Mon Sep 17 00:00:00 2001
From: Steffen Illium <steffen.illium@ifi.lmu.de>
Date: Fri, 17 Nov 2023 12:27:03 +0100
Subject: [PATCH] Comments, small bugfixes removed legacy elements

---
 marl_factory_grid/configs/default_config.yaml |   1 +
 marl_factory_grid/environment/constants.py    |   1 +
 marl_factory_grid/environment/entity/agent.py |  80 +++++++++--
 .../environment/entity/entity.py              | 129 +++++++++++++++++-
 .../environment/entity/object.py              |  92 +++++++++++--
 marl_factory_grid/environment/entity/util.py  |  36 ++++-
 marl_factory_grid/environment/entity/wall.py  |   6 +
 marl_factory_grid/environment/factory.py      |  36 +++++
 .../environment/groups/agents.py              |  14 +-
 .../environment/groups/collection.py          |   6 -
 .../environment/groups/mixins.py              |   6 -
 .../environment/groups/objects.py             |   2 +-
 marl_factory_grid/environment/groups/utils.py |  35 +++--
 marl_factory_grid/environment/rules.py        |  82 ++++++++++-
 marl_factory_grid/modules/batteries/groups.py |   4 -
 marl_factory_grid/modules/doors/entitites.py  |   1 -
 marl_factory_grid/modules/doors/groups.py     |   2 +
 marl_factory_grid/modules/items/groups.py     |   9 +-
 marl_factory_grid/modules/zones/rules.py      |   2 +-
 marl_factory_grid/utils/helpers.py            |   7 +
 .../utils/observation_builder.py              |  12 ++
 marl_factory_grid/utils/ray_caster.py         |   6 +
 marl_factory_grid/utils/renderer.py           |   6 +
 marl_factory_grid/utils/results.py            |  28 ++++
 marl_factory_grid/utils/states.py             |  12 ++
 marl_factory_grid/utils/tools.py              |   6 +
 marl_factory_grid/utils/utility_classes.py    |  12 ++
 27 files changed, 569 insertions(+), 64 deletions(-)

diff --git a/marl_factory_grid/configs/default_config.yaml b/marl_factory_grid/configs/default_config.yaml
index 1118704..4f6d3ee 100644
--- a/marl_factory_grid/configs/default_config.yaml
+++ b/marl_factory_grid/configs/default_config.yaml
@@ -23,6 +23,7 @@ Agents:
     - DropOffLocations
     - Maintainers
 Entities:
+
   Batteries:
     initial_charge: 0.8
     per_action_costs: 0.02
diff --git a/marl_factory_grid/environment/constants.py b/marl_factory_grid/environment/constants.py
index 6ddb19a..deb368d 100644
--- a/marl_factory_grid/environment/constants.py
+++ b/marl_factory_grid/environment/constants.py
@@ -24,6 +24,7 @@ SYMBOL_FLOOR            = '-'
 
 VALID                   = True            # Identifier to rename boolean values in the context of actions.
 NOT_VALID               = False           # Identifier to rename boolean values in the context of actions.
+
 VALUE_FREE_CELL         = 0               # Free-Cell value used in observation
 VALUE_OCCUPIED_CELL     = 1               # Occupied-Cell value used in observation
 VALUE_NO_POS            = (-9999, -9999)  # Invalid Position value used in the environment (smth. is off-grid)
diff --git a/marl_factory_grid/environment/entity/agent.py b/marl_factory_grid/environment/entity/agent.py
index f4d9b3b..25a26ec 100644
--- a/marl_factory_grid/environment/entity/agent.py
+++ b/marl_factory_grid/environment/entity/agent.py
@@ -14,37 +14,70 @@ class Agent(Entity):
 
     @property
     def var_is_paralyzed(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return len(self._paralyzed)
 
     @property
     def paralyze_reasons(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return [x for x in self._paralyzed]
 
     @property
     def obs_tag(self):
+        """Internal Usage"""
         return self.name
 
     @property
     def actions(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return self._actions
 
     @property
     def observations(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return self._observations
 
     def step_result(self):
-        pass
+        """
+        TODO
+        FIXME THINK ITS LEGACY... Not Used any more
 
-    @property
-    def collection(self):
-        return self._collection
+
+        :return:
+        """
+        pass
 
     @property
     def var_is_blocking_pos(self):
         return self._is_blocking_pos
 
-
     def __init__(self, actions: List[Action], observations: List[str], *args, is_blocking_pos=False, **kwargs):
+        """
+        TODO
+
+
+        :return:
+        """
         super(Agent, self).__init__(*args, **kwargs)
         self._paralyzed = set()
         self.step_result = dict()
@@ -54,26 +87,53 @@ class Agent(Entity):
         self._is_blocking_pos = is_blocking_pos
 
     def summarize_state(self):
+        """
+        TODO
+
+
+        :return:
+        """
         state_dict = super().summarize_state()
         state_dict.update(valid=bool(self.state.validity), action=str(self.state.identifier))
         return state_dict
 
-    def set_state(self, action_result):
-        self._status = action_result
+    def set_state(self, state):
+        """
+        TODO
+
+
+        :return:
+        """
+        self._status = state
+        return c.VALID
+
 
     def paralyze(self, reason):
+        """
+        TODO
+
+
+        :return:
+        """
         self._paralyzed.add(reason)
         return c.VALID
 
-    def de_paralyze(self, reason):
+    def de_paralyze(self, reason) -> bool:
+        """
+        TODO
+
+
+        :return:
+        """
         try:
             self._paralyzed.remove(reason)
             return c.VALID
         except KeyError:
             return c.NOT_VALID
 
-    def render(self):
-        i = next(idx for idx, x in enumerate(self._collection) if x.name == self.name)
+    def render(self) -> RenderEntity:
+        i = self.collection.idx_by_entity(self)
+        assert i is not None
         curr_state = self.state
         if curr_state.identifier == c.COLLISION:
             render_state = renderer.STATE_COLLISION
diff --git a/marl_factory_grid/environment/entity/entity.py b/marl_factory_grid/environment/entity/entity.py
index 4926153..42a52eb 100644
--- a/marl_factory_grid/environment/entity/entity.py
+++ b/marl_factory_grid/environment/entity/entity.py
@@ -4,23 +4,40 @@ import numpy as np
 
 from .object import Object
 from .. import constants as c
-from ...utils.results import ActionResult
+from ...utils.results import State
 from ...utils.utility_classes import RenderEntity
 
 
 class Entity(Object, abc.ABC):
-    """Full Env Entity that lives on the environment Grid. Doors, Items, DirtPile etc..."""
 
     @property
     def state(self):
-        return self._status or ActionResult(entity=self, identifier=c.NOOP, validity=c.VALID)
+        """
+        TODO
+
+
+        :return:
+        """
+        return self._status or State(entity=self, identifier=c.NOOP, validity=c.VALID)
 
     @property
     def var_has_position(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return self.pos != c.VALUE_NO_POS
 
     @property
     def var_is_blocking_light(self):
+        """
+        TODO
+
+
+        :return:
+        """
         try:
             return self._collection.var_is_blocking_light or False
         except AttributeError:
@@ -28,6 +45,12 @@ class Entity(Object, abc.ABC):
 
     @property
     def var_can_move(self):
+        """
+        TODO
+
+
+        :return:
+        """
         try:
             return self._collection.var_can_move or False
         except AttributeError:
@@ -35,6 +58,12 @@ class Entity(Object, abc.ABC):
 
     @property
     def var_is_blocking_pos(self):
+        """
+        TODO
+
+
+        :return:
+        """
         try:
             return self._collection.var_is_blocking_pos or False
         except AttributeError:
@@ -42,6 +71,12 @@ class Entity(Object, abc.ABC):
 
     @property
     def var_can_collide(self):
+        """
+        TODO
+
+
+        :return:
+        """
         try:
             return self._collection.var_can_collide or False
         except AttributeError:
@@ -49,22 +84,53 @@ class Entity(Object, abc.ABC):
 
     @property
     def x(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return self.pos[0]
 
     @property
     def y(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return self.pos[1]
 
     @property
     def pos(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return self._pos
 
-    def set_pos(self, pos):
+    def set_pos(self, pos) -> bool:
+        """
+        TODO
+
+
+        :return:
+        """
         assert isinstance(pos, tuple) and len(pos) == 2
         self._pos = pos
+        return c.VALID
 
     @property
     def last_pos(self):
+        """
+        TODO
+
+
+        :return:
+        """
         try:
             return self._last_pos
         except AttributeError:
@@ -74,12 +140,24 @@ class Entity(Object, abc.ABC):
 
     @property
     def direction_of_view(self):
+        """
+        TODO
+
+
+        :return:
+        """
         if self._last_pos != c.VALUE_NO_POS:
             return 0, 0
         else:
             return np.subtract(self._last_pos, self.pos)
 
     def move(self, next_pos, state):
+        """
+        TODO
+
+
+        :return:
+        """
         next_pos = next_pos
         curr_pos = self._pos
         if not_same_pos := curr_pos != next_pos:
@@ -95,11 +173,19 @@ class Entity(Object, abc.ABC):
         return not_same_pos
 
     def __init__(self, pos, bind_to=None, **kwargs):
+        """
+        Full Env Entity that lives on the environment Grid. Doors, Items, DirtPile etc...
+        TODO
+
+
+        :return:
+        """
         super().__init__(**kwargs)
         self._view_directory = c.VALUE_NO_POS
         self._status = None
         self._pos = pos
         self._last_pos = pos
+        self._collection = None
         if bind_to:
             try:
                 self.bind_to(bind_to)
@@ -108,14 +194,27 @@ class Entity(Object, abc.ABC):
                 exit()
 
     def summarize_state(self) -> dict:
+        """
+        TODO
+
+
+        :return:
+        """
         return dict(name=str(self.name), x=int(self.x), y=int(self.y), can_collide=bool(self.var_can_collide))
 
     @abc.abstractmethod
     def render(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return RenderEntity(self.__class__.__name__.lower(), self.pos)
 
     @property
     def obs_tag(self):
+        """Internal Usage"""
         try:
             return self._collection.name or self.name
         except AttributeError:
@@ -123,10 +222,32 @@ class Entity(Object, abc.ABC):
 
     @property
     def encoding(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return c.VALUE_OCCUPIED_CELL
 
     def change_parent_collection(self, other_collection):
+        """
+        TODO
+
+
+        :return:
+        """
         other_collection.add_item(self)
         self._collection.delete_env_object(self)
         self._collection = other_collection
         return self._collection == other_collection
+
+    @property
+    def collection(self):
+        """
+        TODO
+
+
+        :return:
+        """
+        return self._collection
diff --git a/marl_factory_grid/environment/entity/object.py b/marl_factory_grid/environment/entity/object.py
index fbb4f75..c81f622 100644
--- a/marl_factory_grid/environment/entity/object.py
+++ b/marl_factory_grid/environment/entity/object.py
@@ -6,40 +6,85 @@ import marl_factory_grid.utils.helpers as h
 
 
 class Object:
-    """Generell Objects for Organisation and Maintanance such as Actions etc..."""
 
     _u_idx = defaultdict(lambda: 0)
 
-    def __bool__(self):
-        return True
+    @property
+    def bound_entity(self):
+        """
+        TODO
+
+
+        :return:
+        """
+        return self._bound_entity
 
     @property
-    def var_can_be_bound(self):
+    def var_can_be_bound(self) -> bool:
+        """
+        TODO
+        Indicates if it is possible to bind this object to another Entity or Object.
+
+        :return: Whether this object can be bound.
+        """
         try:
             return self._collection.var_can_be_bound or False
         except AttributeError:
             return False
 
     @property
-    def observers(self):
+    def observers(self) -> set:
+        """
+        TODO
+
+
+        :return:
+        """
         return self._observers
 
     @property
     def name(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return f'{self.__class__.__name__}[{self.identifier}]'
 
     @property
     def identifier(self):
+        """
+        TODO
+
+
+        :return:
+        """
         if self._str_ident is not None:
             return self._str_ident
         else:
             return self.u_int
 
     def reset_uid(self):
+        """
+        TODO
+
+
+        :return:
+        """
         self._u_idx = defaultdict(lambda: 0)
         return True
 
     def __init__(self, str_ident: Union[str, None] = None, **kwargs):
+        """
+        Generell Objects for Organisation and Maintanance such as Actions etc...
+
+        TODO
+
+        :param str_ident:
+
+        :return:
+        """
         self._status = None
         self._bound_entity = None
         self._observers = set()
@@ -50,6 +95,9 @@ class Object:
         if kwargs:
             print(f'Following kwargs were passed, but ignored: {kwargs}')
 
+    def __bool__(self) -> bool:
+        return True
+
     def __repr__(self):
         name = self.name
         if self.bound_entity:
@@ -67,39 +115,61 @@ class Object:
     def __hash__(self):
         return hash(self.identifier)
 
-    def _identify_and_count_up(self):
+    def _identify_and_count_up(self) -> int:
+        """Internal Usage"""
         idx = Object._u_idx[self.__class__.__name__]
         Object._u_idx[self.__class__.__name__] += 1
         return idx
 
     def set_collection(self, collection):
+        """Internal Usage"""
         self._collection = collection
+        return self
 
     def add_observer(self, observer):
+        """Internal Usage"""
         self.observers.add(observer)
         observer.notify_add_entity(self)
+        return self
 
     def del_observer(self, observer):
+        """Internal Usage"""
         self.observers.remove(observer)
+        return self
 
     def summarize_state(self):
         return dict()
 
     def clear_temp_state(self):
+        """Internal Usage"""
         self._status = None
         return self
 
     def bind_to(self, entity):
-        # noinspection PyAttributeOutsideInit
+        """
+        TODO
+
+
+        :return:
+        """
         self._bound_entity = entity
         return c.VALID
 
     def belongs_to_entity(self, entity):
+        """
+        TODO
+
+
+        :return:
+        """
         return self._bound_entity == entity
 
-    @property
-    def bound_entity(self):
-        return self._bound_entity
-
     def unbind(self):
+        """
+        TODO
+
+        :return:
+        """
+        previously_bound = self._bound_entity
         self._bound_entity = None
+        return previously_bound
diff --git a/marl_factory_grid/environment/entity/util.py b/marl_factory_grid/environment/entity/util.py
index 2a15c41..6961aec 100644
--- a/marl_factory_grid/environment/entity/util.py
+++ b/marl_factory_grid/environment/entity/util.py
@@ -11,15 +11,33 @@ from marl_factory_grid.environment.entity.object import Object
 class PlaceHolder(Object):
 
     def __init__(self, *args, fill_value=0, **kwargs):
+        """
+        TODO
+
+
+        :return:
+        """
         super().__init__(*args, **kwargs)
         self._fill_value = fill_value
 
     @property
-    def can_collide(self):
+    def var_can_collide(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return False
 
     @property
     def encoding(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return self._fill_value
 
     @property
@@ -29,14 +47,30 @@ class PlaceHolder(Object):
 
 class GlobalPosition(Object):
 
+    @property
+    def obs_tag(self):
+        return self.name
+
     @property
     def encoding(self):
+        """
+        TODO
+
+
+        :return:
+        """
         if self._normalized:
             return tuple(np.divide(self._bound_entity.pos, self._shape))
         else:
             return self.bound_entity.pos
 
     def __init__(self, agent, level_shape, *args, normalized: bool = True, **kwargs):
+        """
+        TODO
+
+
+        :return:
+        """
         super(GlobalPosition, self).__init__(*args, **kwargs)
         self.bind_to(agent)
         self._normalized = normalized
diff --git a/marl_factory_grid/environment/entity/wall.py b/marl_factory_grid/environment/entity/wall.py
index 83044cd..439bb39 100644
--- a/marl_factory_grid/environment/entity/wall.py
+++ b/marl_factory_grid/environment/entity/wall.py
@@ -6,6 +6,12 @@ from marl_factory_grid.utils.utility_classes import RenderEntity
 class Wall(Entity):
 
     def __init__(self, *args, **kwargs):
+        """
+        TODO
+
+
+        :return:
+        """
         super().__init__(*args, **kwargs)
 
     @property
diff --git a/marl_factory_grid/environment/factory.py b/marl_factory_grid/environment/factory.py
index b0a0372..1c91689 100644
--- a/marl_factory_grid/environment/factory.py
+++ b/marl_factory_grid/environment/factory.py
@@ -23,22 +23,52 @@ class Factory(gym.Env):
 
     @property
     def action_space(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return self.state[c.AGENT].action_space
 
     @property
     def named_action_space(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return self.state[c.AGENT].named_action_space
 
     @property
     def observation_space(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return self.obs_builder.observation_space(self.state)
 
     @property
     def named_observation_space(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return self.obs_builder.named_observation_space(self.state)
 
     @property
     def params(self) -> dict:
+        """
+        FIXME LAGEGY
+
+
+        :return:
+        """
         import yaml
         config_path = Path(self._config_file)
         config_dict = yaml.safe_load(config_path.open())
@@ -49,6 +79,12 @@ class Factory(gym.Env):
 
     def __init__(self, config_file: Union[str, PathLike], custom_modules_path: Union[None, PathLike] = None,
                  custom_level_path: Union[None, PathLike] = None):
+        """
+        TODO
+
+
+        :return:
+        """
         self._config_file = config_file
         self.conf = FactoryConfigParser(self._config_file, custom_modules_path)
         # Attribute Assignment
diff --git a/marl_factory_grid/environment/groups/agents.py b/marl_factory_grid/environment/groups/agents.py
index 5405ab1..4d244b7 100644
--- a/marl_factory_grid/environment/groups/agents.py
+++ b/marl_factory_grid/environment/groups/agents.py
@@ -26,12 +26,24 @@ class Agents(Collection):
 
     @property
     def action_space(self):
+        """
+        TODO
+
+
+        :return:
+        """
         from gymnasium import spaces
         space = spaces.Tuple([spaces.Discrete(len(x.actions)) for x in self])
         return space
 
     @property
-    def named_action_space(self):
+    def named_action_space(self) -> dict[str, dict[str, list[int]]]:
+        """
+        TODO
+
+
+        :return:
+        """
         named_space = dict()
         for agent in self:
             named_space[agent.name] = {action.name: idx for idx, action in enumerate(agent.actions)}
diff --git a/marl_factory_grid/environment/groups/collection.py b/marl_factory_grid/environment/groups/collection.py
index c7c9f4c..e818d36 100644
--- a/marl_factory_grid/environment/groups/collection.py
+++ b/marl_factory_grid/environment/groups/collection.py
@@ -118,12 +118,6 @@ class Collection(Objects):
         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)))
-        except (StopIteration, AttributeError):
-            return None
-
     def render(self):
         if self.var_has_position:
             return [y for y in [x.render() for x in self] if y is not None]
diff --git a/marl_factory_grid/environment/groups/mixins.py b/marl_factory_grid/environment/groups/mixins.py
index acfac7e..fad0985 100644
--- a/marl_factory_grid/environment/groups/mixins.py
+++ b/marl_factory_grid/environment/groups/mixins.py
@@ -28,9 +28,3 @@ class HasBoundMixin:
             return next((x for x in self if 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)))
-        except (StopIteration, AttributeError):
-            return None
diff --git a/marl_factory_grid/environment/groups/objects.py b/marl_factory_grid/environment/groups/objects.py
index 23e91ab..9df31da 100644
--- a/marl_factory_grid/environment/groups/objects.py
+++ b/marl_factory_grid/environment/groups/objects.py
@@ -160,7 +160,7 @@ class Objects:
 
     def idx_by_entity(self, entity):
         try:
-            return h.get_first_index(self, filter_by=lambda x: x.belongs_to_entity(entity))
+            return h.get_first_index(self, filter_by=lambda x: x == entity)
         except (StopIteration, AttributeError):
             return None
 
diff --git a/marl_factory_grid/environment/groups/utils.py b/marl_factory_grid/environment/groups/utils.py
index d272152..6c12440 100644
--- a/marl_factory_grid/environment/groups/utils.py
+++ b/marl_factory_grid/environment/groups/utils.py
@@ -1,4 +1,4 @@
-from typing import List, Union
+from typing import List, Union, Iterable
 
 from marl_factory_grid.environment import constants as c
 from marl_factory_grid.environment.entity.util import GlobalPosition
@@ -39,17 +39,36 @@ class GlobalPositions(Collection):
 
     _entity = GlobalPosition
 
-    var_is_blocking_light = False
-    var_can_be_bound = True
-    var_can_collide = False
-    var_has_position = False
+    @property
+    def var_is_blocking_light(self):
+        return False
+
+    @property
+    def var_has_position(self):
+        return False
+
+    @property
+    def var_can_collide(self):
+        return False
+
+    @property
+    def var_can_be_bound(self):
+        return True
 
     def __init__(self, *args, **kwargs):
+        """
+        TODO
+
+
+        :return:
+        """
         super(GlobalPositions, self).__init__(*args, **kwargs)
 
-    def spawn(self, agents, level_shape, *args, **kwargs):
+    def spawn(self, agents, level_shape, *args, **kwargs) -> list[Result]:
         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)
+    def trigger_spawn(self, state: Gamestate, *args, **kwargs) -> list[Result]:
+        result = self.spawn(state[c.AGENT], state.lvl_shape, *args, **kwargs)
+        state.print(f'{len(self)} new {self.__class__.__name__} have been spawned for {[x for x in state[c.AGENT]]}')
+        return result
diff --git a/marl_factory_grid/environment/rules.py b/marl_factory_grid/environment/rules.py
index 2e5f305..5151aec 100644
--- a/marl_factory_grid/environment/rules.py
+++ b/marl_factory_grid/environment/rules.py
@@ -12,44 +12,94 @@ class Rule(abc.ABC):
 
     @property
     def name(self):
+        """
+        TODO
+
+
+        :return:
+        """
         return self.__class__.__name__
 
     def __init__(self):
+        """
+        TODO
+
+
+        :return:
+        """
         pass
 
     def __repr__(self):
         return f'{self.name}'
 
     def on_init(self, state, lvl_map):
+        """
+        TODO
+
+
+        :return:
+        """
         return []
 
     def on_reset(self, state) -> List[TickResult]:
+        """
+        TODO
+
+
+        :return:
+        """
         return []
 
     def tick_pre_step(self, state) -> List[TickResult]:
+        """
+        TODO
+
+
+        :return:
+        """
         return []
 
     def tick_step(self, state) -> List[TickResult]:
+        """
+        TODO
+
+
+        :return:
+        """
         return []
 
     def tick_post_step(self, state) -> List[TickResult]:
+        """
+        TODO
+
+
+        :return:
+        """
         return []
 
     def on_check_done(self, state) -> List[DoneResult]:
+        """
+        TODO
+
+
+        :return:
+        """
         return []
 
 
 class SpawnEntity(Rule):
 
-    @property
-    def _collection(self) -> Collection:
-        return Collection()
-
     @property
     def name(self):
         return f'{self.__class__.__name__}({self.collection.name})'
 
     def __init__(self, collection, coords_or_quantity, ignore_blocking=False):
+        """
+        TODO
+
+
+        :return:
+        """
         super().__init__()
         self.coords_or_quantity = coords_or_quantity
         self.collection = collection
@@ -65,6 +115,12 @@ class SpawnEntity(Rule):
 class SpawnAgents(Rule):
 
     def __init__(self):
+        """
+        TODO
+
+
+        :return:
+        """
         super().__init__()
         pass
 
@@ -91,6 +147,12 @@ class SpawnAgents(Rule):
 class DoneAtMaxStepsReached(Rule):
 
     def __init__(self, max_steps: int = 500):
+        """
+        TODO
+
+
+        :return:
+        """
         super().__init__()
         self.max_steps = max_steps
 
@@ -103,6 +165,12 @@ class DoneAtMaxStepsReached(Rule):
 class AssignGlobalPositions(Rule):
 
     def __init__(self):
+        """
+        TODO
+
+
+        :return:
+        """
         super().__init__()
 
     def on_reset(self, state, lvl_map):
@@ -116,6 +184,12 @@ class AssignGlobalPositions(Rule):
 class WatchCollisions(Rule):
 
     def __init__(self, reward=r.COLLISION, done_at_collisions: bool = False, reward_at_done=r.COLLISION_DONE):
+        """
+        TODO
+
+
+        :return:
+        """
         super().__init__()
         self.reward_at_done = reward_at_done
         self.reward = reward
diff --git a/marl_factory_grid/modules/batteries/groups.py b/marl_factory_grid/modules/batteries/groups.py
index 7db43bd..b5f930a 100644
--- a/marl_factory_grid/modules/batteries/groups.py
+++ b/marl_factory_grid/modules/batteries/groups.py
@@ -12,10 +12,6 @@ class Batteries(Collection):
     var_has_position = False
     var_can_be_bound = True
 
-    @property
-    def obs_tag(self):
-        return self.__class__.__name__
-
     def __init__(self, size, initial_charge_level: float=1.0, *args, **kwargs):
         super(Batteries, self).__init__(size, *args, **kwargs)
         self.initial_charge_level = initial_charge_level
diff --git a/marl_factory_grid/modules/doors/entitites.py b/marl_factory_grid/modules/doors/entitites.py
index ed7ad57..411eb9c 100644
--- a/marl_factory_grid/modules/doors/entitites.py
+++ b/marl_factory_grid/modules/doors/entitites.py
@@ -50,7 +50,6 @@ class Door(Entity):
     def is_open(self):
         return self._state == d.STATE_OPEN
 
-
     @property
     def time_to_close(self):
         return self._time_to_close
diff --git a/marl_factory_grid/modules/doors/groups.py b/marl_factory_grid/modules/doors/groups.py
index 0e83881..cc0b83a 100644
--- a/marl_factory_grid/modules/doors/groups.py
+++ b/marl_factory_grid/modules/doors/groups.py
@@ -18,6 +18,7 @@ class Doors(Collection):
     def tick_doors(self, state):
         results = list()
         for door in self:
+            assert isinstance(door, Door)
             tick_result = door.tick(state)
             if tick_result is not None:
                 results.append(tick_result)
@@ -26,4 +27,5 @@ class Doors(Collection):
 
     def reset(self):
         for door in self:
+            assert isinstance(door, Door)
             door.reset()
diff --git a/marl_factory_grid/modules/items/groups.py b/marl_factory_grid/modules/items/groups.py
index d69935f..ff7a88f 100644
--- a/marl_factory_grid/modules/items/groups.py
+++ b/marl_factory_grid/modules/items/groups.py
@@ -56,6 +56,9 @@ class Inventory(IsBoundMixin, Collection):
         self._collection = None
         self.bind(agent)
 
+    def __repr__(self):
+        return f'{self.__class__.__name__}#{self._bound_entity.name}({dict(self._data)})'
+
     def summarize_states(self, **kwargs):
         attr_dict = {key: val for key, val in self.__dict__.items() if not key.startswith('_') and key != 'data'}
         attr_dict.update(dict(items=[val.summarize_state(**kwargs) for key, val in self.items()]))
@@ -100,12 +103,6 @@ class Inventories(Objects):
     def trigger_spawn(self, state, *args, **kwargs) -> [Result]:
         return self.spawn(state[c.AGENT], *args, **kwargs)
 
-    def idx_by_entity(self, entity):
-        try:
-            return next((idx for idx, inv in enumerate(self) if inv.belongs_to_entity(entity)))
-        except StopIteration:
-            return None
-
     def by_entity(self, entity):
         try:
             return next((inv for inv in self if inv.belongs_to_entity(entity)))
diff --git a/marl_factory_grid/modules/zones/rules.py b/marl_factory_grid/modules/zones/rules.py
index a52de61..f308256 100644
--- a/marl_factory_grid/modules/zones/rules.py
+++ b/marl_factory_grid/modules/zones/rules.py
@@ -47,7 +47,7 @@ class AgentSingleZonePlacement(Rule):
 class IndividualDestinationZonePlacement(Rule):
 
     def __init__(self):
-        raise NotImplementedError("This is rpetty new, and needs to be debugged, after the zones")
+        raise NotImplementedError("This is pretty new, and needs to be debugged, after the zones")
         super().__init__()
 
     def on_reset(self, state):
diff --git a/marl_factory_grid/utils/helpers.py b/marl_factory_grid/utils/helpers.py
index c1c850f..cb54c2b 100644
--- a/marl_factory_grid/utils/helpers.py
+++ b/marl_factory_grid/utils/helpers.py
@@ -249,4 +249,11 @@ def get_first(iterable: Iterable, filter_by: Callable[[any], bool] = lambda _: T
 
 
 def get_first_index(iterable: Iterable, filter_by: Callable[[any], bool] = lambda _: True):
+    """
+    todo
+
+    :param iterable:
+    :param filter_by:
+    :return:
+    """
     return next((idx for idx, x in enumerate(iterable) if filter_by(x)), None)
diff --git a/marl_factory_grid/utils/observation_builder.py b/marl_factory_grid/utils/observation_builder.py
index 35497bf..aae544b 100644
--- a/marl_factory_grid/utils/observation_builder.py
+++ b/marl_factory_grid/utils/observation_builder.py
@@ -18,12 +18,24 @@ class OBSBuilder(object):
 
     @property
     def pomdp_d(self):
+        """
+        TODO
+
+
+        :return:
+        """
         if self.pomdp_r:
             return (self.pomdp_r * 2) + 1
         else:
             return 0
 
     def __init__(self, level_shape: np.size, state: Gamestate, pomdp_r: int):
+        """
+        TODO
+
+
+        :return:
+        """
         self.all_obs = dict()
         self.ray_caster = dict()
 
diff --git a/marl_factory_grid/utils/ray_caster.py b/marl_factory_grid/utils/ray_caster.py
index d89997e..87d682e 100644
--- a/marl_factory_grid/utils/ray_caster.py
+++ b/marl_factory_grid/utils/ray_caster.py
@@ -7,6 +7,12 @@ from numba import njit
 
 class RayCaster:
     def __init__(self, agent, pomdp_r, degs=360):
+        """
+        TODO
+
+
+        :return:
+        """
         self.agent = agent
         self.pomdp_r = pomdp_r
         self.n_rays = 100  # (self.pomdp_r + 1) * 8
diff --git a/marl_factory_grid/utils/renderer.py b/marl_factory_grid/utils/renderer.py
index 1976974..08a7293 100644
--- a/marl_factory_grid/utils/renderer.py
+++ b/marl_factory_grid/utils/renderer.py
@@ -33,6 +33,12 @@ class Renderer:
                  lvl_padded_shape: Union[Tuple[int, int], None] = None,
                  cell_size: int = 40, fps: int = 7, factor: float = 0.9,
                  grid_lines: bool = True, view_radius: int = 2):
+        """
+        TODO
+
+
+        :return:
+        """
         # TODO: Customn_assets paths
         self.grid_h, self.grid_w = lvl_shape
         self.lvl_padded_shape = lvl_padded_shape if lvl_padded_shape is not None else lvl_shape
diff --git a/marl_factory_grid/utils/results.py b/marl_factory_grid/utils/results.py
index b4b07fc..67f0545 100644
--- a/marl_factory_grid/utils/results.py
+++ b/marl_factory_grid/utils/results.py
@@ -10,6 +10,12 @@ TYPES = [TYPE_VALUE, TYPE_REWARD]
 
 @dataclass
 class InfoObject:
+    """
+    TODO
+
+
+    :return:
+    """
     identifier: str
     val_type: str
     value: Union[float, int]
@@ -17,6 +23,12 @@ class InfoObject:
 
 @dataclass
 class Result:
+    """
+    TODO
+
+
+    :return:
+    """
     identifier: str
     validity: bool
     reward: Union[float, None] = None
@@ -40,6 +52,17 @@ class Result:
 
 @dataclass
 class TickResult(Result):
+    """
+    TODO
+    """
+    pass
+
+
+@dataclass
+class ActionResult(Result):
+    """
+    TODO
+    """
     pass
 
 
@@ -47,6 +70,11 @@ class TickResult(Result):
 class ActionResult(Result):
     pass
 
+@dataclass
+class State(Result):
+    # TODO: change identifiert to action/last_action
+    pass
+
 
 @dataclass
 class DoneResult(Result):
diff --git a/marl_factory_grid/utils/states.py b/marl_factory_grid/utils/states.py
index 523615a..36cd166 100644
--- a/marl_factory_grid/utils/states.py
+++ b/marl_factory_grid/utils/states.py
@@ -12,6 +12,12 @@ from marl_factory_grid.utils.results import Result, DoneResult
 
 class StepRules:
     def __init__(self, *args):
+        """
+        TODO
+
+
+        :return:
+        """
         if args:
             self.rules = list(args)
         else:
@@ -77,6 +83,12 @@ class Gamestate(object):
         return [y for x in self.entities for y in x if x.var_can_move]
 
     def __init__(self, entities, agents_conf, rules: List[Rule], lvl_shape, env_seed=69, verbose=False):
+        """
+        TODO
+
+
+        :return:
+        """
         self.lvl_shape = lvl_shape
         self.entities = entities
         self.curr_step = 0
diff --git a/marl_factory_grid/utils/tools.py b/marl_factory_grid/utils/tools.py
index 73fa50d..29c17eb 100644
--- a/marl_factory_grid/utils/tools.py
+++ b/marl_factory_grid/utils/tools.py
@@ -22,6 +22,12 @@ EXCLUDED     = ['identifier', 'args', 'kwargs', 'Move', 'Agent', 'GlobalPosition
 class ConfigExplainer:
 
     def __init__(self, custom_path: Union[None, PathLike] = None):
+        """
+        TODO
+
+
+        :return:
+        """
         self.base_path = Path(__file__).parent.parent.resolve()
         self.custom_path = custom_path
         self.searchspace = [ACTION, GENERAL, ENTITIES, OBSERVATIONS, RULES, ASSETS]
diff --git a/marl_factory_grid/utils/utility_classes.py b/marl_factory_grid/utils/utility_classes.py
index 4d1cfe1..1ed9932 100644
--- a/marl_factory_grid/utils/utility_classes.py
+++ b/marl_factory_grid/utils/utility_classes.py
@@ -18,6 +18,12 @@ class MarlFrameStack(gym.ObservationWrapper):
 
 @dataclass
 class RenderEntity:
+    """
+    TODO
+
+
+    :return:
+    """
     name: str
     pos: np.array
     value: float = 1
@@ -30,6 +36,12 @@ class RenderEntity:
 
 @dataclass
 class Floor:
+    """
+    TODO
+
+
+    :return:
+    """
 
     @property
     def encoding(self):