concurrent actor decisions
parent
6111f69c48
commit
8798de1a83
7
main.py
7
main.py
|
@ -8,12 +8,13 @@ STEPS = 1000
|
||||||
|
|
||||||
np.random.seed(12345)
|
np.random.seed(12345)
|
||||||
fig, ax = plt.subplots()
|
fig, ax = plt.subplots()
|
||||||
env = Environment((40, 30))
|
env = Environment((100, 100))
|
||||||
|
|
||||||
first_agent = CAMSReverseAndSidestepAgent(
|
first_agent = CAMSReverseAndSidestepAgent(
|
||||||
environment=env,
|
environment=env,
|
||||||
position=(20,15),
|
position=(50,50),
|
||||||
initial_direction=Direction.NORTH
|
initial_direction=Direction.NORTH,
|
||||||
|
required_resources=300
|
||||||
)
|
)
|
||||||
|
|
||||||
im = ax.imshow(env.render(), aspect="equal", origin="lower")
|
im = ax.imshow(env.render(), aspect="equal", origin="lower")
|
||||||
|
|
153
sim.py
153
sim.py
|
@ -1,6 +1,7 @@
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
class Direction(Enum):
|
class Direction(Enum):
|
||||||
NORTH = (0, 1)
|
NORTH = (0, 1)
|
||||||
|
@ -8,10 +9,6 @@ class Direction(Enum):
|
||||||
WEST = (-1, 0)
|
WEST = (-1, 0)
|
||||||
EAST = (1, 0)
|
EAST = (1, 0)
|
||||||
|
|
||||||
class CellState(Enum):
|
|
||||||
OPEN = auto()
|
|
||||||
WALL = auto()
|
|
||||||
|
|
||||||
class Colours(Enum):
|
class Colours(Enum):
|
||||||
WALL = [30,30,30]
|
WALL = [30,30,30]
|
||||||
STOCKED = [200,150,0]
|
STOCKED = [200,150,0]
|
||||||
|
@ -19,23 +16,24 @@ class Colours(Enum):
|
||||||
UNDEFINED = [255,0,255]
|
UNDEFINED = [255,0,255]
|
||||||
AGENT = [0,255,0]
|
AGENT = [0,255,0]
|
||||||
|
|
||||||
class Cell():
|
@dataclass
|
||||||
def __init__(self, state, resources):
|
class Observations:
|
||||||
self.state = state
|
obstacles: np.ndarray
|
||||||
self.resources = resources
|
resources: np.ndarray
|
||||||
|
agents: np.ndarray
|
||||||
|
|
||||||
|
def has_obstacle(self, position):
|
||||||
|
return self.obstacles[tuple(position)] == 1
|
||||||
|
|
||||||
|
def has_agent(self, position):
|
||||||
|
return self.agents[tuple(position)] == 1
|
||||||
|
|
||||||
|
def has_resources(self, position):
|
||||||
|
return self.resources[tuple(position)] > 0
|
||||||
|
|
||||||
|
def get_resources(self, position):
|
||||||
|
return self.resources[tuple(position)]
|
||||||
|
|
||||||
def get_colour(self):
|
|
||||||
if self.state is CellState.WALL:
|
|
||||||
return Colours.WALL
|
|
||||||
elif self.state is CellState.OPEN:
|
|
||||||
if self.resources > 0:
|
|
||||||
return Colours.STOCKED
|
|
||||||
elif self.resources == 0:
|
|
||||||
return Colours.DEPLETED
|
|
||||||
else:
|
|
||||||
return Colours.UNDEFINED
|
|
||||||
else:
|
|
||||||
return Colours.UNDEFINED
|
|
||||||
|
|
||||||
class Environment:
|
class Environment:
|
||||||
def __init__(self, shape):
|
def __init__(self, shape):
|
||||||
|
@ -46,41 +44,66 @@ class Environment:
|
||||||
np.random.normal(loc=50, scale=10, size=shape)
|
np.random.normal(loc=50, scale=10, size=shape)
|
||||||
)
|
)
|
||||||
|
|
||||||
cols, rows = shape
|
self.obstacle_map = np.hstack((
|
||||||
self.cells = [[] for _ in range(rows)]
|
np.ones((shape[0], 1)),
|
||||||
for y in range(rows):
|
np.vstack((
|
||||||
for x in range(cols):
|
np.ones((1, shape[1]-2)),
|
||||||
if (x == 0 or y == 0 or x+1==cols or y+1==rows):
|
np.zeros((shape[0]-2, shape[1]-2)),
|
||||||
self.cells[y].append(Cell(CellState.WALL, 0))
|
np.ones((1, shape[1]-2))
|
||||||
else:
|
)),
|
||||||
self.cells[y].append(Cell(CellState.OPEN, self.resource_map[x,y]))
|
np.ones((shape[0], 1))
|
||||||
|
))
|
||||||
|
|
||||||
|
print(self.obstacle_map)
|
||||||
|
print(self.obstacle_map.shape)
|
||||||
|
|
||||||
def step(self):
|
def step(self):
|
||||||
|
agent_map = np.zeros(self.shape)
|
||||||
for agent in self.agents:
|
for agent in self.agents:
|
||||||
agent.step()
|
agent_map[tuple(agent.position)] = 1
|
||||||
|
|
||||||
|
observations = Observations(
|
||||||
|
obstacles=self.obstacle_map,
|
||||||
|
resources=self.resource_map,
|
||||||
|
agents=agent_map
|
||||||
|
)
|
||||||
|
|
||||||
|
for agent in self.agents:
|
||||||
|
agent.step(observations)
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
cols, rows = self.shape
|
pixel_data = np.zeros(self.shape + (3,))
|
||||||
pixel_data = [[] for _ in range(rows)]
|
|
||||||
|
|
||||||
for y in range(self.shape[1]):
|
print(pixel_data.shape)
|
||||||
for x in range(self.shape[0]):
|
|
||||||
#print((x, y, self.cell((x,y)).state, self.cell((x,y)).get_colour().value))
|
pixel_data += (
|
||||||
pixel_data[y].append(self.cell((x,y)).get_colour().value)
|
((self.obstacle_map[..., np.newaxis] == 1) * np.array(Colours.WALL.value))
|
||||||
|
+ ((self.obstacle_map[..., np.newaxis] == 0) * (self.resource_map[..., np.newaxis] == 0) * np.array(Colours.DEPLETED.value))
|
||||||
|
+ ((self.obstacle_map[..., np.newaxis] == 0) * (self.resource_map[..., np.newaxis] > 0) * np.array(Colours.STOCKED.value))
|
||||||
|
)
|
||||||
|
|
||||||
|
print(pixel_data)
|
||||||
|
print(pixel_data.shape)
|
||||||
|
|
||||||
for agent in self.agents:
|
for agent in self.agents:
|
||||||
x, y = agent.position
|
pixel_data[tuple(agent.position)] = agent.get_colour()
|
||||||
pixel_data[y][x] = Colours.AGENT.value
|
|
||||||
|
|
||||||
return np.array(pixel_data)
|
return np.array(pixel_data).astype(np.uint8).swapaxes(0, 1)
|
||||||
|
|
||||||
|
def eat(self, position):
|
||||||
|
resources = self.resource_map[tuple(position)]
|
||||||
|
self.resource_map[tuple(position)] = 0
|
||||||
|
return resources
|
||||||
|
|
||||||
def cell(self, position):
|
def cell(self, position):
|
||||||
x, y = tuple(position)
|
x, y = tuple(position)
|
||||||
return self.cells[y][x]
|
return self.cells[y][x]
|
||||||
|
|
||||||
def is_wall(self, position):
|
def has_obstacle(self, position):
|
||||||
x, y = tuple(position)
|
return self.obstacle_map[tuple(position)] == 1
|
||||||
return self.cells[y][x].state == CellState.WALL
|
|
||||||
|
def has_agent(self, position):
|
||||||
|
return tuple(position) in {tuple(agent.position) for agent in self.agents}
|
||||||
|
|
||||||
def register_agent(self, agent):
|
def register_agent(self, agent):
|
||||||
self.agents.append(agent)
|
self.agents.append(agent)
|
||||||
|
@ -94,17 +117,22 @@ class Agent:
|
||||||
self.environment = environment
|
self.environment = environment
|
||||||
self.environment.register_agent(self)
|
self.environment.register_agent(self)
|
||||||
|
|
||||||
def step(self):
|
def step(self, _observations):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def move(self, direction, respect_walls=True):
|
def move(self, direction, respect_obstacles=True, respect_agents=True):
|
||||||
new_position = self.position + direction.value
|
new_position = self.position + direction.value
|
||||||
if respect_walls and self.environment.is_wall(new_position):
|
if respect_obstacles and self.environment.has_obstacle(new_position):
|
||||||
|
return False
|
||||||
|
elif respect_agents and self.environment.has_agent(new_position):
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
self.position = new_position
|
self.position = new_position
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def get_colour(self):
|
||||||
|
return Colours.AGENT.value
|
||||||
|
|
||||||
def die(self):
|
def die(self):
|
||||||
self.environment.unregister_agent(self)
|
self.environment.unregister_agent(self)
|
||||||
|
|
||||||
|
@ -113,16 +141,14 @@ class DirectionalAgent(Agent):
|
||||||
super().__init__(environment, position)
|
super().__init__(environment, position)
|
||||||
self.direction = initial_direction
|
self.direction = initial_direction
|
||||||
|
|
||||||
def get_cell_in_front(self):
|
def get_position_in_front(self):
|
||||||
position_in_front = self.position + self.direction.value
|
return self.position + self.direction.value
|
||||||
return self.environment.cell(position_in_front)
|
|
||||||
|
|
||||||
def wall_in_front(self):
|
def obstacle_in_front(self, observations):
|
||||||
position_in_front = self.position + self.direction.value
|
return observations.has_obstacle(self.get_position_in_front())
|
||||||
return self.environment.is_wall(position_in_front)
|
|
||||||
|
|
||||||
def agent_in_front(self):
|
def agent_in_front(self, observations):
|
||||||
return False
|
return observations.has_agent(self.get_position_in_front())
|
||||||
|
|
||||||
def move_forward(self):
|
def move_forward(self):
|
||||||
return self.move(self.direction)
|
return self.move(self.direction)
|
||||||
|
@ -173,12 +199,12 @@ class CAMSReverseAndSidestepAgent(DirectionalAgent):
|
||||||
self.required_resources = required_resources
|
self.required_resources = required_resources
|
||||||
self.number_of_turns = 0
|
self.number_of_turns = 0
|
||||||
|
|
||||||
def step(self):
|
def step(self, observations):
|
||||||
self.eat()
|
self.eat()
|
||||||
|
|
||||||
if self.wall_in_front():
|
if self.obstacle_in_front(observations):
|
||||||
# self.die()
|
self.die()
|
||||||
#elif self.agent_in_front():
|
elif self.agent_in_front(observations):
|
||||||
if self.number_of_turns == 0:
|
if self.number_of_turns == 0:
|
||||||
self.reverse_direction()
|
self.reverse_direction()
|
||||||
self.move_forward()
|
self.move_forward()
|
||||||
|
@ -187,12 +213,12 @@ class CAMSReverseAndSidestepAgent(DirectionalAgent):
|
||||||
self.turn_right()
|
self.turn_right()
|
||||||
self.move_forward()
|
self.move_forward()
|
||||||
self.turn_right()
|
self.turn_right()
|
||||||
self.number_of_turns == 0
|
self.number_of_turns = 0
|
||||||
elif self.resources >= self.required_resources:
|
elif self.resources >= self.required_resources:
|
||||||
self.resources -= self.required_resources
|
self.resources -= self.required_resources
|
||||||
new_agent = CAMSReverseAndSidestepAgent(
|
new_agent = CAMSReverseAndSidestepAgent(
|
||||||
environment=self.environment,
|
environment=self.environment,
|
||||||
position=(self.position + self.direction.value),
|
position=self.position,
|
||||||
initial_direction=self.direction,
|
initial_direction=self.direction,
|
||||||
required_resources=self.required_resources
|
required_resources=self.required_resources
|
||||||
)
|
)
|
||||||
|
@ -201,15 +227,20 @@ class CAMSReverseAndSidestepAgent(DirectionalAgent):
|
||||||
self.move_forward()
|
self.move_forward()
|
||||||
|
|
||||||
def eat(self):
|
def eat(self):
|
||||||
cell = self.environment.cell(self.position)
|
resources = self.environment.eat(self.position)
|
||||||
resources = cell.resources
|
|
||||||
|
|
||||||
if resources > 0:
|
if resources > 0:
|
||||||
self.resources += resources
|
self.resources += resources
|
||||||
cell.resources = 0
|
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_colour(self):
|
||||||
|
if self.number_of_turns == 0:
|
||||||
|
return [0, 255, 0]
|
||||||
|
elif self.number_of_turns == 1:
|
||||||
|
return [255, 0, 0]
|
||||||
|
else:
|
||||||
|
return Colours.UNDEFINED
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue