Browse Source

Pheromone: object model

Bastien Sevajol 9 years ago
parent
commit
af8f3c0bd4

+ 8 - 0
intelligine/core/exceptions.py View File

18
     pass
18
     pass
19
 
19
 
20
 
20
 
21
+class NoTypeInPheromone(NoPheromone):
22
+    pass
23
+
24
+
25
+class NoCategoryInPheromone(NoPheromone):
26
+    pass
27
+
28
+
21
 class BestPheromoneHere(PheromoneException):
29
 class BestPheromoneHere(PheromoneException):
22
 
30
 
23
     def __init__(self, best_distance,  *args, **kwargs):
31
     def __init__(self, best_distance,  *args, **kwargs):

+ 11 - 18
intelligine/display/Pygame.py View File

1
+from intelligine.core.exceptions import NoPheromone
1
 from xyzworld.display.Pygame import Pygame as XyzPygame
2
 from xyzworld.display.Pygame import Pygame as XyzPygame
2
 import pygame
3
 import pygame
3
 from intelligine.cst import PHEROMON_INFOS, PHEROMON_DIRECTION, PHEROMON_DIR_HOME, PHEROMON_DIR_EXPLO, PHEROMON_POSITIONS
4
 from intelligine.cst import PHEROMON_INFOS, PHEROMON_DIRECTION, PHEROMON_DIR_HOME, PHEROMON_DIR_EXPLO, PHEROMON_POSITIONS
11
         super().__init__(config, context)
12
         super().__init__(config, context)
12
         self._is_display_pheromones = False
13
         self._is_display_pheromones = False
13
 
14
 
14
-
15
     def receive(self, synergy_object_manager, context):
15
     def receive(self, synergy_object_manager, context):
16
         super().receive(synergy_object_manager, context)
16
         super().receive(synergy_object_manager, context)
17
         if self._is_display_pheromones:
17
         if self._is_display_pheromones:
18
             self._display_pheromones(context.metas.list.get(PHEROMON_POSITIONS, PHEROMON_POSITIONS, allow_empty=True), context)
18
             self._display_pheromones(context.metas.list.get(PHEROMON_POSITIONS, PHEROMON_POSITIONS, allow_empty=True), context)
19
 
19
 
20
     def _display_pheromones(self, pheromones_positions, context):
20
     def _display_pheromones(self, pheromones_positions, context):
21
+        # TODO: Code de test bordelique !
21
         for point in pheromones_positions:
22
         for point in pheromones_positions:
22
-            exploration_info = context.pheromones().get_info(point,
23
-                                                             [PHEROMON_DIRECTION,
24
-                                                              PHEROMON_DIR_HOME],
25
-                                                             allow_empty=True,
26
-                                                             empty_value={})
27
-
28
-            # TODO: ne pas avoir a creer d'objet, voir comment dans display
29
-            if exploration_info:
23
+            flavour = context.pheromones().get_flavour(point)
24
+            try:
25
+                flavour.get_pheromone(category=PHEROMON_DIRECTION, type=PHEROMON_DIR_HOME)
30
                 pheromon = PheromonHome(object(), context)
26
                 pheromon = PheromonHome(object(), context)
31
                 pheromon.set_direction(11) # TODO: plus de direction avec ces nlles pheromones
27
                 pheromon.set_direction(11) # TODO: plus de direction avec ces nlles pheromones
32
                 self._draw_objects_with_decal(point, [pheromon])
28
                 self._draw_objects_with_decal(point, [pheromon])
33
-
34
-
35
-            exploration_info = context.pheromones().get_info(point,
36
-                                                             [PHEROMON_DIRECTION,
37
-                                                              PHEROMON_DIR_EXPLO],
38
-                                                             allow_empty=True,
39
-                                                             empty_value={})
40
-            if exploration_info:
41
-                # TODO: ne pas avoir a creer d'objet, voir comment dans display
29
+            except NoPheromone:
30
+                pass
31
+            try:
32
+                flavour.get_pheromone(category=PHEROMON_DIRECTION, type=PHEROMON_DIR_EXPLO)
42
                 pheromon = PheromonExploration(object(), context)
33
                 pheromon = PheromonExploration(object(), context)
