Browse Source

dirty but working code for pheromone food exploration

Bastien Sevajol 9 years ago
parent
commit
034f90c16e
32 changed files with 489 additions and 178 deletions
  1. 30 0
      TODO
  2. 13 6
      config.py
  3. 18 1
      intelligine/core/exceptions.py
  4. 3 0
      intelligine/cst.py
  5. 5 8
      intelligine/display/Pygame.py
  6. BIN
      intelligine/display/pygame/image/food.png
  7. BIN
      intelligine/display/pygame/image/hole.png
  8. BIN
      intelligine/display/pygame/image/phee (copie).png
  9. BIN
      intelligine/display/pygame/image/phee.png
  10. BIN
      intelligine/display/pygame/image/pheh (copie).png
  11. BIN
      intelligine/display/pygame/image/pheh.png
  12. BIN
      intelligine/display/pygame/image/rock.png
  13. BIN
      intelligine/display/pygame/image/rock_old.png
  14. 5 0
      intelligine/display/pygame/visualisation.py
  15. 4 3
      intelligine/sandbox/exploration/ColonyConfiguration.py
  16. 10 1
      intelligine/sandbox/exploration/map2.tmx
  17. 37 0
      intelligine/simulation/object/brain/AntBrain.py
  18. 5 0
      intelligine/simulation/object/brain/Brain.py
  19. 11 0
      intelligine/simulation/object/pheromone/MovementPheromoneGland.py
  20. 13 0
      intelligine/simulation/object/pheromone/PheromoneGland.py
  21. 107 0
      intelligine/simulation/pheromone/DirectionPheromone.py
  22. 1 1
      intelligine/synergy/Colony.py
  23. 156 25
      intelligine/synergy/event/move/MoveAction.py
  24. 9 9
      intelligine/synergy/event/move/direction.py
  25. 0 65
      intelligine/synergy/event/pheromone/ApposeDirection.py
  26. 0 26
      intelligine/synergy/event/pheromone/DetermineDirection.py
  27. 0 15
      intelligine/synergy/event/pheromone/PheromoneEvent.py
  28. 9 1
      intelligine/synergy/object/BaseBug.py
  29. 2 3
      intelligine/synergy/object/Food.py
  30. 5 0
      intelligine/synergy/object/Hole.py
  31. 23 8
      intelligine/synergy/object/ant/Ant.py
  32. 23 6
      intelligine/synergy/stigmergy/PheromonesManager.py

+ 30 - 0
TODO View File

@@ -0,0 +1,30 @@
1
+Warning:
2
+ * Lorsque une f trp un objet, l'event PUtableEvent observe cjaque tours. C parce que la fourmis rentre dans les clous
3
+ (carrying). Mais le mechanisme n'a rien trouve: on peux economier les observe dans ce cas la.
4
+
5
+Pheromones:
6
+
7
+ * Une pheromone doit transporter les données:
8
+ ** Direction
9
+ ** Intensité (cumul des pheromones identique, ou depot plus puissant)
10
+ ** Age (exprimé en "pas"/"nb de cases" depuis l'objectif (colonie/nourriture).
11
+
12
+ * Une fourmis ne pose de pheromone que sur la case ou elle se trouve.
13
+ * Une fourmis ne lit de pheromone que sur la case ou elle se trouve.
14
+ ** Si il n'y en a pas elle regarde sur les cases autour d'elle
15
+ *** Si il y a une pheromone (si plusieurs choisir la plus forte, et parmis les plus forte la plus recente (distance))
16
+ **** Aller dessus, repdrendre depuis "*".
17
+
18
+BUGS:
19
+ * Comme c'est une action qui pose les pheromones, elle survient parfois avant le mouvement. La direction ne pointe
20
+ alors pas vers la ou il faut. Le depot de pheromone doit etre declenché par l'action de mouvement effectué.
21
+
22
+
23
+NOTE:
24
+ * Lorsque une fourmis prend un Food; Elle effectue un deplacement en meme temps. Ce qui fait qu'elle va
25
+   se retrouver a 2 case (?) de la derniere trace de pheromone.aa
26
+
27
+Questions en suspens:
28
+  * Pour limiter la quantité de données, lorsque l'on pose une pheromone pour la direction x, peut-on (au lieu d'ajouter une nouvelle pheromone avec l'age préci) redescendre l'age de la pheromone precedente a l'age en cours.
29
+    Ex: Directions: Nord: (intensité 5 += 1, age 22 <= 15)
30
+  * Deux fourmis qui se croisent, posant respectivement ce qu'elle cherche comme pheromone. Vont-elle se bloquer ?

+ 13 - 6
config.py View File

@@ -2,16 +2,23 @@ from intelligine.core.Context import Context
2 2
 from intelligine.synergy.Simulation import Simulation
3 3
 from intelligine.display.Pygame import Pygame
4 4
 from intelligine.display.pygame.visualisation import visualisation as pygame_visualisation
5
-from intelligine.sandbox.colored.colors_colonys import collections
5
+#from intelligine.sandbox.colored.colors_colonys import collections
6
+# TODO: influencer avec argument python
7
+from intelligine.sandbox.exploration.collections import collections
6 8
 
7 9
 """
8 10
  TODO:
9 11
  * AttackAction :: comment choisir entre les actions ?
10
- * TakeAction, PutAction, Object Egg
11
- * --> frameworkiser les usage de states, metas etc ?
12
- * Plusieurs objets au mm endroit; Cinq oeuf => dessein de cinq oeuf; etc (image dynamique (param max_supperposer ?)
13
- * 3d
14
- * Optimisation display pygame: ne pas tout reafficher; opt google
12
+
13
+ * pheromones:
14
+   cf. doc papier
15
+   + Pour le "pt de ressource": Poser un objet qui, lorsque on applique la position:
16
+     L'objet doit pouvoir occuper plusieurs positions (gros objet)
17
+     Il a donc * une position de reference
18
+               * une liste de positions occupe
19
+               * dans les metas cette liste de position contient la reference de l'objet
20
+               *
21
+
15 22
 """
16 23
 
17 24
 config = {

+ 18 - 1
intelligine/core/exceptions.py View File

@@ -1,11 +1,28 @@
1 1
 class MovementException(Exception):
2 2
     pass
3 3
 
4
+
4 5
 class SamePosition(MovementException):
5 6
     pass
6 7
 
8
+
7 9
 class PheromoneException(Exception):
8 10
     pass
9 11
 
12
+
13
+class NoPheromone(PheromoneException):
14
+    pass
15
+
16
+
10 17
 class NoPheromoneMove(PheromoneException, MovementException):
11
-    pass
18
+    pass
19
+
20
+
21
+class BestPheromoneHere(PheromoneException):
22
+
23
+    def __init__(self, best_distance,  *args, **kwargs):
24
+        super().__init__(*args, **kwargs)
25
+        self._best_distance = best_distance
26
+
27
+    def get_best_distance(self):
28
+        return self._best_distance

+ 3 - 0
intelligine/cst.py View File

@@ -15,9 +15,12 @@ CANT_CARRY_STILL = IncrementedNamedInt.get('intelligine.cantcarry.still')
15 15
 CANT_PUT_STILL = IncrementedNamedInt.get('intelligine.cantput.still')
16 16
 ACTION_DIE = IncrementedNamedInt.get('intelligine.basebug.action.die')
17 17
 
18
+MOVE_MODE = IncrementedNamedInt.get('intelligine.basebug.move.mode')
18 19
 MOVE_MODE_EXPLO = IncrementedNamedInt.get('intelligine.basebug.move.mode.explo')
19 20
 MOVE_MODE_GOHOME = IncrementedNamedInt.get('intelligine.basebug.move.mode.gohome')
20 21
 
22
+LAST_PHERMONES_POINTS = IncrementedNamedInt.get('intelligine.last_pheromones_points')
23
+
21 24
 PHEROMON_POSITIONS = IncrementedNamedInt.get('intelligine.phero.positions')
22 25
 PHEROMON_INFOS = IncrementedNamedInt.get('intelligine.phero.infos')
23 26
 PHEROMON_DIRECTION = IncrementedNamedInt.get('intelligine.phero.direction')

+ 5 - 8
intelligine/display/Pygame.py View File

@@ -25,11 +25,10 @@ class Pygame(XyzPygame):
25 25
                                                              allow_empty=True,
26 26
                                                              empty_value={})
27 27
 
28
-            for direction in exploration_info:
29
-                intensity = exploration_info[direction]
30
-                # TODO: ne pas avoir a creer d'objet, voir comment dans display
28
+            # TODO: ne pas avoir a creer d'objet, voir comment dans display
29
+            if exploration_info:
31 30
                 pheromon = PheromonHome(object(), context)
32
-                pheromon.set_direction(direction)
31
+                pheromon.set_direction(11) # TODO: plus de direction avec ces nlles pheromones
33 32
                 self._draw_objects_with_decal(point, [pheromon])
34 33
 
35 34
 
@@ -38,12 +37,10 @@ class Pygame(XyzPygame):
38 37
                                                               PHEROMON_DIR_EXPLO],
