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