43
                 pheromon.set_direction(11) # TODO: plus de direction avec ces nlles pheromones
34
                 pheromon.set_direction(11) # TODO: plus de direction avec ces nlles pheromones
44
                 self._draw_objects_with_decal(point, [pheromon])
35
                 self._draw_objects_with_decal(point, [pheromon])
36
+            except NoPheromone:
37
+                pass
45
 
38
 
46
     def _key_pressed(self, key):
39
     def _key_pressed(self, key):
47
         if key == pygame.K_p:
40
         if key == pygame.K_p:

+ 4 - 3
intelligine/simulation/object/pheromone/MovementPheromoneGland.py View File

1
+from intelligine.cst import PHEROMON_DIRECTION
1
 from intelligine.simulation.object.pheromone.PheromoneGland import PheromoneGland
2
 from intelligine.simulation.object.pheromone.PheromoneGland import PheromoneGland
3
+from intelligine.simulation.pheromone.Pheromone import Pheromone
2
 
4
 
3
 
5
 
4
 class MovementPheromoneGland(PheromoneGland):
6
 class MovementPheromoneGland(PheromoneGland):
5
 
7
 
6
-
7
-    def get_movement_molecules(self):
8
+    def get_pheromone(self):
8
         """
9
         """
9
         :return: pheromone_type, distance_from_objective
10
         :return: pheromone_type, distance_from_objective
10
         """
11
         """
11
-        return self._pheromone_type, self._host.get_brain().get_distance_from_objective()
12
+        return Pheromone(PHEROMON_DIRECTION, self._pheromone_type, self._host.get_brain().get_distance_from_objective(), 1)

+ 4 - 1
intelligine/simulation/object/pheromone/PheromoneGland.py View File

16
             raise Exception("pheromone_type not specified")
16
             raise Exception("pheromone_type not specified")
17
         return self._pheromone_type
17
         return self._pheromone_type
18
 
18
 
19
+    def get_pheromone(self):
20
+        raise NotImplementedError()
21
+
19
     def appose(self):
22
     def appose(self):
20
         try:
23
         try:
21
             DirectionPheromone.appose(self._context,
24
             DirectionPheromone.appose(self._context,
22
                                       self._host.get_position(),
25
                                       self._host.get_position(),
23
-                                      self._host.get_movement_pheromone_gland().get_movement_molecules())
26
+                                      self.get_pheromone())
24
         except BestPheromoneHere as best_pheromone_here:
27
         except BestPheromoneHere as best_pheromone_here:
25
             self._host.get_brain().set_distance_from_objective(best_pheromone_here.get_best_distance())
28
             self._host.get_brain().set_distance_from_objective(best_pheromone_here.get_best_distance())

+ 26 - 31
intelligine/simulation/pheromone/DirectionPheromone.py View File

8
 class DirectionPheromone():
8
 class DirectionPheromone():
9
 
9
 
10
     @staticmethod
10
     @staticmethod
11
-    def appose(context, point, movement_molecules):
12
-        pheromone_type, distance_from = movement_molecules
13
-        context.pheromones().increment(point, [PHEROMON_DIRECTION, pheromone_type], distance=distance_from)
11
+    def appose(context, point, pheromone):
12
+        context.pheromones().increment_with_pheromone(point, pheromone)
14
         context.metas.list.add(PHEROMON_POSITIONS, PHEROMON_POSITIONS, point, assert_not_in=False)
13
         context.metas.list.add(PHEROMON_POSITIONS, PHEROMON_POSITIONS, point, assert_not_in=False)
15
 
14
 
16
     @staticmethod
15
     @staticmethod
17
     def get_direction_for_point(context, point, pheromone_type):
16
     def get_direction_for_point(context, point, pheromone_type):
18
-        try:
19
-            pheromone_info = context.pheromones().get_info(point, [PHEROMON_DIRECTION, pheromone_type])
20
-        except KeyError:
21
-            raise NoPheromone()
22
-
23
-        # DEBUG: On se rettrouve avec un {} ...
24
-        if not pheromone_info:
25
-            raise NoPheromone()
17
+        flavour = context.pheromones().get_flavour(point)
18
+        pheromone = flavour.get_pheromone(category=PHEROMON_DIRECTION, type=pheromone_type)
26
 
19
 
27
-        point_intensity = pheromone_info[1]
28
-        point_distance = pheromone_info[0]
20
+        distance = pheromone.get_distance()
29
         around_points = context.get_around_points_of(point)
21
         around_points = context.get_around_points_of(point)
30
-
22
+        # TODO: Cet algo around a mettre ailleurs
31
         around_pheromones_points = []
23
         around_pheromones_points = []
32
         for around_point in around_points:
24
         for around_point in around_points:
33
-            around_pheromone_info = context.pheromones().get_info(around_point,
34
-                                                                   [PHEROMON_DIRECTION, pheromone_type],
35
-                                                                   allow_empty=True,
36
-                                                                   empty_value={})
37
-            if around_pheromone_info and around_pheromone_info[0] < point_distance:
38
-                around_pheromones_points.append((around_point, around_pheromone_info))
25
+            flavour = context.pheromones().get_flavour(around_point)
26
+            try:
27
+                around_pheromone = flavour.get_pheromone(category=PHEROMON_DIRECTION, type=pheromone_type)
28
+                if around_pheromone.get_distance() < distance:
29
+                    around_pheromones_points.append((around_point, around_pheromone))
30
+            except NoPheromone:
31
+                pass  # No pheromone, ok continue to sniff around
39
 
32
 
40
         if not around_pheromones_points:
33
         if not around_pheromones_points:
41
             raise NoPheromone()
34
             raise NoPheromone()
42
 
35
 
43
         shuffle(around_pheromones_points)
36
         shuffle(around_pheromones_points)
44
-        around_pheromones_sorted = sorted(around_pheromones_points, key=lambda x: x[1][1], reverse=True)
45
-        max_intensity = around_pheromones_sorted[0][1][1]
37
+        around_pheromones_sorted = sorted(around_pheromones_points, key=lambda x: x[1].get_intensity(), reverse=True)
38
+        max_intensity = around_pheromones_sorted[0][1].get_intensity()
46
 
39
 
47
         around_pheromones_max = []
40
         around_pheromones_max = []
48
         for around_pheromone_sorted in around_pheromones_sorted:
41
         for around_pheromone_sorted in around_pheromones_sorted:
49
-            if around_pheromone_sorted[1][1] == max_intensity:
42
+            if around_pheromone_sorted[1].get_intensity() == max_intensity:
50
                 around_pheromones_max.append(around_pheromone_sorted)
43
                 around_pheromones_max.append(around_pheromone_sorted)
51
 
44
 
52
-        around_pheromones_sorted_by_distance = sorted(around_pheromones_max, key=lambda x: x[1][0], reverse=False)
45
+        around_pheromones_sorted_by_distance = sorted(around_pheromones_max,
46
+                                                      key=lambda x: x[1].get_distance(),
47
+                                                      reverse=False)
53
 
48
 
54
         go_to_point = around_pheromones_sorted_by_distance[0][0]
49
         go_to_point = around_pheromones_sorted_by_distance[0][0]
55
 
50
 
76
     def get_best_pheromone_direction_in(context, reference_point, points, pheromone_type):
71
     def get_best_pheromone_direction_in(context, reference_point, points, pheromone_type):
77
         around_pheromones_points = []
72
         around_pheromones_points = []
78
         for around_point in points:
73
         for around_point in points:
79
-            around_pheromone_info = context.pheromones().get_info(around_point,
80
-                                                                   [PHEROMON_DIRECTION, pheromone_type],
81
-                                                                   allow_empty=True,
82
-                                                                   empty_value={})
83
-            if around_pheromone_info:
84
-                around_pheromones_points.append((around_point, around_pheromone_info))
74
+            flavour = context.pheromones().get_flavour(around_point)
75
+            try:
76
+                around_pheromone = flavour.get_pheromone(category=PHEROMON_DIRECTION, type=pheromone_type)
77
+                around_pheromones_points.append((around_point, around_pheromone))
78
+            except NoPheromone:
79
+                pass  # Ok, no pheromone, continue to sniff around
85
 
80
 
86
         if not around_pheromones_points:
81
         if not around_pheromones_points:
87
             raise NoPheromone()
82
             raise NoPheromone()
88
 
83
 
89
         shuffle(around_pheromones_points)
84
         shuffle(around_pheromones_points)
90
-        around_pheromones_sorted = sorted(around_pheromones_points, key=lambda x: x[1][1], reverse=True)
85
+        around_pheromones_sorted = sorted(around_pheromones_points, key=lambda x: x[1].get_intensity(), reverse=True)
91
         go_to_point = around_pheromones_sorted[0][0]
86
         go_to_point = around_pheromones_sorted[0][0]
92
 
87
 
93
         direction_degrees = get_degree_from_north(reference_point, go_to_point)
88
         direction_degrees = get_degree_from_north(reference_point, go_to_point)

+ 24 - 1
intelligine/simulation/pheromone/Pheromone.py View File

1
 class Pheromone():
1
 class Pheromone():
2
-    pass
2
+
3
+    def __init__(self, category, type, distance=None, intensity=0):
4
+        self._category = category
5
+        self._type = type
6
+        self._distance = distance
7
+        self._intensity = intensity
8
+
9
+    def get_category(self):
10
+        return self._category
11
+
12
+    def get_type(self):
13
+        return self._type
14
+
15
+    def get_distance(self):
16
+        return self._distance
17
+
18
+    def set_distance(self, distance):
19
+        self._distance = distance
20
+
21
+    def get_intensity(self):
22
+        return self._intensity
23
+
24
+    def increment_intensity(self, increment_value):
25
+        self._intensity += increment_value

+ 31 - 1
intelligine/simulation/pheromone/PheromoneFlavour.py View File

1
+from intelligine.core.exceptions import NoTypeInPheromone, NoCategoryInPheromone
2
+from intelligine.simulation.pheromone.Pheromone import Pheromone
3
+
4
+
1
 class PheromoneFlavour():
5
 class PheromoneFlavour():
2
-    pass
6
+
7
+    def __init__(self, point_data):
8
+        self._point_data = point_data
9
+
10
+    def get_pheromone(self, category, type):
11
+        types = self.get_types(category)
12
+        if type not in types:
13
+            raise NoTypeInPheromone()
14
+        distance, intensity = types[type]
15
+        return Pheromone(category, type, distance, intensity)
16
+
17
+    def get_types(self, category):
18
+        if category not in self._point_data:
19
+            raise NoCategoryInPheromone()
20
+        return self._point_data[category]
21
+
22
+    def update_pheromone(self, pheromone):
23
+        category = pheromone.get_category()
24
+        type = pheromone.get_type()
25
+
26
+        if category not in self._point_data:
27
+            self._point_data[category] = {}
28
+
29
+        self._point_data[category][type] = (pheromone.get_distance(), pheromone.get_intensity())
30
+
31
+    def get_raw_data(self):
32
+        return self._point_data

+ 1 - 3
intelligine/synergy/object/ant/Ant.py View File

77
     def initialize(self):
77
     def initialize(self):
78
         super().initialize()
78
         super().initialize()
79
         try:
79
         try:
80
-            DirectionPheromone.appose(self._context,
81
-                                      self.get_position(),
82
-                                      self.get_movement_pheromone_gland().get_movement_molecules())
80
+            self.get_movement_pheromone_gland().appose()
83
         except BestPheromoneHere as best_pheromone_here:
81
         except BestPheromoneHere as best_pheromone_here:
84
             pass
82
             pass
85
 
83
 

+ 33 - 29
intelligine/synergy/stigmergy/PheromonesManager.py View File

1
-from intelligine.core.exceptions import BestPheromoneHere
1
+from intelligine.core.exceptions import BestPheromoneHere, NoPheromone
2
 from intelligine.cst import PHEROMON_INFOS
2
 from intelligine.cst import PHEROMON_INFOS
3
-from intelligine.core.exceptions import NoPheromone
3
+from intelligine.simulation.pheromone.PheromoneFlavour import PheromoneFlavour
4
+from intelligine.simulation.pheromone.Pheromone import Pheromone
4
 
5
 
5
 
6
 
6
 class PheromonesManager():
7
 class PheromonesManager():
8
     def __init__(self, context):
9
     def __init__(self, context):
9
         self._context = context
10
         self._context = context
10
 
11
 