39 38
                                                              allow_empty=True,
40 39
                                                              empty_value={})
41
-
42
-            for direction in exploration_info:
43
-                intensity = exploration_info[direction]
40
+            if exploration_info:
44 41
                 # TODO: ne pas avoir a creer d'objet, voir comment dans display
45 42
                 pheromon = PheromonExploration(object(), context)
46
-                pheromon.set_direction(direction)
43
+                pheromon.set_direction(11) # TODO: plus de direction avec ces nlles pheromones
47 44
                 self._draw_objects_with_decal(point, [pheromon])
48 45
 
49 46
     def _key_pressed(self, key):

BIN
intelligine/display/pygame/image/food.png View File


BIN
intelligine/display/pygame/image/hole.png View File


BIN
intelligine/display/pygame/image/phee (copie).png View File


BIN
intelligine/display/pygame/image/phee.png View File


BIN
intelligine/display/pygame/image/pheh (copie).png View File


BIN
intelligine/display/pygame/image/pheh.png View File


BIN
intelligine/display/pygame/image/rock.png View File


BIN
intelligine/display/pygame/image/rock_old.png View File


+ 5 - 0
intelligine/display/pygame/visualisation.py View File

@@ -2,6 +2,7 @@ from xyworld.display.object.pygame.PygameImage import PygameImage
2 2
 from xyworld.display.object.pygame.DirectionnedImage import DirectionnedImage
3 3
 from intelligine.synergy.object.Bug import Bug
4 4
 from intelligine.synergy.object.Food import Food
5
+from intelligine.synergy.object.Hole import Hole
5 6
 from intelligine.synergy.object.ant.Ant import Ant
6 7
 from intelligine.sandbox.colored.BlueAnt import BlueAnt
7 8
 from intelligine.sandbox.colored.RedAnt import RedAnt
@@ -15,6 +16,7 @@ from intelligine.cst import PREVIOUS_DIRECTION
15 16
 
16 17
 ant = PygameImage.from_filepath(getcwd()+'/intelligine/display/pygame/image/ant.png')
17 18
 food = PygameImage.from_filepath(getcwd()+'/intelligine/display/pygame/image/food.png')
19
+hole = PygameImage.from_filepath(getcwd()+'/intelligine/display/pygame/image/hole.png')
18 20
 dead_ant = PygameImage.from_filepath(getcwd()+'/intelligine/display/pygame/image/dead_ant.png')
19 21
 red_ant = PygameImage.from_filepath(getcwd()+'/intelligine/display/pygame/image/red_ant.png')
20 22
 green_ant = PygameImage.from_filepath(getcwd()+'/intelligine/display/pygame/image/green_ant.png')
@@ -139,6 +141,9 @@ visualisation = {
139 141
         Food: {
140 142
             'default': food
141 143
         },
144
+        Hole: {
145
+            'default': hole
146
+        },
142 147
         PheromonExploration: {
143 148
             'default': phee,
144 149
             'callbacks': [phee_direction]

+ 4 - 3
intelligine/sandbox/exploration/ColonyConfiguration.py View File

@@ -1,11 +1,12 @@
1
+from intelligine.core.exceptions import BestPheromoneHere
2
+from intelligine.simulation.pheromone.DirectionPheromone import DirectionPheromone
1 3
 from intelligine.synergy.ColonyConfiguration import ColonyConfiguration
2 4
 from intelligine.synergy.object.ant.Ant import Ant
5
+from intelligine.cst import PHEROMON_DIR_HOME
3 6
 
4 7
 
5 8
 class ColonyConfiguration(ColonyConfiguration):
6 9
 
7 10
     _start_position = (0, 5, 5)
8 11
     _ant_class = Ant
9
-    _ant_count = 50
10
-
11
-
12
+    _ant_count = 5

+ 10 - 1
intelligine/sandbox/exploration/map2.tmx View File

@@ -18,9 +18,18 @@
18 18
    </properties>
19 19
   </tile>
20 20
  </tileset>
21
+ <tileset firstgid="3" name="hole" tilewidth="20" tileheight="20">
22
+  <image source="../../display/pygame/image/hole.png" width="20" height="20"/>
23
+  <tile id="0">
24
+   <properties>
25
+    <property name="classname" value="Hole"/>
26
+    <property name="file" value="intelligine.synergy.object.Hole"/>
27
+   </properties>
28
+  </tile>
29
+ </tileset>
21 30
  <layer name="Calque 1" width="200" height="100">
22 31
   <data encoding="base64" compression="zlib">
23
-   eJzt3MEKg0AQREH1/z86lxyFBFnxTVIFc2+36av7tm27u3z8tikdF3MWM7HWlI6LOYuZWGtKx8WcxUysNaXjYs5iJtaa0nExZzETa03p+FPOJ75jyttxXaHjbzLYB08odGwfVBU6tg+qCh3bB1WFju2DqkLH9kFVoWP7oKrQsX1QVejYPqgqdGwfVBU6tg+qCh1P28fxvsLbca9Cxysy3P0dx8kV3o57FTqu7+NsG/bxHwod2wdVhY7tg6qn/48z/QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaHgB3d0BMg==
32
+   eJzt3MFKI0EARdFE//+fBxeiDE5MXsIs6p4DvS14dC4upOt6uVyunvnhbK96x6f+Vt5uPKdu5os+fqePLn3cRx9N+rifPnp+esfvLzrnRPpo8ffjcfro0MdGHw362BU31+hjV9xco49dcXONPnbFzTX62BU31+hjV9xco49dcXONPnbFzTX62BU31+hjV9xco49dcXONPnbFzTX62BU31+hjV9xc8/GOb91BcO9T/K0UN9foY1fcXKOPXXFzjT52xc01+tgVN9foY1fcXKOPXXFzjf9/7Iqba/SxK26u0ceuuLlGH7vi5hp97Iqba/SxK26u0ceuuLlGH7vi5hp97Iqba/SxK26u0ceuuLlGH7vi5hp97Iqba/SxK26u0ceuuLlGH7vi5hp9bKrfhNXo43HlbyZrPr+vfcU5BfVvimu+f3/+7Dmn8819z9/3MzxzzsncSdH00/0l6zmncmdL17/u91nOOZE7jdpu3X/16DmncecXv90P98g5J3EnHh+unqceAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+jz/dxQL7
24 33
   </data>
25 34
  </layer>
26 35
 </map>

+ 37 - 0
intelligine/simulation/object/brain/AntBrain.py View File

@@ -0,0 +1,37 @@
1
+from intelligine.simulation.object.brain.Brain import Brain
2
+from intelligine.cst import MOVE_MODE, MOVE_MODE_EXPLO, MOVE_MODE_GOHOME, PHEROMON_DIR_HOME, PHEROMON_DIR_EXPLO
3
+
4
+
5
+class AntBrain(Brain):
6
+
7
+    def __init__(self, context, host):
8
+        super().__init__(context, host)
9
+        self._movement_mode = MOVE_MODE_EXPLO
10
+        self._distance_from_objective = 0  # TODO rename: distance_since_objective
11
+
12
+    def switch_to_mode(self, mode):
13
+        self._movement_mode = mode
14
+        self._update_pheromone_gland(mode)
15
+        self._context.metas.value.set(MOVE_MODE, self._host.get_id(), mode)
16
+        self._distance_from_objective = 0
17
+
18
+    def _update_pheromone_gland(self, mode):
19
+        if mode == MOVE_MODE_EXPLO:
20
+            pheromone_direction_type = PHEROMON_DIR_HOME
21
+        elif mode == MOVE_MODE_GOHOME:
22
+            pheromone_direction_type = PHEROMON_DIR_EXPLO
23
+        else:
24
+            raise NotImplementedError()
25
+        self._host.get_movement_pheromone_gland().set_pheromone_type(pheromone_direction_type)
26
+
27
+    def get_movement_mode(self):
28
+        return self._movement_mode
29
+
30
+    def host_moved(self, distance=1):
31
+        self._distance_from_objective += 1
32
+
33
+    def set_distance_from_objective(self, distance):
34
+        self._distance_from_objective = distance
35
+
36
+    def get_distance_from_objective(self):
37
+        return self._distance_from_objective

+ 5 - 0
intelligine/simulation/object/brain/Brain.py View File

@@ -0,0 +1,5 @@
1
+class Brain():
2
+
3
+    def __init__(self, context, host):
4
+        self._context = context
5
+        self._host = host

+ 11 - 0
intelligine/simulation/object/pheromone/MovementPheromoneGland.py View File

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

+ 13 - 0
intelligine/simulation/object/pheromone/PheromoneGland.py View File

@@ -0,0 +1,13 @@
1
+class PheromoneGland():
2
+
3
+    def __init__(self, host):
4
+        self._pheromone_type = None
5
+        self._host = host
6
+
7
+    def set_pheromone_type(self, pheromone_type):
8
+        self._pheromone_type = pheromone_type
9
+
10
+    def get_pheromone_type(self):
11
+        if self._pheromone_type is None:
12
+            raise Exception("pheromone_type not specified")
13
+        return self._pheromone_type

+ 107 - 0
intelligine/simulation/pheromone/DirectionPheromone.py View File

@@ -0,0 +1,107 @@
1
+from collections import OrderedDict
2
+from intelligine.cst import PHEROMON_DIRECTION, PHEROMON_POSITIONS, MOVE_MODE_EXPLO, MOVE_MODE_GOHOME,\
3
+    PHEROMON_DIR_EXPLO, PHEROMON_DIR_HOME
4
+from intelligine.core.exceptions import NoPheromone
5
+from random import shuffle
6
+from xyzworld.geometry import get_degree_from_north
7
+from intelligine.synergy.event.move.direction import get_direction_for_degrees
8
+
9
+
10
+class DirectionPheromone():
11
+
12
+    @staticmethod
13
+    def get_pheromone_type_for_move_mode(move_mode):
14
+        if move_mode == MOVE_MODE_EXPLO:
15
+            return PHEROMON_DIR_EXPLO
16
+        if move_mode == MOVE_MODE_GOHOME:
17
+            return PHEROMON_DIR_HOME
18
+        raise NotImplementedError()
19
+
20
+    @staticmethod
21
+    def appose(context, point, movement_molecules):
22
+        pheromone_type, distance_from = movement_molecules
23
+        # TODO: Ajouter l'age de la pheromone !
24
+        context.pheromones().increment(point, [PHEROMON_DIRECTION, pheromone_type], distance=distance_from)
25
+        context.metas.list.add(PHEROMON_POSITIONS, PHEROMON_POSITIONS, point, assert_not_in=False)
26
+
27
+    @staticmethod
28
+    def get_direction_for_point(context, point, pheromone_type):
29
+        try:
30
+            pheromone_info = context.pheromones().get_info(point, [PHEROMON_DIRECTION, pheromone_type])
31
+        except KeyError:
32
+            raise NoPheromone()
33
+
34
+        # DEBUG: On se rettrouve avec un {} ...
35
+        if not pheromone_info:
36
+            raise NoPheromone()
37
+
38
+        point_intensity = pheromone_info[1]
39
+        point_distance = pheromone_info[0]
40
+        arround_points = context.get_arround_points_of(point)
41
+
42
+        arround_pheromones_points = []
43
+        for arround_point in arround_points:
44
+            arround_pheromone_info = context.pheromones().get_info(arround_point,
45
+                                                                   [PHEROMON_DIRECTION, pheromone_type],
46
+                                                                   allow_empty=True,
47
+                                                                   empty_value={})
48
+            if arround_pheromone_info and arround_pheromone_info[0] < point_distance:
49
+                arround_pheromones_points.append((arround_point, arround_pheromone_info))
50
+
51
+        if not arround_pheromones_points:
52
+            raise NoPheromone()
53
+
54
+        shuffle(arround_pheromones_points)
55
+        arround_pheromones_sorted = sorted(arround_pheromones_points, key=lambda x: x[1][1])
56
+        max_intensity = arround_pheromones_sorted[0][1][1]
57
+
58
+        arround_pheromones_max = []
59
+        for arround_pheromone_sorted in arround_pheromones_sorted:
60
+            if arround_pheromone_sorted[1][1] == max_intensity:
61
+                arround_pheromones_max.append(arround_pheromone_sorted)
62
+
63
+        arround_pheromones_sorted_by_distance = sorted(arround_pheromones_max, key=lambda x: x[1][0], reverse=False)
64
+
65
+        go_to_point = arround_pheromones_sorted_by_distance[0][0]
66
+
67
+        direction_degrees = get_degree_from_north(point, go_to_point)
68
+        direction = get_direction_for_degrees(direction_degrees)
69
+
70
+        return direction
71
+        # # 1: On melange
72
+        # items = pheromone_info.items()
73
+        # shuffle(items)
74
+        # ph = OrderedDict(items)
75
+        # foo = True
76
+        # # 2: On trie par puissance
77
+        # ph_sorted = sorted(ph.items(), key=lambda x: x[1])
78
+        # # 3: On recupere les direction de la puissance max
79
+        # max_intensity = ph_sorted[0][1][1]
80
+        # max_directions = [direction_name for direction_name in pheromone_info
81
+        #                  if pheromone_info[direction_name][1] == max_intensity]
82
+        # # 4: On trie par age
83
+        # # 5: On recupere les directions de l'age le plus court
84
+        # # 6: On choisis une direction au hasard parmis elles (ou par rapport a direction precedente ??bug autre fois??)
85
+
86
+    @staticmethod
87
+    def get_best_pheromone_direction_in(context, reference_point, points, pheromone_type):
88
+        arround_pheromones_points = []
89
+        for arround_point in points:
90
+            arround_pheromone_info = context.pheromones().get_info(arround_point,
91
+                                                                   [PHEROMON_DIRECTION, pheromone_type],
92
+                                                                   allow_empty=True,
93
+                                                                   empty_value={})
94
+            if arround_pheromone_info:
95
+                arround_pheromones_points.append((arround_point, arround_pheromone_info))
96
+
97
+        if not arround_pheromones_points:
98
+            raise NoPheromone()
99
+
100
+        shuffle(arround_pheromones_points)
101
+        arround_pheromones_sorted = sorted(arround_pheromones_points, key=lambda x: x[1][1])
102
+        go_to_point = arround_pheromones_sorted[0][0]
103
+
104
+        direction_degrees = get_degree_from_north(reference_point, go_to_point)
105
+        direction = get_direction_for_degrees(direction_degrees)
106
+
107
+        return direction

+ 1 - 1
intelligine/synergy/Colony.py View File

@@ -13,4 +13,4 @@ class Colony(SynergyCollection):
13 13
     def __init__(self, configuration):
14 14
         super().__init__(configuration)
15 15
         self._actions = [MoveAction, NearAttackableAction, TakeableAction, PutableAction,
16
-                         CycleAction, ApposeDirection]
16
+                         CycleAction]

+ 156 - 25
intelligine/synergy/event/move/MoveAction.py View File

@@ -2,9 +2,15 @@ from synergine.synergy.event.Action import Action
2 2
 from intelligine.synergy.event.move.MoveEvent import MoveEvent
3 3
 from random import randint, choice, randrange
4 4
 from xyzworld.cst import POSITION, POSITIONS
5
-from intelligine.cst import PREVIOUS_DIRECTION, BLOCKED_SINCE
5
+from intelligine.cst import PREVIOUS_DIRECTION, BLOCKED_SINCE, MOVE_MODE, MOVE_MODE_GOHOME, MOVE_MODE_EXPLO, \
6
+                            PHEROMON_DIR_EXPLO, PHEROMON_DIR_HOME, PHEROMON_DIRECTION, \
7
+    COL_TRANSPORTER_NOT_CARRYING, COL_TRANSPORTER_CARRYING
6 8
 from intelligine.synergy.event.move.direction import directions_same_level, directions_modifiers, directions_slighty
7
-from intelligine.core.exceptions import NoPheromoneMove
9
+from intelligine.core.exceptions import NoPheromoneMove, NoPheromone, BestPheromoneHere
10
+import operator
11
+from intelligine.simulation.pheromone.DirectionPheromone import DirectionPheromone
12
+from xyzworld.geometry import get_degree_from_north
13
+from intelligine.synergy.event.move.direction import get_direction_for_degrees, directions_opposites
8 14
 
9 15
 
10 16
 class MoveAction(Action):
@@ -12,28 +18,62 @@ class MoveAction(Action):
12 18
     _listen = MoveEvent
13 19
 
14 20
     def __init__(self, object_id, parameters):
15
-      super().__init__(object_id, parameters)
16
-      self._move_to_point = None
17
-      self._move_to_direction = None
21
+        super().__init__(object_id, parameters)
22
+        self._move_to_point = None
23
+        self._move_to_direction = None
18 24
 
19 25
     def prepare(self, context):
20
-      object_point = context.metas.value.get(POSITION, self._object_id)
21
-      try:
22
-          choosed_direction_name, choosed_direction_point = self._get_pheromone_direction_point(context, object_point)
23
-      except NoPheromoneMove:
24
-          choosed_direction_name, choosed_direction_point = self._get_random_direction_point(context, object_point)
25
-      if self._direction_point_is_possible(context, choosed_direction_point):
26
-        self._move_to_point = choosed_direction_point
27
-        self._move_to_direction = choosed_direction_name
28
-
29
-    def _get_random_direction_point(self, context, reference_point):
30
-        z, x, y = reference_point
31
-        direction_name = self._get_random_direction_name(context)
32
-        directions_modifier = directions_modifiers[direction_name]
33
-        new_position = (z + directions_modifier[0], x + directions_modifier[1], y + directions_modifier[2])
34
-        return (direction_name, new_position)
26
+        object_point = context.metas.value.get(POSITION, self._object_id)
27
+
28
+        try:
29
+            direction = self._get_direction_with_pheromones(context, object_point)
30
+        except NoPheromone:
31
+            direction = self._get_random_direction(context)
32
+
33
+        move_to_point = self._get_point_for_direction(object_point, direction)
34
+        if self._direction_point_is_possible(context, move_to_point):
35
+            self._move_to_point = move_to_point
36
+            self._move_to_direction = direction
37
+        else:
38
+            # TODO: mettre self._dont_move = True ?
39
+            pass
40
+
41
+    def _get_direction_with_pheromones(self, context, object_point):
42
+        # TODO: Placer directnement pheromone type dans les metas
43
+        object_movement_mode = context.metas.value.get(MOVE_MODE, self._object_id)
44
+        pheromone_type = DirectionPheromone.get_pheromone_type_for_move_mode(object_movement_mode)
45
+        try:
46
+            direction = self._get_pheromone_direction_for_point(context, object_point, pheromone_type)
47
+        except NoPheromone:
48
+            direction = self._get_direction_of_pheromone(context, object_point, pheromone_type)
49
+        return direction
50
+
51
+    @staticmethod
52
+    def _get_pheromone_direction_for_point(context, point, pheromone_type):
53
+        return DirectionPheromone.get_direction_for_point(context, point, pheromone_type)
54
+
55
+    @staticmethod
56
+    def _get_direction_of_pheromone(context, point, pheromone_type):
57
+        search_pheromone_distance = 1  # TODO: config
58
+        search_pheromone_in_points = context.get_arround_points_of(point, distance=search_pheromone_distance)
59
+        try:
60
+            # TODO: ? Avoir plutot un DirectionPheromone.get_best_pheromone_direction_in ?
61
+            best_pheromone_direction = DirectionPheromone.get_best_pheromone_direction_in(context,
62
+                                                                                          point,
63
+                                                                                          search_pheromone_in_points,
64
+                                                                                          pheromone_type)
65
+            return best_pheromone_direction
66
+        except NoPheromone as err:
67
+            raise err
68
+
69
+    # def _get_random_direction_point(self, context, reference_point):
70
+    #     z, x, y = reference_point
71
+    #     direction_name = self._get_random_direction_name(context)
72
+    #     directions_modifier = directions_modifiers[direction_name]
73
+    #     new_position = (z + directions_modifier[0], x + directions_modifier[1], y + directions_modifier[2])
74
+    #     return (direction_name, new_position)
35 75
 
36
-    def _get_random_direction_name(self, context):
76
+    def _get_random_direction(self, context):
37 77
         try:
38 78
             blocked_since = context.metas.value.get(BLOCKED_SINCE, self._object_id)
39 79
         except KeyError:
@@ -59,14 +99,45 @@ class MoveAction(Action):
59 99
 
60 100
         return direction_name
61 101
 
62
-    def _direction_point_is_possible(self, context, direction_point):
102
+    @staticmethod
103
+    def _get_point_for_direction(reference_point, direction):
104
+        # TODO: mettre une fonction cote direction.py pour appliquer le modifier.
105
+        z, x, y = reference_point
106
+        directions_modifier = directions_modifiers[direction]
107
+        return z + directions_modifier[0], x + directions_modifier[1], y + directions_modifier[2]
108
+
109
+    @staticmethod
110
+    def _direction_point_is_possible(context, direction_point):
63 111
         return context.position_is_penetrable(direction_point)
64 112
 
65 113
     def run(self, obj, context, synergy_manager):
66
-        if self._move_to_point is not None:
114
+        if self._move_to_point is not None and self._move_to_direction != 14: # TODO: il ne faut pas choisir une direction 14.
67 115
             obj.set_position(self._move_to_point)
116
+            #direction_from = directions_opposites[self._move_to_direction]
117
+            #obj.set_direction_from(direction_from)
68 118
             context.metas.value.set(PREVIOUS_DIRECTION, self._object_id, self._move_to_direction)
69 119
             context.metas.value.set(BLOCKED_SINCE, self._object_id, 0)
120
+            self._appose_pheromone(obj, context)
121
+
122
+            # TEST: le temps de tout tester
123
+            if self._move_to_point == (0, 5, 5) and obj.is_carrying():
124
+                obj_transported = obj.get_carried()
125
+                obj_transported.set_carried_by(None)
126
+                obj.put_carry(obj_transported, (-1, 0, 0))
127
+                obj.get_brain().switch_to_mode(MOVE_MODE_EXPLO)
128
+                context.metas.collections.add_remove(obj.get_id(),
129
+                    COL_TRANSPORTER_NOT_CARRYING, COL_TRANSPORTER_CARRYING)
130
+
131
+            # TMP: Devra etre un event et une action
132
+            # if self._move_to_point == (0, 5, 5):  # position de depart
133
+            #     if len(obj._carried):
134
+            #         obj_transported = obj.get_carried()
135
+            #         obj_transported.set_carried_by(None)
136
+            #         obj.put_carry(obj_transported, (-1, 5, 5))
137
+            #         context.metas.collections.add_remove(obj.get_id(), COL_TRANSPORTER_NOT_CARRYING, COL_TRANSPORTER_CARRYING)
138
+            #     obj.set_movement_mode(MOVE_MODE_EXPLO)
139
+
140
+
70 141
         else:
71 142
             try:
72 143
                 blocked_since = context.metas.value.get(BLOCKED_SINCE, self._object_id)
@@ -74,6 +145,66 @@ class MoveAction(Action):
74 145
                 blocked_since = 0
75 146
             context.metas.value.set(BLOCKED_SINCE, self._object_id, blocked_since+1)
76 147
 
77
-    def _get_pheromone_direction_point(self, context, object_point):
148
+    # def _get_pheromone_direction_point(self, context, object_point):
149
+    #     try:
150
+    #         blocked_since = context.metas.value.get(BLOCKED_SINCE, self._object_id)
151
+    #     except KeyError:
152
+    #         blocked_since = 0
153
+    #     if blocked_since > 3:
154
+    #         raise NoPheromoneMove()
155
+    #     # Si on explore, on cherche pheromone d'explo
156
+    #     # si on rentre a home, on cherche pheromone d'home...
157
+    #     # TODO: code arrache
158
+    #     object_movement_mode = context.metas.value.get(MOVE_MODE, self._object_id)
159
+    #     if object_movement_mode == MOVE_MODE_EXPLO:
160
+    #         pheromone_direction_type = PHEROMON_DIR_EXPLO
161
+    #     elif object_movement_mode == MOVE_MODE_GOHOME:
162
+    #         pheromone_direction_type = PHEROMON_DIR_HOME
163
+    #
164
+    #     sniff_points = context.get_arround_points_of(object_point, distance=0)
165
+    #     # Faire un compile des infos de pheromones
166
+    #
167
+    #     directions = {}
168
+    #     for sniff_point in sniff_points:
169
+    #         info = context.pheromones().get_info(sniff_point,
170
+    #                                              [PHEROMON_DIRECTION, pheromone_direction_type],
171
+    #                                              allow_empty=True,
172
+    #                                              empty_value={})
173
+    #         for direction in info:
174
+    #             if direction not in directions:
175
+    #                 directions[direction] = info[direction]
176
+    #             else:
177
+    #                 directions[direction] += info[direction]
178
+    #     if len(directions):
179
+    #         sorted_directions = sorted(directions.items(), key=operator.itemgetter(1))
180
+    #         sorted_directions.reverse()
181
+    #         #best_direction_name = sorted_directions[0][0]
182
+    #         best_direction_level = sorted_directions[0][1]
183
+    #         best_direction_names = [direction for direction in directions \
184
+    #                                if directions[direction] == best_direction_level]
185
+    #         # Si plusieurs best directions, choisir mm direction que la precedente
186
+    #         # si y a pas, au hasard.
187
+    #         last_dir_name = context.metas.value.get(PREVIOUS_DIRECTION, self._object_id)
188
+    #         if last_dir_name in best_direction_names:
189
+    #             direction_name = last_dir_name
190
+    #         else:
191
+    #             direction_name = choice(best_direction_names)
192
+    #
193
+    #         # DRY
194
+    #         z, x, y = object_point
195
+    #         directions_modifier = directions_modifiers[direction_name]
196
+    #         new_position = (z + directions_modifier[0], x + directions_modifier[1], y + directions_modifier[2])
197
+    #         return (direction_name, new_position)
198
+    #
199
+    #         pass
200
+    #     raise NoPheromoneMove()
78 201
 
79
-        raise NoPheromoneMove()
202
+    def _appose_pheromone(self, obj, context):
203
+        # TODO: Cette action de pheromone doit etre une surcharge de Move afin d'avoir une Action Move generique.
204
+        obj.get_brain().host_moved()
205
+        try:
206
+            DirectionPheromone.appose(context,
207
+                                      obj.get_position(),
208
+                                      obj.get_movement_pheromone_gland().get_movement_molecules())
209
+        except BestPheromoneHere as best_pheromone_here:
210
+            obj.get_brain().set_distance_from_objective(best_pheromone_here.get_best_distance())

+ 9 - 9
intelligine/synergy/event/move/direction.py View File

@@ -98,15 +98,15 @@ directions_slighty = {
98 98
 }
99 99
 
100 100
 directions_degrees = {
101
-    (0, 22): 11,
102
-    (22, 67): 12,
103
-    (68, 112): 15,
104
-    (112, 158): 18,
105
-    (158, 201): 17,
106
-    (201, 246): 16,
107
-    (246, 291): 13,
108
-    (291, 338): 10,
109
-    (338, 0): 11
101
+    (0, 22.5): 11,
102
+    (22.5, 67): 12,
103
+    (67, 112.5): 15,
104
+    (112.5, 157.5): 18,
105
+    (157.5, 202.5): 17,
106
+    (202.5, 247.5): 16,
107
+    (247.5, 292.5): 13,
108
+    (292.5, 337.5): 10,
109
+    (337.5, 0): 11
110 110
 }
111 111
 
112 112
 def get_direction_for_degrees(degrees):

+ 0 - 65
intelligine/synergy/event/pheromone/ApposeDirection.py View File

@@ -1,65 +0,0 @@
1
-from synergine.synergy.event.Action import Action
2
-from intelligine.synergy.event.pheromone.PheromoneEvent import PheromoneEvent
3
-from xyzworld.cst import POSITION
4
-from intelligine.cst import PHEROMON_DIRECTION, PHEROMON_DIR_HOME, PHEROMON_POSITIONS, MOVE_MODE_EXPLO, \
5
-    MOVE_MODE_GOHOME, PHEROMON_DIR_EXPLO
6
-from xyzworld.geometry import get_degree_from_north
7
-from intelligine.synergy.event.move.direction import get_direction_for_degrees, get_direction_opposite
8
-from intelligine.core.exceptions import SamePosition
9
-
10
-
11
-class ApposeDirection(Action):
12
-
13
-    _listen = PheromoneEvent
14
-
15
-    def prepare(self, context):
16
-        """
17
-        Recupere chaque coordonnees de points qui doivent etre update
18
-        pour ne pas avoir a e calculer dans le run
19
-        :param context:
20
-        :return:
21
-        """
22
-        object_point =  context.metas.value.get(POSITION, self._object_id)
23
-        distance = 1 # TODO: Config ?
24
-        self._parameters['concerned_points'] = context.get_arround_points_of(object_point, distance)
25
-
26
-    def run(self, obj, context, synergy_manager):
27
-        """
28
-        On effectue l'incrementation dans le process principal. Beaucoups plus lourd que de le faie dans les
29
-        process. Mais si on le fait dans les process on va rater des infos ...
30
-        met a jour les pts (incremente)
31
-        """
32
-        self._appose_pheromones(obj, context, synergy_manager)
33
-
34
-    def _appose_pheromones(self, obj, context, synergy_manager):
35
-        try:
36
-            from_direction = self._get_from_direction(obj)
37
-        except SamePosition:
38
-            return
39
-
40
-        depose_intensity = 1 # TODO: config
41
-        pheromone_direction_type = self._get_pheromone_direction_type(obj)
42
-        for affected_point in self._parameters['concerned_points']:
43
-            context.pheromones().increment(affected_point, [PHEROMON_DIRECTION,
44
-                                                            pheromone_direction_type,
45
-                                                            from_direction], depose_intensity)
46
-            context.metas.list.add(PHEROMON_POSITIONS, PHEROMON_POSITIONS, affected_point, assert_not_in=False)
47
-
48
-        obj.set_last_pheromone_point(PHEROMON_DIRECTION, obj.get_position())
49
-
50
-    def _get_from_direction(self, obj):
51
-        obj_position = obj.get_position()
52
-        obj_last_pheromon_position = obj.get_last_pheromone_point(PHEROMON_DIRECTION)
53
-        try:
54
-            direction_degrees = get_degree_from_north(obj_last_pheromon_position, obj_position)
55
-        except ZeroDivisionError:
56
-            raise SamePosition()
57
-        direction = get_direction_for_degrees(direction_degrees)
58
-        return get_direction_opposite(direction)
59
-
60
-    def _get_pheromone_direction_type(self, obj):
61
-        if obj.get_movement_mode() == MOVE_MODE_EXPLO:
62
-            return PHEROMON_DIR_HOME
63
-        if obj.get_movement_mode() == MOVE_MODE_GOHOME:
64
-            return PHEROMON_DIR_EXPLO
65
-        raise NotImplementedError()

+ 0 - 26
intelligine/synergy/event/pheromone/DetermineDirection.py View File

@@ -1,26 +0,0 @@
1
-from synergine.synergy.event.Action import Action
2
-from intelligine.synergy.event.mind.PheromoneEvent import PheromoneEvent
3
-
4
-
5
-class DetermineDirection(Action):
6
-
7
-    _listen = PheromoneEvent
8
-
9
-    def prepare(self, context):
10
-        """
11
-        Recupere chaque coordonnees de points qui doivent etre update
12
-        pour ne pas avoir a e calculer dans le run
13
-        :param context:
14
-        :return:
15
-        """
16
-        pass
17
-
18
-    def run(self, obj, context, synergy_manager):
19
-        """
20
-        Met a jour la direction en cours de l'ant
21
-        :param obj:
22
-        :param context:
23
-        :param synergy_manager:
24
-        :return:
25
-        """
26
-        pass

+ 0 - 15
intelligine/synergy/event/pheromone/PheromoneEvent.py View File

@@ -1,15 +0,0 @@
1
-from synergine.synergy.event.Event import Event
2
-from intelligine.cst import COL_WALKER
3
-
4
-
5
-class PheromoneEvent(Event):
6
-    """
7
-    TODO: dissipation des infos de pheromones:
8
-          On doit manipuler l'environnement (pas des syn.obj.) car -= l'intensite d'un pt.
9
-    """
10
-
11
-    concern = COL_WALKER # Maybe more when more pheromones
12
-    _each_cycle = 2
13
-
14
-    def _object_match(self, object_id, context, parameters):
15
-        return True

+ 9 - 1
intelligine/synergy/object/BaseBug.py View File

@@ -1,5 +1,6 @@
1 1
 from intelligine.synergy.object.Transportable import Transportable
2 2
 from intelligine.cst import ALIVE, ATTACKABLE, COL_ALIVE
3
+from intelligine.simulation.object.brain.Brain import Brain
3 4
 
4 5
 
5 6
 class BaseBug(Transportable):
@@ -10,6 +11,7 @@ class BaseBug(Transportable):
10 11
         context.metas.collections.add(self.get_id(), COL_ALIVE)
11 12
         self._life_points = 10
12 13
         self._movements_count = -1
14
+        self._brain = self._get_brain_instance()
13 15
 
14 16
     def hurted(self, points):
15 17
         self._life_points -= points
@@ -22,4 +24,10 @@ class BaseBug(Transportable):
22 24
         self._movements_count += 1
23 25
 
24 26
     def get_movements_count(self):
25
-        return self._movements_count
27
+        return self._movements_count
28
+
29
+    def _get_brain_instance(self):
30
+        return Brain(self._context, self)
31
+
32
+    def get_brain(self):
33
+        return self._brain

+ 2 - 3
intelligine/synergy/object/Food.py View File

@@ -1,15 +1,14 @@
1 1
 from intelligine.synergy.object.Transportable import Transportable
2
-from intelligine.cst import IMPENETRABLE, TRANSPORTABLE
2
+from intelligine.cst import TRANSPORTABLE
3 3
 
4 4
 
5 5
 class Food(Transportable):
6 6
 
7 7
     def __init__(self, collection, context):
8 8
         super().__init__(collection, context)
9
-        context.metas.states.add(self.get_id(), IMPENETRABLE)
10 9
         context.metas.states.add(self.get_id(), TRANSPORTABLE)
11 10
 
12
-    def get_carry(self):
11
+    def get_what_carry(self):
13 12
         clone = self.__class__(self._collection, self._context)
14 13
         self._collection.add_object(clone)
15 14
         return clone

+ 5 - 0
intelligine/synergy/object/Hole.py View File

@@ -0,0 +1,5 @@
1
+from xyzworld.SynergyObject import SynergyObject as XyzSynergyObject
2
+
3
+
4
+class Hole(XyzSynergyObject):
5
+    pass

+ 23 - 8
intelligine/synergy/object/ant/Ant.py View File

@@ -1,9 +1,13 @@
1
+from intelligine.core.exceptions import BestPheromoneHere
2
+from intelligine.simulation.pheromone.DirectionPheromone import DirectionPheromone
1 3
 from intelligine.synergy.object.Bug import Bug
2 4
 from intelligine.cst import CARRYING, TRANSPORTER, ATTACKER, \
3 5
                             COL_TRANSPORTER, COL_TRANSPORTER_NOT_CARRYING, \
4 6
                             COL_FIGHTER, MOVE_MODE_EXPLO, MOVE_MODE_GOHOME, \
5
-                            PHEROMON_DIR_EXPLO
7
+                            PHEROMON_DIR_EXPLO, LAST_PHERMONES_POINTS
6 8
 from intelligine.synergy.object.Food import Food
9
+from intelligine.simulation.object.pheromone.MovementPheromoneGland import MovementPheromoneGland
10
+from intelligine.simulation.object.brain.AntBrain import AntBrain
7 11
 
8 12
 
9 13
 class Ant(Bug):
@@ -16,7 +20,14 @@ class Ant(Bug):
16 20
                                                            COL_FIGHTER])
17 21
         self._carried = []
18 22
         self._last_pheromones_points = {}
19
-        self._movement_mode = MOVE_MODE_EXPLO
23
+        self._movement_pheromone_gland = MovementPheromoneGland(self)
24
+        self._brain.switch_to_mode(MOVE_MODE_EXPLO)
25
+
26
+    def _get_brain_instance(self):
27
+        return AntBrain(self._context, self)
28
+
29
+    def get_movement_pheromone_gland(self):
30
+        return self._movement_pheromone_gland
20 31
 
21 32
     def put_carry(self, obj, position=None):
22 33
         if position is None:
@@ -34,7 +45,7 @@ class Ant(Bug):
34 45
         self._context.metas.states.add(self.get_id(), CARRYING)
35 46
         # TODO: pour le moment hardcode
36 47
         if isinstance(obj, Food):
37
-            self.set_movement_mode(MOVE_MODE_GOHOME)
48
+            self.get_brain().switch_to_mode(MOVE_MODE_GOHOME)
38 49
             self.set_last_pheromone_point(PHEROMON_DIR_EXPLO, obj.get_position())
39 50
 
40 51
     def is_carrying(self):
@@ -56,9 +67,13 @@ class Ant(Bug):
56 67
 
57 68
     def set_last_pheromone_point(self, pheromone_name, position):
