1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 import copy
40 import random
41 import os
42 import sys
43 import operator
44 from math import *
45 import numpy
46
47 from vec2d import *
48 from lineline import *
49
50 import geometry
51 import rrtTree
52 import perceptModels
53 from actions import *
54 import state
55 from messages import PrimitiveMessage, CompositeMessage
56 import obstacleAvoidance
57 from navigationTactics import *
58 from scripts import heuristicDivide
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
90 """
91 This class is a base class for all the models an agent
92 can have about the world.
93 A subclass should implement a specific model of the world,
94 and a specific way to process percepts for this model.
95 There can be multiple ways to process percepts for any
96 given model, so an example class hierarchy could be:
97
98 -------------------
99 | AgentWorldModel |
100 -------------------
101 / \
102 ---------- ----------
103 | Model1 | | Model2 |
104 ---------- ----------
105 / \ \
106 ------------------- ------------------ .
107 |with method 1 to | |with method 2 to| .
108 |processPercepts | |processPercepts | .
109 |for Model1 | |for Model1 |
110 ------------------- ------------------
111 """
113 """
114 Every world model contains a queue for incoming messages.
115 Note that outgoing msgs are inside strategy.
116 TODO: does this design need change?
117 """
118 self.incomingMsgs = CompositeMessage()
119
120
122 """
123 For a given concrete model, this method
124 implements a specific method of updating this
125 model from percepts.
126 This is just an extra layer of flexibility, in case
127 there are multiple methods to update percepts for the
128 same model.
129
130 @type perceptsList: PerceptList
131 @param perceptsList: A list of percepts to be processed
132 """
133 abstract
134
136 """
137 Get a list of estimated ShipExternalState of all other ships
138 in the system.
139
140 @type selfIndex: int
141 @param selfIndex: The index of the ship controlled by the agent - we don't want to include it in the returned states.
142
143 @rtype: A list of ShipExternalState
144 @return: A list of estimated states of all other ships in the system
145 """
146 abstract
147
149 """
150 Get a list of estimated ShipExternalState of all other ships
151 indexed by shipIndices.
152
153 @type selfIndex: list[int]
154 @param selfIndex: The indices of the ships for which location is estimated
155
156 @rtype: A list of ShipExternalState
157 @return: A list of estimated states of all other ships in the system
158 """
159 abstract
160
162 """
163 Get the estimated ShipExternalState as estimated
164 by the world model.
165
166 @rtype: ShipExternalState
167 @return: An estimation of the ship's real state according to our AgentWorldModel.
168 """
169 abstract
170
172 """
173 Get the estimated wind vector in the location of
174 the ship.
175
176 @rtype: numpy array (vector)
177 @return: an estimation of the wind vector (speed and direction) in the agent's location according to our AgentWorldModel.
178 """
179 abstract
180
182 """
183 Get the estimated water vector in the location of
184 the ship.
185
186 @rtype: numpy array (vector)
187 @return: an estimation of the water vector (speed and direction) in the agent's location according to our AgentWorldModel.
188 """
189 abstract
190
192 """
193 Get a list of estimated obstacle shapes.
194
195 @rtype: Obstacles
196 @return: an estimation of the obstacles shapes (and positions) according to our AgentWorldModel.
197 """
198 abstract
199
200
201
204
206 """
207 Append a message to the queue
208 """
209 self.incomingMsgs.appendMsg(msg)
210
211 if len(self.incomingMsgs.primitiveMsgs) > 100:
212 raise Exception("Did you forget to read and clean messages")
213
214
215
216
218 """
219 Just a skeleton for testing purposes.
220 The world model is exactly the world state.
221 """
226
227
237
239 """
240 Implements the abstract method
241 """
242 states = self.state.shipExternalStates
243 return states[0:selfIndex] + states[selfIndex + 1:]
244
246 """
247 Implements the abstract method
248 """
249 states = self.state.shipExternalStates
250 return [states[i] for i in shipIndices]
251
253 """
254 Implements the abstract method
255 """
256 return self.state.shipExternalStates[self.shipIndex]
257
259 """
260 Implements the abstract method
261 """
262 shipState = self.state.shipExternalStates[self.shipIndex]
263 posX, posY = shipState.x, shipState.y
264 return self.state.sea.wind.getSpeedVectorInLocation(posX, posY)
265
267 """
268 Implements the abstract method
269 """
270 shipState = self.state.shipExternalStates[self.shipIndex]
271 posX, posY = shipState.x, shipState.y
272 return self.state.sea.waterCurrents.getSpeedVectorInLocation(posX, posY)
273
275 """
276 Implements the abstract method
277 """
278 return self.state.sea.obstacles.getObstaclesList()
279
280
281
282
283
284
285
286
287
289 """
290 An interface for specific decision making strategy.
291 It should be defined for a given AgentWorldModel,
292 a given set of legal actions, and a given decision making algorithm.
293
294 For each step, the flow is:
295 AgentWorldModel --> Specific_AgentStrategy --> Actions-to-execute
296 """
301
303 "Given the (inferred) state of the world, decide on a set of actions."
304 abstract
305
307 msg = self.outgoingMsg
308
309 if len(msg.primitiveMsgs) > 0:
310 self.outgoingMsg = CompositeMessage()
311 return msg
312
315
316
318 """
319 Implements a basic patrol strategy.
320 Given points of interest, just travel
321 along the cycle they define
322 """
323 - def __init__(self, agentIndex, myPatrolPath, rulesOfTheSea):
324 """
325 Initializes the strategy.
326
327 @type agentIndex: int
328 @param agentIndex: sort of an agent-id - an agent's index in the array of all agents
329
330 @type path: a list of 2-tuples
331 @param path: a list of (x,y) points that define a cycle for the agent to travel along
332
333 @type rulesOfTheSea: boolean
334 @param rulesOfTheSea: Tells whether to respect the rules of the sea
335 """
336 AgentStrategy.__init__(self)
337
338 self.agentIndex = agentIndex
339 self.myPatrolPath = myPatrolPath
340 self.rulesOfTheSea = rulesOfTheSea
341 self.nextTaskPointIndex = 0
342
343 self.navigationTactic = None
344
345 self.time = 0
346 self.prevPointTime = 0
347 self.firstVisit = True
348
350 """
351 Implements the abstract method, see documentation
352 of the abstract method.
353 """
354
355
356
357
358
359 self.time += 1
360
361 if self.navigationTactic and self.navigationTactic.done(agentWorldModel):
362 self.recordStatistics()
363
364 self.setNextPointAndNavigationTacticIfNeeded(agentWorldModel)
365
366 return self.navigationTactic.composeAction(agentWorldModel)
367
369 if self.navigationTactic == None:
370
371 goalPos = self.myPatrolPath[self.nextTaskPointIndex]
372 self.setNavigationTactic(agentWorldModel, goalPos)
373
374 elif self.navigationTactic.done(agentWorldModel):
375 self.nextTaskPointIndex = (self.nextTaskPointIndex + 1) % len(self.myPatrolPath)
376 goalPos = self.myPatrolPath[self.nextTaskPointIndex]
377 self.setNavigationTactic(agentWorldModel, goalPos)
378
396
397
399 return self.myPatrolPath
400
401
425
426
428 """
429 Implements a coordinated patrol strategy.
430 Given points of interest, each agent
431 runs heuristicDivide(), assign ships
432 to locations, and transmits it. Agents
433 vote and decide on suggestion, move to
434 their initial locations, and start
435 patroling.
436 """
437
438
439 TRANSMIT_INITIAL_LOCATION = 1
440 COMPUTE_PATROL_ASSIGNMENTS_AND_TRANSMIT = 2
441 VOTE = 3
442 MOVING_TO_START = 4
443 PATROLING = 5
444
445
446 - def __init__(self, agentIndex, patrolPoints, edgeLengths, rulesOfTheSea):
478
479
480
481
482
483
485 """
486 Resets all coordinated-patrol related data members
487 """
488 self.missionState = self.TRANSMIT_INITIAL_LOCATION
489 self.shipPositions = {}
490 self.ship2patrolData = {}
491 self.ship2patrolDataSuggestions = []
492 self.reachedStartPoint = set()
493
494 self.myStartingPatrolPosition = None
495 self.myPatrolPath = []
496 self.nextTaskPointIndex = None
497 self.navigationTactic = None
498
499
500
502
503 self.time += 1
504
505 self.processIncomingMsgs(agentWorldModel)
506
507
508 returnedAction = CompositeAction()
509 returnedAction.appendAction(PrimitiveAction("stop", []))
510
511 if self.missionState == self.TRANSMIT_INITIAL_LOCATION:
512 myState = agentWorldModel.getEstimatedExtShipState()
513 self.transmit(
514 PrimitiveMessage(PrimitiveMessage.TO_ALL,
515 PrimitiveMessage.TYPE_POSITION,
516 (agentWorldModel.shipIndex, myState.x, myState.y))
517 )
518
519 self.missionState = self.COMPUTE_PATROL_ASSIGNMENTS_AND_TRANSMIT
520
521
522 elif self.missionState == self.COMPUTE_PATROL_ASSIGNMENTS_AND_TRANSMIT:
523 numShips = len(self.shipPositions)
524 patrolPoints, paths, patrolStartingStates = heuristicDivide.run(numShips,
525 self.patrolPoints, self.edgeLengths, debug=False)
526 state2ship = self.assignShipsToStates(self.shipPositions, patrolStartingStates)
527
528 self.ship2patrolData = {}
529 for i, start_and_path in enumerate(zip(patrolStartingStates, paths)):
530 start, path = start_and_path
531 ship = state2ship[i]
532 self.ship2patrolData[ship] = (start, path)
533 msgContent = self.ship2patrolData
534 self.transmit(
535 PrimitiveMessage(PrimitiveMessage.TO_ALL,
536 PrimitiveMessage.TYPE_PATROL_DIVISION,
537 msgContent)
538 )
539
540 self.missionState = self.VOTE
541
542
543 elif self.missionState == self.VOTE:
544 for suggestion in self.ship2patrolDataSuggestions:
545 if not suggestion == self.ship2patrolData:
546 print 'suggestion', suggestion
547 print 'mysuggestion', self.ship2patrolData
548 raise Exception("vote failed - need to be implemented")
549
550 self.myStartingPatrolPosition, self.myPatrolPath = self.ship2patrolData[self.agentIndex]
551 self.missionState = self.MOVING_TO_START
552
553
554 elif self.missionState == self.MOVING_TO_START:
555 if self.navigationTactic == None:
556 pos = self.myStartingPatrolPosition
557 self.setNavigationTactic(agentWorldModel,
558 (pos.x, pos.y))
559
560
561
562
563 if self.navigationTactic.done(agentWorldModel):
564 msgContent = self.agentIndex
565 self.transmit(
566 PrimitiveMessage(PrimitiveMessage.TO_ALL,
567 PrimitiveMessage.TYPE_REACHED_START,
568 msgContent)
569 )
570
571
572 pos = self.myStartingPatrolPosition
573 self.setNavigationTactic(agentWorldModel,
574 (pos.x, pos.y))
575 returnedAction = self.navigationTactic.composeAction(agentWorldModel)
576 if self.allReachedStartingPoints():
577 print 'allReachedStartingPoints'
578 self.missionState = self.PATROLING
579
580 self.nextTaskPointIndex = 0
581 self.setNavigationTactic(agentWorldModel,
582 self.myPatrolPath[self.nextTaskPointIndex])
583
584 elif self.missionState == self.PATROLING:
585 if self.navigationTactic.done(agentWorldModel):
586 self.nextTaskPointIndex = (self.nextTaskPointIndex + 1) % len(self.myPatrolPath)
587 self.setNavigationTactic(agentWorldModel,
588 self.myPatrolPath[self.nextTaskPointIndex])
589
590 self.recordStatistics()
591
592
593
594
595
596
597
598 returnedAction = self.navigationTactic.composeAction(agentWorldModel)
599
600
601 return returnedAction
602
620
644
646 """
647 Reads incoming msgs from the agentWorldModel
648 and clean its queue
649
650 @type agentWorldModel: AgentWorldModel
651 @param agentWorldModel: the world model, which contain msgs.
652 """
653 for msg in agentWorldModel.incomingMsgs.primitiveMsgs:
654
655 if msg.to != PrimitiveMessage.TO_ALL:
656 raise Exception("Message doesn't seem to be directed at me")
657
658 getattr(self, self.msgCallbacks[msg.type])(msg.content)
659
661 """
662 Implements a matching algorithm
663
664 @type shipPositions: map[shipIndex] = (x,y) position
665 @param shipPositions: map of the transmitted positions of ships
666
667 @type patrolStartingStates: array of [shipExternalState, ... ] for all ships
668 @param patrolStartingStates: the starting states computed by heuristicDivide
669
670 @rtype: map[shipIndex] = shipStartingState
671 @return: mapping of each ship to its patrol starting state
672 """
673 numShips = len(shipPositions)
674 if not numShips == len(patrolStartingStates):
675 raise Exception("number of ships must be equal to num patrol start points")
676
677
678 edges = []
679 for shipIndex, position in shipPositions.items():
680 distances = [geometry.distance2D(position, (state.x, state.y)) for state in patrolStartingStates]
681 edges += [(shipIndex, i, dist) for i, dist in enumerate(distances)]
682 edges = sorted(edges, key=operator.itemgetter(2), reverse=True)
683
684
685
686 shipNumEdges = {}
687 posNumEdges = {}
688 numOutgoingEdges = numShips
689 for i in range(numOutgoingEdges):
690 shipNumEdges[i] = numOutgoingEdges
691 posNumEdges[i] = numOutgoingEdges
692
693 match = []
694 matchedShips = set()
695 matchedPositions = set()
696
697
698
699
700
701 while len(match) < numShips:
702 deletedShips = set()
703 deletedPositions = set()
704 for edge in edges:
705 shipIndex, posIndex, dist = edge
706
707 if shipIndex in deletedShips or posIndex in deletedPositions:
708 continue
709
710 if shipNumEdges[shipIndex] == 1 or posNumEdges[posIndex] == 1:
711 match.append(edge)
712 deletedShips.add(shipIndex)
713 deletedPositions.add(posIndex)
714 matchedShips.add(shipIndex)
715 matchedPositions.add(posIndex)
716
717 shipNumEdges[shipIndex] -= 1
718 posNumEdges[posIndex] -= 1
719
720
721 newEdges = []
722 for edge in edges:
723 shipIndex, posIndex, dist = edge
724 if shipIndex in matchedShips or posIndex in matchedPositions:
725 continue
726 else:
727 newEdges.append(edge)
728 edges = newEdges
729
730
731
732 state2Ship = {}
733 for edge in match:
734 shipIndex, posIndex, dist = edge
735 state2Ship[posIndex] = shipIndex
736
737 return state2Ship
738
740 numShips = len(self.shipPositions)
741 if len(self.reachedStartPoint) == numShips:
742 return True
743 else:
744 return False
745
747 return self.myPatrolPath
748
749
751 """
752 Processes a msg that notifies ships to start patrol
753
754 @type msgContent: None
755 @param msgContent: no additional information currently needed
756 """
757 self.reset()
758
760 """
761 Processes a msg that notifies other ship's position
762
763 @type msgContent: a 3-tuple (shipIndex, x, y)
764 @param msgContent: the position of the sending ship
765 """
766 shipIndex, x, y = msgContent
767 self.shipPositions[shipIndex] = (x,y)
768
770 """
771 Processes a msg that notifies other ship's patrol suggestion
772
773 @type msgContent: map[int] = (pos, list-of-positions)
774 @param msgContent: for each ship, a starting position and a path
775 """
776 self.ship2patrolDataSuggestions.append(msgContent)
777
779 """
780 Processes a msg that notifies some ship reached its start pos
781
782 @type msgContent: int
783 @param msgContent: an index of an agent that reached start
784 """
785 self.reachedStartPoint.add(msgContent)
786
787
789 """
790 Implements an agent that waits for some time,
791 then joins a coordinated patrol - this is why it is a coordinated
792 patrol
793 """
794
795 - def __init__(self, agentIndex, patrolPoints, edgeLengths, rulesOfTheSea):
796 """
797 Initializes the strategy.
798
799 @type agentIndex: int
800 @param agentIndex: sort of an agent-id - an agent's index in the array of all agents
801
802 @type agentIndex: string
803 @param agentIndex: the name of the file containing edges and nodes from measurements data
804
805 @type rulesOfTheSea: boolean
806 @param rulesOfTheSea: Tells whether to respect the rules of the sea
807 """
808 AgentCoordinatedPatrolStrategy.__init__(self, agentIndex, patrolPoints, edgeLengths, rulesOfTheSea)
809
810 self.waitingTime = 1000
811 self.currentTime = 0
812
834
835
837 """
838 Implements a basic patrol strategy.
839 Given points of interest, just travel
840 along the cycle they define
841 """
842
843
844 TRANSMIT_LOCATION = 1
845 COMPUTE_PATROL_ASSIGNMENTS_AND_TRANSMIT = 2
846 VOTE_AND_SET_NAV_TARGET = 3
847
848
849
850 - def __init__(self, agentIndex, trackedShipIndices,
851 trackingShipIndices, trackingDistance, positionOffsets,
852 rulesOfTheSea):
853 """
854 Initializes the strategy.
855
856 @type agentIndex: int
857 @param agentIndex: sort of an agent-id - an agent's index in the array of all agents
858
859 @type trackedShipIndices: a list of integer indices
860 @param trackedShipIndices: a list of indices of tracked ships
861
862 @type trackingShipIndices: a list of integer indices
863 @param trackingShipIndices: a list of indices of tracking ships
864
865 @type trackingDistance: a floating point number
866 @param trackingDistance: a (close to) maximal distance for tracking/sensing
867
868 @type positionOffsets: a list of numpy 2d vectors
869 @param positionOffsets: offsets for all tracking ships
870
871 @type rulesOfTheSea: boolean
872 @param rulesOfTheSea: Tells whether to respect the rules of the sea
873 """
874 AgentStrategy.__init__(self)
875
876 self.agentIndex = agentIndex
877 self.trackedShipIndices = trackedShipIndices
878 self.trackingShipIndices = trackingShipIndices
879 self.trackingDistance = trackingDistance
880 self.positionOffsets = positionOffsets
881 self.rulesOfTheSea = rulesOfTheSea
882
883 self.navigationTactic = None
884
885 self.reset()
886
887 self.missionState = self.TRANSMIT_LOCATION
888
889
890 self.msgCallbacks = {}
891 self.msgCallbacks[PrimitiveMessage.TYPE_TRACKING_POINT] = self.processMsgTrackingPoint.__name__
892 self.msgCallbacks[PrimitiveMessage.TYPE_NAVIGATION_CENTRAL_POINT] = self.processMsgNavigationCentralPoint.__name__
893 self.msgCallbacks[PrimitiveMessage.TYPE_POSITIONS_ASSIGNMENT] = self.processMsgPositionAssignments.__name__
894
895 self.time = 0
896
898 self.trackingPoints = {}
899 self.navCentralPoint = {}
900 self.ship2positionSuggestions = []
901
917
919 if self.navigationTactic == None:
920
921 shipState = agentWorldModel.getEstimatedExtShipState()
922 self.setNavigationTactic(agentWorldModel, (shipState.x, shipState.y))
923
924 if self.missionState == self.TRANSMIT_LOCATION:
925 self.trackingPoint = self.computedAvgPosOfTrackedShips(agentWorldModel)
926 self.transmit(
927 PrimitiveMessage(PrimitiveMessage.TO_ALL,
928 PrimitiveMessage.TYPE_TRACKING_POINT,
929 self.trackingPoint)
930 )
931 self.navigationCentralPoint = self.computedAvgPosOfTrackingShips(agentWorldModel)
932 self.transmit(
933 PrimitiveMessage(PrimitiveMessage.TO_ALL,
934 PrimitiveMessage.TYPE_NAVIGATION_CENTRAL_POINT,
935 self.navigationCentralPoint)
936 )
937 self.missionState = self.COMPUTE_PATROL_ASSIGNMENTS_AND_TRANSMIT
938
939 elif self.missionState == self.COMPUTE_PATROL_ASSIGNMENTS_AND_TRANSMIT:
940 goal = self.computeNextGoal(agentWorldModel)
941 targets = self.generateNewTargets(goal, self.trackingPoint)
942 trackingShipPositions = self.getTrackingShipLocations(agentWorldModel)
943 self.ship2state = self.assignShipsToStates(trackingShipPositions, targets)
944 msgContent = self.ship2state
945 self.transmit(
946 PrimitiveMessage(PrimitiveMessage.TO_ALL,
947 PrimitiveMessage.TYPE_POSITIONS_ASSIGNMENT,
948 msgContent)
949 )
950
951 self.missionState = self.VOTE_AND_SET_NAV_TARGET
952
953 elif self.missionState == self.VOTE_AND_SET_NAV_TARGET:
954 for suggestion in self.ship2positionSuggestions:
955 if not suggestion == self.ship2state:
956 print 'suggestion', suggestion
957 print 'mysuggestion', self.ship2state
958 raise Exception("vote failed - need to be implemented")
959
960 self.myStartingPatrolPosition = self.ship2state[self.agentIndex]
961 goalPos = self.myStartingPatrolPosition
962 self.setNavigationTactic(agentWorldModel, goalPos)
963
964 self.missionState = self.TRANSMIT_LOCATION
965 self.reset()
966
967
969 """
970 Computes the next goal for the tracking strategy.
971 """
972 trackingPoint = self.computedAvgPosOfTrackedShips(agentWorldModel)
973 navigationCentralPoint = self.computedAvgPosOfTrackingShips(agentWorldModel)
974 distToTarget = geometry.distance2D(navigationCentralPoint, trackingPoint)
975 newTrgt = navigationCentralPoint + (trackingPoint - navigationCentralPoint) * (1 - self.trackingDistance / distToTarget)
976 return newTrgt
977
983
988
1006
1008 return [self.navigationTactic.goalPoint]
1009
1033
1035 """
1036 Reads incoming msgs from the agentWorldModel
1037 and clean its queue
1038
1039 @type agentWorldModel: AgentWorldModel
1040 @param agentWorldModel: the world model, which contain msgs.
1041 """
1042 for msg in agentWorldModel.incomingMsgs.primitiveMsgs:
1043
1044 if msg.to != PrimitiveMessage.TO_ALL:
1045 raise Exception("Message doesn't seem to be directed at me")
1046
1047 getattr(self, self.msgCallbacks[msg.type])(msg.content)
1048
1050 """
1051 Processes a msg that notifies the tracking point - avg location of tracked
1052 ships
1053
1054 @type msgContent: a tuple (int, numpy.array[(x,y)])
1055 @param msgContent: (suggestingShipIndex, suggestedTrackingPoint)
1056 """
1057 suggestingShipIndex, trackingPoint = msgContent
1058 self.trackingPoints[suggestingShipIndex] = trackingPoint
1059
1061 """
1062 Processes a msg that notifies the central navigation point -
1063 the point from which ship offsets are computed
1064
1065 @type msgContent: a tuple (int, numpy.array[(x,y)])
1066 @param msgContent: (suggestingShipIndex, suggestedNavigationPoint)
1067 """
1068 suggestingShipIndex, navPoint = msgContent
1069 self.navCentralPoint[suggestingShipIndex] = navPoint
1070
1072 """
1073 Processes a msg that notifies other ship's patrol suggestion
1074
1075 @type msgContent: map[int] = (pos)
1076 @param msgContent: for each ship, a target position
1077 """
1078
1079 self.ship2positionSuggestions.append(msgContent)
1080
1082 """
1083 Implements a matching algorithm
1084
1085 @type shipPositions: map[shipIndex] = (x,y) position
1086 @param shipPositions: map of the transmitted positions of ships
1087
1088 @type targets: array of [(x,y), ... ] for all ships
1089 @param targets: the target locations for tracking
1090
1091 @rtype: map[shipIndex] = shipStartingState
1092 @return: mapping of each ship to its patrol starting state
1093 """
1094 numShips = len(shipPositions)
1095 if not numShips == len(targets):
1096 raise Exception("number of ships must be equal to num patrol start points")
1097
1098
1099 edges = []
1100 for shipIndex, position in shipPositions.items():
1101 distances = [geometry.distance2D(position, target) for target in targets]
1102 edges += [(shipIndex, i, dist) for i, dist in enumerate(distances)]
1103 edges = sorted(edges, key=operator.itemgetter(2), reverse=True)
1104
1105
1106
1107 shipNumEdges = {}
1108 posNumEdges = {}
1109 numOutgoingEdges = numShips
1110 for i in range(numOutgoingEdges):
1111 posNumEdges[i] = numOutgoingEdges
1112 for shipIndex in shipPositions.keys():
1113 shipNumEdges[shipIndex] = numOutgoingEdges
1114
1115 match = []
1116 matchedShips = set()
1117 matchedPositions = set()
1118
1119
1120
1121
1122
1123 while len(match) < numShips:
1124 deletedShips = set()
1125 deletedPositions = set()
1126 for edge in edges:
1127 shipIndex, posIndex, dist = edge
1128
1129 if shipIndex in deletedShips or posIndex in deletedPositions:
1130 continue
1131
1132 if shipNumEdges[shipIndex] == 1 or posNumEdges[posIndex] == 1:
1133 match.append(edge)
1134 deletedShips.add(shipIndex)
1135 deletedPositions.add(posIndex)
1136 matchedShips.add(shipIndex)
1137 matchedPositions.add(posIndex)
1138
1139 shipNumEdges[shipIndex] -= 1
1140 posNumEdges[posIndex] -= 1
1141
1142
1143 newEdges = []
1144 for edge in edges:
1145 shipIndex, posIndex, dist = edge
1146 if shipIndex in matchedShips or posIndex in matchedPositions:
1147 continue
1148 else:
1149 newEdges.append(edge)
1150 edges = newEdges
1151
1152
1153 ship2state = {}
1154 for edge in match:
1155 shipIndex, posIndex, dist = edge
1156 ship2state[shipIndex] = tuple(targets[posIndex])
1157
1158 return ship2state
1159
1161 """
1162 returns a list of x,y coordinates of tracked ships
1163 """
1164 states = dict( (i, (s.x, s.y)) for i,s in
1165 zip(self.trackedShipIndices,
1166 agentWorldModel.getEstimatedStatesOfShips(self.trackedShipIndices) ) )
1167 return states
1168
1170 """
1171 returns a list of x,y coordinates of tracking ships
1172 """
1173 states = dict( (i, (s.x, s.y)) for i,s in
1174 zip(self.trackingShipIndices,
1175 agentWorldModel.getEstimatedStatesOfShips(self.trackingShipIndices) ) )
1176 return states
1177
1179 """
1180 Given the new goal and vector offsets - generate new targets.
1181 """
1182
1183 direction = trackingPoint - goal
1184 direction = direction / numpy.linalg.norm(direction)
1185 perpendicular = numpy.dot(numpy.array([[0,1], [-1,0]]), direction)
1186 goal = numpy.array(goal)
1187 return [ goal + offset[0] * direction + offset[1] * perpendicular for offset in self.positionOffsets]
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1562 """
1563 This is a class for an agent that controls a ship.
1564 An agent has two main components: it's world model,
1565 and its decision-making strategy.
1566 """
1567 - def __init__(self, worldModel, strategy):
1568 self.worldModel = worldModel
1569 self.strategy = strategy
1570
1572 """
1573 A template method.
1574 Choose an action based on current percepts
1575
1576 @type percepts: PerceptList
1577 @param percepts: A list of percepts sent to the agent for this decision cycle
1578
1579 @rtype: CompositeAction
1580 @return: A list of actions to be executed on the ship
1581 """
1582 self.worldModel.processPercepts(percepts)
1583 action = self.strategy.composeAction(self.worldModel)
1584 self.worldModel.cleanMsgQueue()
1585 return action
1586
1588 """
1589 msg is received by the agent using this function
1590
1591 @type msg: PrimitiveMessage
1592 @param msg: a primitive message sent to the agent.
1593 """
1594
1595
1596 return self.worldModel.receiveMsg(msg)
1597
1599 """
1600 Returns any message that strategy created
1601
1602 @rtype: CompositeMessage
1603 @return: The agents' outgoing message for this decision cycle
1604 """
1605 return self.strategy.getOutgoingMessage()
1606