11
-    def get_pheromones(self, position, prepare=[]):
12
+    def get_flavour(self, position):
12
         point_pheromones = self._context.metas.value.get(PHEROMON_INFOS,
13
         point_pheromones = self._context.metas.value.get(PHEROMON_INFOS,
13
                                                          position,
14
                                                          position,
14
                                                          allow_empty=True,
15
                                                          allow_empty=True,
15
                                                          empty_value={})
16
                                                          empty_value={})
17
+        return PheromoneFlavour(point_pheromones)
18
+
16
         current_check = point_pheromones
19
         current_check = point_pheromones
17
         for prepare_key in prepare:
20
         for prepare_key in prepare:
18
             if prepare_key not in current_check:
21
             if prepare_key not in current_check:
21
 
24
 
22
         return point_pheromones
25
         return point_pheromones
23
 
26
 
24
-    def set_pheromones(self, position, pheromones):
25
-        self._context.metas.value.set(PHEROMON_INFOS, position, pheromones)
27
+    def set_flavour(self, position, flavour):
28
+        self._context.metas.value.set(PHEROMON_INFOS, position, flavour.get_raw_data())
29
+
30
+    def get_pheromone(self, position, category, type, allow_empty=False, empty_value=None):
31
+        # TODO: empty_value as du sens ?
32
+        flavour = self.get_flavour(position)
33
+        try:
34
+            return flavour.get_pheromone(category, type)
35
+        except NoPheromone:
36
+            if allow_empty:
37
+                return Pheromone()
38
+            raise
26
 
39
 
27
-    def get_info(self, position, address, allow_empty=False, empty_value=None):
28
-        pheromones = self.get_pheromones(position, address[:-1])
29
 
40
 
30
         pheromone = pheromones
41
         pheromone = pheromones
31
         for key in address[:-1]:
42
         for key in address[:-1]:
39
 
50
 
40
         return pheromone[address[-1]]
51
         return pheromone[address[-1]]
41
 
52
 
42
-    def increment(self, position, address, distance, increment_value=1):
43
-        pheromones = self.get_pheromones(position, address[:-1])
44
-
45
-        pheromone = pheromones
46
-        for key in address[:-1]:
47
-            pheromone = pheromone[key]
48
-
49
-        if address[-1] not in pheromone:
50
-            pheromone[address[-1]] = (distance, 0)
51
-        # On se retrouve avec un {} dans pheromone[address[-1]]. A cause de la recherche de pheromone avant (et main process)
52
-        if not pheromone[address[-1]]:
53
-            pheromone[address[-1]] = (distance, 0)
54
-
55
-        pheromone_distance = pheromone[address[-1]][0]
56
-        pheromone_intensity = pheromone[address[-1]][1]
53
+    def increment_with_pheromone(self, position, apposed_pheromone):
54
+        flavour = self.get_flavour(position)
55
+        try:
56
+            position_pheromone = flavour.get_pheromone(apposed_pheromone.get_category(), apposed_pheromone.get_type())
57
+        except NoPheromone:
58
+            position_pheromone = Pheromone(apposed_pheromone.get_category(),
59
+                                           apposed_pheromone.get_type(),
60
+                                           distance=apposed_pheromone.get_distance())
57
 
61
 
58
-        pheromone_intensity += increment_value
62
+        position_pheromone.increment_intensity(apposed_pheromone.get_intensity())
59
 
63
 
60
-        if distance < pheromone_distance:
61
-            pheromone_distance = distance
64
+        if apposed_pheromone.get_distance() < position_pheromone.get_distance():
65
+            position_pheromone.set_distance(apposed_pheromone.get_distance())
62
 
66
 
63
-        pheromone[address[-1]] = (pheromone_distance, pheromone_intensity)
64
-        self.set_pheromones(position, pheromones)
67
+        flavour.update_pheromone(position_pheromone)
68
+        self.set_flavour(position, flavour)
65
 
69
 
66
-        if distance > pheromone_distance:
67
-            raise BestPheromoneHere(pheromone_distance)
70
+        if apposed_pheromone.get_distance() > position_pheromone.get_distance():
71
+            raise BestPheromoneHere(position_pheromone.get_distance())

+ 2 - 2
intelligine/tests/simulation/mode/TestChangeMode.py View File

