1 package cz.cuni.amis.pogamut.ut2004.agent.navigation;
2
3 import java.util.EventListener;
4 import java.util.HashSet;
5 import java.util.Set;
6 import java.util.logging.Level;
7
8 import cz.cuni.amis.pogamut.base.agent.navigation.IPathExecutorState;
9 import cz.cuni.amis.pogamut.base.agent.navigation.PathExecutorState;
10 import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
11 import cz.cuni.amis.pogamut.base.utils.logging.LogCategory;
12 import cz.cuni.amis.pogamut.base3d.worldview.object.ILocated;
13 import cz.cuni.amis.pogamut.ut2004.agent.module.sensor.NavigationGraphBuilder;
14 import cz.cuni.amis.pogamut.ut2004.agent.navigation.astar.UT2004AStar;
15 import cz.cuni.amis.pogamut.ut2004.agent.navigation.floydwarshall.FloydWarshallMap;
16 import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
17 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BotDamaged;
18 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BotKilled;
19 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPointNeighbourLink;
20 import cz.cuni.amis.pogamut.ut2004.communication.worldview.map.UT2004Map;
21 import cz.cuni.amis.utils.NullCheck;
22 import cz.cuni.amis.utils.flag.FlagListener;
23 import cz.cuni.amis.utils.listener.Listeners;
24 import cz.cuni.amis.utils.maps.CountIntMap;
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 public class UT2004PathAutoFixer {
44
45
46
47 public static final int REAMOVE_EDGE_AFTER_N_FAILURES_DEFAULT = 2;
48
49 private IUT2004PathExecutor<? extends ILocated> pathExecutor;
50 private FloydWarshallMap fwMap;
51 private UT2004AStar aStar;
52 private NavigationGraphBuilder navBuilder;
53
54 private CountIntMap<NavPointNeighbourLink> badLinks = new CountIntMap<NavPointNeighbourLink>();
55
56 private Set<NavPointNeighbourLink> removedLinks = new HashSet<NavPointNeighbourLink>();
57
58 private LogCategory log;
59
60 private int removeBadEdgeAfterNFailures;
61
62 private boolean botHarmed;
63
64 private IWorldEventListener<BotDamaged> botDamagedListener = new IWorldEventListener<BotDamaged>() {
65
66 @Override
67 public void notify(BotDamaged event) {
68 botDamaged();
69 }
70
71 };
72
73 private IWorldEventListener<BotKilled> botKilledListener = new IWorldEventListener<BotKilled>() {
74
75 @Override
76 public void notify(BotKilled event) {
77 botKilled();
78 }
79
80 };
81
82
83
84
85
86
87
88
89
90
91 public UT2004PathAutoFixer(UT2004Bot bot, IUT2004PathExecutor<? extends ILocated> pathExecutor, FloydWarshallMap fwMap, UT2004AStar aStar, NavigationGraphBuilder navBuilder) {
92 this(bot, pathExecutor, fwMap, aStar, navBuilder, REAMOVE_EDGE_AFTER_N_FAILURES_DEFAULT);
93 }
94
95
96
97
98
99
100
101
102
103
104 public UT2004PathAutoFixer(UT2004Bot bot, IUT2004PathExecutor<? extends ILocated> pathExecutor, FloydWarshallMap fwMap, UT2004AStar aStar, NavigationGraphBuilder navBuilder, int removeBadEdgeAfterNFailures) {
105 if (removeBadEdgeAfterNFailures < 1) {
106 throw new IllegalArgumentException("removeBadEdgeAfterNFailures == " + removeBadEdgeAfterNFailures + " < 1 cannot be!");
107 }
108 this.log = bot.getLogger().getCategory(UT2004PathAutoFixer.class.getSimpleName());
109 this.pathExecutor = pathExecutor;
110 this.fwMap = fwMap;
111 this.aStar = aStar;
112 this.navBuilder = navBuilder;
113
114 NullCheck.check(this.pathExecutor, "pathExecutor");
115 NullCheck.check(this.navBuilder, "navBuilder");
116
117 this.removeBadEdgeAfterNFailures = removeBadEdgeAfterNFailures;
118
119 this.pathExecutor.getState().addListener(new FlagListener<IPathExecutorState>() {
120
121 @Override
122 public void flagChanged(IPathExecutorState changedValue) {
123 switch (changedValue.getState()) {
124 case PATH_COMPUTED:
125 pathComputed();
126 return;
127 case SWITCHED_TO_ANOTHER_PATH_ELEMENT:
128 switchedToNewElement();
129 return;
130 case STUCK:
131 stuck();
132 return;
133
134 }
135 }
136
137 });
138
139 bot.getWorldView().addEventListener(BotDamaged.class, botDamagedListener);
140 bot.getWorldView().addEventListener(BotKilled.class, botKilledListener);
141 }
142
143 protected void botDamaged() {
144
145 botHarmed = true;
146 }
147
148 protected void botKilled() {
149
150 botHarmed = true;
151 }
152
153 protected void switchedToNewElement() {
154
155
156 botHarmed = false;
157 }
158
159 protected void pathComputed() {
160
161 botHarmed = false;
162 }
163
164 protected void stuck() {
165 if (botHarmed) {
166
167
168 return;
169 }
170
171 NavPointNeighbourLink link = pathExecutor.getCurrentLink();
172 if (link == null) return;
173
174 badLinks.increase(link);
175 checkRemove(link);
176 }
177
178
179
180
181
182 protected void checkRemove(NavPointNeighbourLink link) {
183 if (log != null && log.isLoggable(Level.WARNING)) log.warning("Bot has stuck (" + badLinks.get(link) + "x) on link " + link);
184 if (badLinks.get(link) >= removeBadEdgeAfterNFailures) {
185 listenerLink = link;
186 listenersLinkCanRemove = true;
187 linkRemovalListeners.notify(canRemoveLinkNotifier);
188 if (listenersLinkCanRemove) {
189 removeLink(link);
190 } else {
191 if (log != null && log.isLoggable(Level.WARNING)) log.warning("Some listener prevented link from removal: " + link);
192 }
193 }
194 }
195
196
197
198
199
200 protected void removeLink(NavPointNeighbourLink link) {
201 String fromId = link.getFromNavPoint().getId().getStringId();
202 String toId = link.getToNavPoint().getId().getStringId();
203 if (log != null && log.isLoggable(Level.WARNING)) log.warning("REMOVING EDGE FROM NAV-GRAPTH (affects fwMap): " + fromId + " -> " + toId);
204 navBuilder.removeEdge(fromId, toId);
205 removedLinks.add(link);
206 if (fwMap != null) fwMap.refreshPathMatrix();
207 if (aStar != null) aStar.mapChanged();
208
209 listenerLink = link;
210 linkRemovalListeners.notify(linkRemovedNotifier);
211 }
212
213
214
215
216
217 public Set<NavPointNeighbourLink> getRemovedLinks() {
218 return removedLinks;
219 }
220
221
222
223
224
225
226
227 public CountIntMap<NavPointNeighbourLink> getBadLinks() {
228 return badLinks;
229 }
230
231
232
233
234
235 public static interface ILinkRemovalListener extends EventListener {
236
237
238
239
240
241
242 public boolean canRemoveLink(NavPointNeighbourLink link);
243
244
245
246
247
248 public void linkRemoved(NavPointNeighbourLink link);
249
250 }
251
252 private Listeners<ILinkRemovalListener> linkRemovalListeners = new Listeners<ILinkRemovalListener>();
253
254 public NavPointNeighbourLink listenerLink;
255
256 public boolean listenersLinkCanRemove = true;
257
258 private Listeners.ListenerNotifier<ILinkRemovalListener> canRemoveLinkNotifier = new Listeners.ListenerNotifier<ILinkRemovalListener>() {
259
260 @Override
261 public NavPointNeighbourLink getEvent() {
262 return listenerLink;
263 }
264
265 @Override
266 public void notify(ILinkRemovalListener listener) {
267 listenersLinkCanRemove = listenersLinkCanRemove && listener.canRemoveLink(listenerLink);
268 }
269
270 };
271
272 private Listeners.ListenerNotifier<ILinkRemovalListener> linkRemovedNotifier = new Listeners.ListenerNotifier<ILinkRemovalListener>() {
273
274 @Override
275 public NavPointNeighbourLink getEvent() {
276 return listenerLink;
277 }
278
279 @Override
280 public void notify(ILinkRemovalListener listener) {
281 listener.linkRemoved(listenerLink);
282 }
283
284 };
285
286 public void addListener(ILinkRemovalListener listener) {
287 linkRemovalListeners.addStrongListener(listener);
288 }
289
290 public void removeListener(ILinkRemovalListener listener) {
291 linkRemovalListeners.removeListener(listener);
292 }
293
294 public boolean isListener(ILinkRemovalListener listener) {
295 return linkRemovalListeners.isListening(listener);
296 }
297
298 }