class WanderingPeepo(Peepo): RADIUS = 100 WAN_LEFT = 'RON_wandering_left' WAN_RIGHT = 'RON_wandering_right' OBS_LEFT = 'RON_obstacle_left' OBS_RIGHT = 'RON_obstacle_right' MOT_LEFT = 'LEN_motor_left' MOT_RIGHT = 'LEN_motor_right' VIS_1 = 'LEN_vision_1' VIS_2 = 'LEN_vision_2' VIS_3 = 'LEN_vision_3' VIS_4 = 'LEN_vision_4' VIS_5 = 'LEN_vision_5' VIS_6 = 'LEN_vision_6' def __init__(self, peepo_actor, actors): super().__init__(self.create_model()) self.peepo_actor = peepo_actor self.actors = actors self.motor_output = {pg.K_LEFT: False, pg.K_RIGHT: False} self.obstacle_input = {'1': False, '2': False, '3': False, '4': False, '5': False, '6': False} self.wander_left_chance = 0 self.wander_right_chance = 0 self.wandering_left = False self.wandering_right = False self.genmodel = GenerativeModel(self) def action(self, node, prediction): # prediction [0.9, 0.1] = STOP # prediction [0.1, 0.9] = START if np.argmax(prediction) == 0: if 'left' in node: self.motor_output[pg.K_LEFT] = False if 'right' in node: self.motor_output[pg.K_RIGHT] = False else: if 'left' in node: self.motor_output[pg.K_LEFT] = True if 'right' in node: self.motor_output[pg.K_RIGHT] = True def observation(self, name): if 'vision' in name: # prediction [0.9, 0.1] = NO OBSTACLE # prediction [0.1, 0.9] = OBSTACLE if '1' in name: return np.array([0.1, 0.9]) if self.obstacle_input['1'] else np.array([0.9, 0.1]) if '2' in name: return np.array([0.1, 0.9]) if self.obstacle_input['2'] else np.array([0.9, 0.1]) if '3' in name: return np.array([0.1, 0.9]) if self.obstacle_input['3'] else np.array([0.9, 0.1]) if '4' in name: return np.array([0.1, 0.9]) if self.obstacle_input['4'] else np.array([0.9, 0.1]) if '5' in name: return np.array([0.1, 0.9]) if self.obstacle_input['5'] else np.array([0.9, 0.1]) if '6' in name: return np.array([0.1, 0.9]) if self.obstacle_input['6'] else np.array([0.9, 0.1]) elif 'motor' in name: # prediction [0.9, 0.1] = STOPPED # prediction [0.1, 0.9] = MOVING if 'left' in name: return np.array([0.1, 0.9]) if self.motor_output[pg.K_LEFT] else np.array([0.9, 0.1]) if 'right' in name: return np.array([0.1, 0.9]) if self.motor_output[pg.K_RIGHT] else np.array([0.9, 0.1]) def update(self): network = self.genmodel.bayesian_network # [0.9, 0.1] = OFF # [0.1, 0.9] = ON if self.wandering_left: state = network.states[self.genmodel.get_node_index(self.WAN_LEFT)] state.distribution = DiscreteDistribution(change_distribution(state.distribution.items(), [0.9, 0.1])) self.wander_left_chance = 0 self.wandering_left = False else: self.wander_left_chance += 0.1 if random.randint(0, 100) <= self.wander_left_chance: state = network.states[self.genmodel.get_node_index(self.WAN_LEFT)] state.distribution = DiscreteDistribution(change_distribution(state.distribution.items(), [0.1, 0.9])) self.wandering_left = True if self.wandering_right: state = network.states[self.genmodel.get_node_index(self.WAN_RIGHT)] state.distribution = DiscreteDistribution(change_distribution(state.distribution.items(), [0.9, 0.1])) self.wander_right_chance = 0 self.wandering_right = False else: self.wander_right_chance += 0.1 if random.randint(0, 100) <= self.wander_right_chance: state = network.states[self.genmodel.get_node_index(self.WAN_RIGHT)] state.distribution = DiscreteDistribution(change_distribution(state.distribution.items(), [0.1, 0.9])) self.wandering_right = True def create_model(self): pp_network = PeepoNetwork( ron_nodes=[ {'name': self.WAN_LEFT, 'card': 2}, {'name': self.WAN_RIGHT, 'card': 2}, {'name': self.OBS_LEFT, 'card': 2}, {'name': self.OBS_RIGHT, 'card': 2} ], ext_nodes=[ {'name': self.VIS_1, 'card': 2}, {'name': self.VIS_2, 'card': 2}, {'name': self.VIS_3, 'card': 2}, {'name': self.VIS_4, 'card': 2}, {'name': self.VIS_5, 'card': 2}, {'name': self.VIS_6, 'card': 2} ], pro_nodes=[ {'name': self.MOT_LEFT, 'card': 2}, {'name': self.MOT_RIGHT, 'card': 2} ], edges=[ (self.WAN_LEFT, self.MOT_LEFT), (self.WAN_RIGHT, self.MOT_RIGHT), (self.OBS_LEFT, self.MOT_RIGHT), (self.OBS_RIGHT, self.MOT_LEFT), (self.OBS_LEFT, self.VIS_1), (self.OBS_LEFT, self.VIS_2), (self.OBS_LEFT, self.VIS_3), (self.OBS_RIGHT, self.VIS_4), (self.OBS_RIGHT, self.VIS_5), (self.OBS_RIGHT, self.VIS_6), ], cpds={ self.WAN_LEFT: [0.9, 0.1], self.WAN_RIGHT: [0.9, 0.1], self.OBS_LEFT: [0.9, 0.1], self.OBS_RIGHT: [0.9, 0.1], self.VIS_1: [[0.9, 0.1], [0.1, 0.9]], self.VIS_2: [[0.9, 0.1], [0.1, 0.9]], self.VIS_3: [[0.9, 0.1], [0.1, 0.9]], self.VIS_4: [[0.9, 0.1], [0.1, 0.9]], self.VIS_5: [[0.9, 0.1], [0.1, 0.9]], self.VIS_6: [[0.9, 0.1], [0.1, 0.9]], self.MOT_LEFT: [[0.9, 0.1, 0.1, 0.1], [0.1, 0.9, 0.9, 0.9]], self.MOT_RIGHT: [[0.9, 0.1, 0.1, 0.1], [0.1, 0.9, 0.9, 0.9]], }) pp_network.assemble() return pp_network def process(self): self.calculate_obstacles() self.genmodel.process() def calculate_obstacles(self): for key in self.obstacle_input: self.obstacle_input[key] = False for actor in self.actors: peepo_vec = vec(self.peepo_actor.rect.center) collided = collision(actor.rect, peepo_vec, self.peepo_actor.edge_left, self.peepo_actor.edge_right, WanderingPeepo.RADIUS) if collided: if 'wall' in actor.id: edge = end_line(WanderingPeepo.RADIUS, self.peepo_actor.rotation, self.peepo_actor.rect.center) if 'left' in actor.id: wall_vec = vec((5, self.peepo_actor.rect.y)) deg = math.degrees( math.atan2(wall_vec.y - edge.y, wall_vec.x - edge.x)) + self.peepo_actor.rotation if deg < 0: self.obstacle_input['6'] = True else: self.obstacle_input['1'] = True elif 'right' in actor.id: wall_vec = vec((1598, self.peepo_actor.rect.y)) deg = math.degrees( math.atan2(wall_vec.y - edge.y, wall_vec.x - edge.x)) + self.peepo_actor.rotation if deg < 0: self.obstacle_input['1'] = True else: self.obstacle_input['6'] = True elif 'up' in actor.id: wall_vec = vec((5, self.peepo_actor.rect.y)) deg = math.degrees( math.atan2(wall_vec.y - edge.y, wall_vec.x - edge.x)) + self.peepo_actor.rotation if deg < 90: self.obstacle_input['6'] = True else: self.obstacle_input['1'] = True else: wall_vec = vec((5, self.peepo_actor.rect.y)) deg = math.degrees( math.atan2(wall_vec.y - edge.y, wall_vec.x - edge.x)) + self.peepo_actor.rotation if deg < -90: self.obstacle_input['6'] = True else: self.obstacle_input['1'] = True else: edge1 = end_line(WanderingPeepo.RADIUS, self.peepo_actor.rotation - 30, self.peepo_actor.rect.center) edge2 = end_line(WanderingPeepo.RADIUS, self.peepo_actor.rotation - 20, self.peepo_actor.rect.center) edge3 = end_line(WanderingPeepo.RADIUS, self.peepo_actor.rotation - 10, self.peepo_actor.rect.center) edge4 = end_line(WanderingPeepo.RADIUS, self.peepo_actor.rotation, self.peepo_actor.rect.center) edge5 = end_line(WanderingPeepo.RADIUS, self.peepo_actor.rotation + 10, self.peepo_actor.rect.center) edge6 = end_line(WanderingPeepo.RADIUS, self.peepo_actor.rotation + 20, self.peepo_actor.rect.center) edge7 = end_line(WanderingPeepo.RADIUS, self.peepo_actor.rotation + 30, self.peepo_actor.rect.center) self.obstacle_input['1'] = collision(actor.rect, peepo_vec, edge1, edge2, WanderingPeepo.RADIUS) self.obstacle_input['2'] = collision(actor.rect, peepo_vec, edge2, edge3, WanderingPeepo.RADIUS) self.obstacle_input['3'] = collision(actor.rect, peepo_vec, edge3, edge4, WanderingPeepo.RADIUS) self.obstacle_input['4'] = collision(actor.rect, peepo_vec, edge4, edge5, WanderingPeepo.RADIUS) self.obstacle_input['5'] = collision(actor.rect, peepo_vec, edge5, edge6, WanderingPeepo.RADIUS) self.obstacle_input['6'] = collision(actor.rect, peepo_vec, edge6, edge7, WanderingPeepo.RADIUS)
class AntPeepo(Peepo): """ This organism represents peepo. """ SIZE = (4, 4) RADIUS = 50 SPEED = 2 def __init__(self, name, network, graphical, pos=(0, 0)): super().__init__(network) self.graphical = graphical self.name = name self.rect = pg.Rect(pos, AntPeepo.SIZE) self.rect.center = pos self.rotation = 0 if self.graphical: self.image = self.make_image() self.image_original = self.image.copy() self.motor = {LEFT: False, RIGHT: False} self.generative_model = GenerativeModel(self, n_jobs=1) self.path = [] def observation(self, name): if MOTOR.lower() in name.lower(): return [0.1, 0.9 ] if self.motor[self.get_direction(name)] else [0.9, 0.1] return [0.5, 0.5] def action(self, node, prediction): if np.argmax(prediction) == 0: self.motor[self.get_direction(node)] = False else: self.motor[self.get_direction(node)] = True @staticmethod def get_direction(name): for direction in [LEFT, RIGHT]: if direction.lower() in name.lower(): return direction raise ValueError('Unexpected node name %s, could not find LEFT, RIGHT', name) def update(self): self.generative_model.process() self.drift_hypotheses() self.rect.x += AntPeepo.SPEED * math.cos(math.radians(self.rotation)) self.rect.y += AntPeepo.SPEED * math.sin(math.radians(self.rotation)) if self.motor[LEFT]: self.rotation -= 10 if self.rotation < 0: self.rotation = 360 if self.motor[RIGHT]: self.rotation += 10 if self.rotation > 360: self.rotation = 0 if self.graphical: self.image = pg.transform.rotate(self.image_original, -self.rotation) self.rect = self.image.get_rect(center=self.rect.center) if self.rect.x < 0: self.rect.x = 799 if self.rect.x > 800: self.rect.x = 1 if self.rect.y < 0: self.rect.y = 799 if self.rect.y > 800: self.rect.y = 1 self.path.append((self.rect.x, self.rect.y)) def drift_hypotheses(self): for root in self.generative_model.get_roots(): root_index = self.generative_model.get_node_index(root.name) if random.choice([0, 1]): old_hypo = self.generative_model.bayesian_network.states[ root_index].distribution.items() moving = [old_hypo[0][1], old_hypo[1][1]] if np.argmax(moving): # ~ [0.1, 0.9] -> [0.9, 0.1] change = 0.05 if moving[1] - change < 0.1: moving = [0.9, 0.1] else: moving = [moving[0] + change, moving[1] - change] else: # ~ [0.9, 0.1] -> [0.1, 0.9] change = 0.1 if moving[0] - change < 0.1: moving = [0.1, 0.9] else: moving = [moving[0] - change, moving[1] + change] new_hypo = {0: moving[0], 1: moving[1]} self.generative_model.bayesian_network.states[ root_index].distribution = DiscreteDistribution(new_hypo) def draw(self, surface): surface.blit(self.image, self.rect) for step in self.path: surface.set_at(step, pg.Color("red")) def make_image(self): image = pg.Surface(self.rect.size).convert_alpha() image.fill(TRANSPARENT) image_rect = image.get_rect() pg.draw.rect(image, pg.Color("black"), image_rect) pg.draw.rect(image, pg.Color("green"), image_rect.inflate(-2, -2)) return image