96
 
96
 
97
         self._run_and_get_core(2)
97
         self._run_and_get_core(2)
98
         self.assertEquals((0, 0, -2), self.ant.get_position())
98
         self.assertEquals((0, 0, -2), self.ant.get_position())
99
-        self.assertEquals((PHEROMON_DIR_EXPLO, 0),
100
-                          self.ant.get_movement_pheromone_gland().get_movement_molecules())
99
+        pheromone = self.ant.get_movement_pheromone_gland().get_pheromone()
100
+        self.assertEquals((PHEROMON_DIR_EXPLO, 0), (pheromone.get_type(), pheromone.get_distance()))
101
 
101
 
102
         # Ant has take Food piece
102
         # Ant has take Food piece
103
         self._run_and_get_core(3)
103
         self._run_and_get_core(3)

+ 9 - 4
intelligine/tests/simulation/pheromone/TestDirection.py View File

1
 from os import getcwd
1
 from os import getcwd
2
 from sys import path as ppath
2
 from sys import path as ppath
3
 from intelligine.core.exceptions import NoPheromone
3
 from intelligine.core.exceptions import NoPheromone
4
+from intelligine.simulation.pheromone.Pheromone import Pheromone
5
+from intelligine.simulation.pheromone.PheromoneFlavour import PheromoneFlavour
4
 
6
 
5
 ppath.insert(1,getcwd()+'/modules')
7
 ppath.insert(1,getcwd()+'/modules')
6
 
8
 
26
         if re_init:
28
         if re_init:
27
             self._context = Context()
29
             self._context = Context()
28
         for position in pheromones:
30
         for position in pheromones:
29
-            self._context.pheromones().set_pheromones(position, pheromones[position])
31
+            self._context.pheromones().set_flavour(position, PheromoneFlavour(pheromones[position]))
30
 
32
 
31
     def _test_direction_for_point(self, pheromones, direction, pheromone_type=PHEROMON_DIR_EXPLO,
33
     def _test_direction_for_point(self, pheromones, direction, pheromone_type=PHEROMON_DIR_EXPLO,
32
                                   reference_point=_p(CENTER), re_init=True):
34
                                   reference_point=_p(CENTER), re_init=True):
207
         # Une pheromone au centre
209
         # Une pheromone au centre
208
         DirectionPheromone.appose(self._context,
210
         DirectionPheromone.appose(self._context,
209
                                   _p(CENTER),
211
                                   _p(CENTER),
210
-                                  (PHEROMON_DIR_EXPLO, 2))
212
+                                  self._get_pheromone(PHEROMON_DIR_EXPLO, 2))
211
         # Ne permet pas de trouver une route
213
         # Ne permet pas de trouver une route
212
         self._test_point_raise_no_pheromone(re_init=False)
214
         self._test_point_raise_no_pheromone(re_init=False)
213
         self._test_points_raise_no_pheromone(re_init=False)
215
         self._test_points_raise_no_pheromone(re_init=False)
215
         # Une pheromone au nord
217
         # Une pheromone au nord
216
         DirectionPheromone.appose(self._context,
218
         DirectionPheromone.appose(self._context,
217
                                   _p(NORTH),
219
                                   _p(NORTH),
218
-                                  (PHEROMON_DIR_EXPLO, 1))
220
+                                  self._get_pheromone(PHEROMON_DIR_EXPLO, 1))
219
         # le permet
221
         # le permet
220
         self._test_direction_for_points({}, NORTH, re_init=False)
222
         self._test_direction_for_points({}, NORTH, re_init=False)
221
         self._test_direction_for_point({}, NORTH, re_init=False)
223
         self._test_direction_for_point({}, NORTH, re_init=False)
233
         try:  # WTF ?
235
         try:  # WTF ?
234
             self._test_direction_for_points(pheromones, direction, re_init=re_init)
236
             self._test_direction_for_points(pheromones, direction, re_init=re_init)
235
         except NoPheromone:
237
         except NoPheromone:
236
-            self.assertTrue(True)
238
+            self.assertTrue(True)
239
+
240
+    def _get_pheromone(self, type, distance):
241
+        return Pheromone(PHEROMON_DIRECTION, type, distance=distance)