58 69
         self._last_pheromones_points[pheromone_name] = position
70
+        self._context.metas.value.set(LAST_PHERMONES_POINTS, self.get_id(), self._last_pheromones_points)
59 71
 
60
-    def get_movement_mode(self):
61
-        return self._movement_mode
62
-
63
-    def set_movement_mode(self, movement_mode):
64
-        self._movement_mode = movement_mode
72
+    def initialize(self):
73
+        super().initialize()
74
+        try:
75
+            DirectionPheromone.appose(self._context,
76
+                                      self.get_position(),
77
+                                      self.get_movement_pheromone_gland().get_movement_molecules())
78
+        except BestPheromoneHere as best_pheromone_here:
79
+            pass

+ 23 - 6
intelligine/synergy/stigmergy/PheromonesManager.py View File

@@ -1,4 +1,6 @@
1
+from intelligine.core.exceptions import BestPheromoneHere
1 2
 from intelligine.cst import PHEROMON_INFOS
3
+from intelligine.core.exceptions import NoPheromone
2 4
 
3 5
 
4 6
 class PheromonesManager():
@@ -31,13 +33,13 @@ class PheromonesManager():
31 33
 
32 34
         if address[-1] not in pheromone:
33 35
             if allow_empty:
34
-              pheromone[address[-1]] = empty_value
36
+                pheromone[address[-1]] = empty_value
35 37
             else:
36
-                raise IndexError()
38
+                raise KeyError()
37 39
 
38 40
         return pheromone[address[-1]]
39 41
 
40
-    def increment(self, position, address, increment_value):
42
+    def increment(self, position, address, distance, increment_value=1):
41 43
         pheromones = self.get_pheromones(position, address[:-1])
42 44
 
43 45
         pheromone = pheromones
@@ -45,6 +47,21 @@ class PheromonesManager():
45 47
             pheromone = pheromone[key]
46 48
 
47 49
         if address[-1] not in pheromone:
48
-            pheromone[address[-1]] = 0
49
-        pheromone[address[-1]] += increment_value
50
-        self.set_pheromones(position, pheromones)
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]
57
+
58
+        pheromone_intensity += increment_value
59
+
60
+        if distance < pheromone_distance:
61
+            pheromone_distance = distance
62
+
63
+        pheromone[address[-1]] = (pheromone_distance, pheromone_intensity)
64
+        self.set_pheromones(position, pheromones)
65
+
66
+        if distance > pheromone_distance:
67
+            raise BestPheromoneHere(pheromone_distance)