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)
Пример #2
0
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