From b0aeb6f94f66179e8df16275103c1a66cb693532 Mon Sep 17 00:00:00 2001 From: Steffen Illium Date: Wed, 28 Jul 2021 11:26:19 +0200 Subject: [PATCH] Correct Door Shadowing --- environments/factory/base/base_factory.py | 37 ++++++++++++++++----- environments/factory/base/objects.py | 6 +++- environments/factory/base/shadow_casting.py | 6 ++-- environments/factory/simple_factory.py | 2 +- environments/helpers.py | 2 -- 5 files changed, 37 insertions(+), 16 deletions(-) diff --git a/environments/factory/base/base_factory.py b/environments/factory/base/base_factory.py index ba3a86c..f52e94b 100644 --- a/environments/factory/base/base_factory.py +++ b/environments/factory/base/base_factory.py @@ -39,13 +39,13 @@ class BaseFactory(gym.Env): elif not self.combin_agent_slices_in_obs and not self.omit_agent_slice_in_obs: slices = self._slices.n - level_shape = (self.pomdp_radius * 2 + 1, self.pomdp_radius * 2 + 1) if self.pomdp_radius else self._level_shape + level_shape = (self.pomdp_r * 2 + 1, self.pomdp_r * 2 + 1) if self.pomdp_r else self._level_shape space = spaces.Box(low=0, high=1, shape=(slices, *level_shape), dtype=np.float32) return space @property def pomdp_diameter(self): - return self.pomdp_radius * 2 + 1 + return self.pomdp_r * 2 + 1 @property def movement_actions(self): @@ -100,7 +100,7 @@ class BaseFactory(gym.Env): self.n_agents = n_agents self.max_steps = max_steps - self.pomdp_radius = pomdp_radius + self.pomdp_r = pomdp_radius self.combin_agent_slices_in_obs = combin_agent_slices_in_obs self.omit_agent_slice_in_obs = omit_agent_slice_in_obs self.cast_shadows = cast_shadows @@ -149,7 +149,7 @@ class BaseFactory(gym.Env): x, y = self._slices.by_enum(c.LEVEL).shape state = np.zeros((len(self._slices), x, y), dtype=np.float32) state[0] = self._slices.by_enum(c.LEVEL).slice - if r := self.pomdp_radius: + if r := self.pomdp_r: self._padded_obs_cube = np.full((len(self._slices), x + r*2, y + r*2), c.FREE_CELL.value, dtype=np.float32) self._padded_obs_cube[0] = c.OCCUPIED_CELL.value self._padded_obs_cube[:, r:r+x, r:r+y] = state @@ -293,14 +293,14 @@ class BaseFactory(gym.Env): def _build_per_agent_obs(self, agent: Agent) -> np.ndarray: first_agent_slice = self._slices.AGENTSTARTIDX - if r := self.pomdp_radius: + if r := self.pomdp_r: x, y = self._level_shape self._padded_obs_cube[:, r:r + x, r:r + y] = self._obs_cube global_x, global_y = agent.pos global_x += r global_y += r - x0, x1 = max(0, global_x - self.pomdp_radius), global_x + self.pomdp_radius + 1 - y0, y1 = max(0, global_y - self.pomdp_radius), global_y + self.pomdp_radius + 1 + x0, x1 = max(0, global_x - self.pomdp_r), global_x + self.pomdp_r + 1 + y0, y1 = max(0, global_y - self.pomdp_r), global_y + self.pomdp_r + 1 obs = self._padded_obs_cube[:, x0:x1, y0:y1] else: obs = self._obs_cube @@ -308,10 +308,29 @@ class BaseFactory(gym.Env): if self.cast_shadows: obs_block_light = [obs[idx] != c.OCCUPIED_CELL.value for idx, slice in enumerate(self._slices) if slice.is_blocking_light] + door_shadowing = False + if door := self._doors.by_pos(agent.pos): + if door.is_closed: + for group in door.connectivity_subgroups: + if agent.last_pos not in group: + door_shadowing = True + if self.pomdp_r: + blocking = [tuple(np.subtract(x, agent.pos) + (self.pomdp_r, self.pomdp_r)) + for x in group] + xs, ys = zip(*blocking) + else: + xs, ys = zip(*group) + obs_block_light[self._slices.get_idx(c.LEVEL)][xs, ys] = False + light_block_map = Map((np.prod(obs_block_light, axis=0) != True).astype(int)) - light_block_map = light_block_map.do_fov(self.pomdp_radius, self.pomdp_radius, max(self._level_shape)) + if self.pomdp_r: + light_block_map = light_block_map.do_fov(self.pomdp_r, self.pomdp_r, max(self._level_shape)) + else: + light_block_map = light_block_map.do_fov(*agent.pos, max(self._level_shape)) + if door_shadowing: + light_block_map[xs, ys] = 0 agent.temp_light_map = light_block_map - obs = (obs * light_block_map) - ((1 - light_block_map) * obs[self._slices.get_idx_by_name(c.LEVEL.name)]) + obs = (obs * light_block_map) - ((1 - light_block_map) * obs[self._slices.get_idx(c.LEVEL)]) if self.combin_agent_slices_in_obs and self.n_agents > 1: agent_obs = np.sum(obs[[key for key, l_slice in self._slices.items() if c.AGENT.name in l_slice.name and diff --git a/environments/factory/base/objects.py b/environments/factory/base/objects.py index 24a6081..7d5f90d 100644 --- a/environments/factory/base/objects.py +++ b/environments/factory/base/objects.py @@ -211,6 +211,10 @@ class Door(Entity): for a, b in possible_connections: if not max(abs(np.subtract(a, b))) > 1: self.connectivity.add_edge(a, b) + self.connectivity_subgroups = list(nx.algorithms.components.connected_components(self.connectivity)) + for idx, group in enumerate(self.connectivity_subgroups): + for tile_pos in group: + self.connectivity.add_edge(tile_pos, idx) if not closed_on_init: self._open() @@ -239,7 +243,7 @@ class Door(Entity): self.use() def _open(self): - self.connectivity.add_edges_from([(self.pos, x) for x in self.connectivity.nodes]) + self.connectivity.add_edges_from([(self.pos, x) for x in range(len(self.connectivity_subgroups))]) self._state = c.OPEN_DOOR self.time_to_close = self.auto_close_interval diff --git a/environments/factory/base/shadow_casting.py b/environments/factory/base/shadow_casting.py index 967d3f7..8c03b68 100644 --- a/environments/factory/base/shadow_casting.py +++ b/environments/factory/base/shadow_casting.py @@ -2,7 +2,6 @@ import numpy as np from environments.helpers import Constants as c -FOV_RADIUS = 10 mult_array = np.asarray([ [1, 0, 0, -1, -1, 0, 0, 1], [0, 1, -1, 0, 0, -1, 1, 0], @@ -14,11 +13,12 @@ mult_array = np.asarray([ class Map(object): # Multipliers for transforming coordinates to other octants: - def __init__(self, map_array: np.ndarray): + def __init__(self, map_array: np.ndarray, 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.d_slope = diamond_slope def blocked(self, x, y): return (x < 0 or y < 0 @@ -47,7 +47,7 @@ class Map(object): 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: - l_slope, r_slope = (dx-0.5)/(dy+0.5), (dx+0.5)/(dy-0.5) + 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: diff --git a/environments/factory/simple_factory.py b/environments/factory/simple_factory.py index cff9990..be46028 100644 --- a/environments/factory/simple_factory.py +++ b/environments/factory/simple_factory.py @@ -60,7 +60,7 @@ class SimpleFactory(BaseFactory): if not self._renderer: # lazy init height, width = self._obs_cube.shape[1:] - self._renderer = Renderer(width, height, view_radius=self.pomdp_radius, fps=5) + self._renderer = Renderer(width, height, view_radius=self.pomdp_r, fps=5) dirt_slice = self._slices.by_name(DIRT).slice dirt = [Entity('dirt', tile.pos, min(0.15 + dirt_slice[tile.pos], 1.5), 'scale') for tile in [tile for tile in self._tiles if dirt_slice[tile.pos]]] diff --git a/environments/helpers.py b/environments/helpers.py index 6b058ac..5d340f6 100644 --- a/environments/helpers.py +++ b/environments/helpers.py @@ -20,8 +20,6 @@ class Constants(Enum): CLOSED_DOOR = 1 OPEN_DOOR = -1 - LEVEL_IDX = 0 - ACTION = auto() COLLISIONS = auto() VALID = True