View Javadoc

1   package cz.cuni.amis.pogamut.ut2004.agent.module.utils;
2   
3   import java.util.Collection;
4   import java.util.HashMap;
5   import java.util.HashSet;
6   import java.util.Iterator;
7   import java.util.Map;
8   import java.util.Set;
9   
10  
11  import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
12  import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
13  import cz.cuni.amis.pogamut.base.utils.math.DistanceUtils;
14  import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
15  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BeginMessage;
16  import cz.cuni.amis.utils.IFilter;
17  
18  /**
19   * This class is a simple implementation of TabooSet (similar to TabooList). It allows you to insert
20   * items that are taboo either for infinite time (via {@link TabooSet#add(Object)}) or for a specified
21   * amount of UT2004 time (via {@link TabooSet#add(Object, double)}).
22   * <p><p>
23   * Items inside taboo set are either removed automatically due to a timeout (a specified amount of time has passed)
24   * or manually via {@link TabooSet#remove(Object)}.
25   */
26  public class TabooSet<T> implements IFilter<T>, Collection<T> {
27  	
28  	public static interface IRelaxedTaboo<T> {
29  		
30  		public boolean isTaboo(T item, double remainingTabooTime);
31  		
32  	}
33  	
34  	/**
35  	 * Map of tabu items together with their time until which they are valid (negative time == valid for infinity).
36  	 */
37  	private Map<T, Double> taboo = new HashMap<T, Double>();	
38  		
39  	/**
40  	 * If not tabooized forever, it returns remaining time for the item to remain taboo.
41  	 * <p><p>
42  	 * If tabooized forever, returns {@link Double#POSITIVE_INFINITY}.
43  	 * <p><p>
44  	 * If item is not tabooized, returns 0.
45  	 * 
46  	 * @param item
47  	 * @return
48  	 */
49  	public double getTabooTime(T item) {
50  		Double tabooTime = taboo.get(item);
51  		if (tabooTime == null) return 0;
52  		if (tabooTime < 0) return Double.POSITIVE_INFINITY;
53  		if (tabooTime < time) {
54  			taboo.remove(item);
55  			return 0;
56  		} else {
57  			return tabooTime - time;
58  		}
59  	}
60  	
61  	/**
62  	 * Determines whether an 'item' is inside tabu set or not based on the current
63  	 * UT2004 time.
64  	 * @param item
65  	 * @return
66  	 */
67  	public boolean isTaboo(T item) {
68  		if (taboo.containsKey(item)) {
69  			double tabooTime = taboo.get(item);
70  			if (tabooTime < 0) {
71  				return true;
72  			}
73  			if (tabooTime < time) {
74  				taboo.remove(item);
75  				return false;
76  			} else {
77  				return true;
78  			}
79  		} else {
80  			return false;
81  		}
82  	}
83  	
84  	/**
85  	 * Determines whether an 'item' is considered to be taboo using relaxed 'estimator'.
86  	 * @param item
87  	 * @param estimator
88  	 * @return
89  	 */
90  	public boolean isTaboo(T item, IRelaxedTaboo estimator) {
91  		if (!isTaboo(item)) {
92  			return false;
93  		} else {
94  			return estimator.isTaboo(item, getTabooTime(item));
95  		}
96  	}
97  	
98  	/**
99  	 * Method that is used by {@link DistanceUtils} methods to filter items.
100 	 * @param item
101 	 * @return returns !{@link TabooSet#isTaboo(Object)}
102 	 */
103 	@Override
104 	public boolean isAccepted(T item) {
105 		return !isTaboo(item);
106 	}
107 	
108 	
109 	/**
110 	 * Filters collection according to the current state of the tabu set. It returns a new hash set
111 	 * containing items from 'collection' that are not inside tabu set.
112 	 * 
113 	 * @param collection
114 	 * @return
115 	 */
116 	public Set<T> filter(Collection<T> collection) {
117 		Set<T> set = new HashSet<T>();
118 		for (T t : collection) {
119 			if (isTaboo(t)) continue;
120 			set.add(t);
121 		}
122 		return set;
123 	}
124 	
125 	/**
126 	 * Filters collection according to the current state of the tabu set. It returns a new hash set
127 	 * containing items from 'collection' that are not inside tabu set.
128 	 * 
129 	 * @param collection
130 	 * @return
131 	 */
132 	public Set<T> filter(Collection<T> collection, IRelaxedTaboo estimator) {
133 		Set<T> set = new HashSet<T>();
134 		for (T t : collection) {
135 			if (!isTaboo(t)) {
136 				set.add(t);
137 			} else {
138 				if (!estimator.isTaboo(t, getTabooTime(t))) {
139 						set.add(t);
140 				}
141 			}
142 		}
143 		return set;
144 	}	
145 	
146 	/**
147 	 * Returns current UT2004 time that is used by the TabooSet.
148 	 */
149 	public double getTime() {
150 		return time;
151 	}
152 	
153 	/**
154 	 * Current UT2004 time updated by {@link TabooSet#beginMessageListener}.
155 	 */
156 	private double time;
157 	
158 	/**
159 	 * {@link BeginMessage} listener that updates {@link TabooSet#time}.
160 	 * @author Jimmy
161 	 */
162 	private class BeginMessageListener implements IWorldEventListener<BeginMessage> {
163 
164 		
165 		public BeginMessageListener(IWorldView worldView) {
166 			worldView.addEventListener(BeginMessage.class, this);
167 		}
168 
169 		@Override
170 		public void notify(BeginMessage event) {
171 			time = event.getTime();
172 		}
173 		
174 	};
175 	
176 	/**
177 	 * {@link BeginMessage} listener that updates {@link TabooSet#time}.
178 	 */
179 	BeginMessageListener beginMessageListener;
180 	
181 	/**
182 	 * Constructor of the TabuSet.
183 	 * @param bot
184 	 */
185 	public TabooSet(UT2004Bot bot) {
186 		beginMessageListener = new BeginMessageListener(bot.getWorldView());
187 	}
188 	
189 	// =======================
190 	// Collection<T> INTERFACE
191 	// =======================
192 
193 	/**
194 	 * Adds a taboo item that is valid for an infinite amount of time.
195 	 * @param item
196 	 * @return 
197 	 */
198 	public boolean add(T item) {
199 		boolean newItem = taboo.containsKey(item);
200 		taboo.put(item, (double)-1);
201 		return newItem;
202 	}
203 	
204 	/**
205 	 * Adds a tabu item that is valid for a period of 'timeout' time (in seconds).
206 	 * @param item
207 	 * @param timeout in seconds
208 	 */
209 	public void add(T item, double timeout) {
210 		taboo.put(item, time+timeout);
211 	}
212 	
213 	/**
214 	 * Removes a tabu item from the set.
215 	 * @param item
216 	 * @return 
217 	 */
218 	public boolean remove(Object item) {
219 		return taboo.remove(item) != null;
220 	}
221 	
222 	@Override
223 	public boolean isEmpty() {
224 		return taboo.isEmpty();
225 	}
226 
227 	@Override
228 	public boolean contains(Object o) {
229 		return taboo.containsKey(o);
230 	}
231 
232 	@Override
233 	public Iterator<T> iterator() {
234 		return taboo.keySet().iterator();
235 	}
236 
237 	@Override
238 	public Object[] toArray() {
239 		return taboo.keySet().toArray();
240 	}
241 
242 	@Override
243 	public <T> T[] toArray(T[] a) {
244 		return taboo.keySet().toArray(a);
245 	}
246 
247 	@Override
248 	public boolean containsAll(Collection<?> c) {
249 		return taboo.keySet().containsAll(c);
250 	}
251 
252 	@Override
253 	public boolean addAll(Collection<? extends T> c) {
254 		boolean result = false;
255 		for (T value : c) {
256 			result = result || add(value);
257 		}
258 		return result;
259 	}
260 
261 	@Override
262 	public boolean removeAll(Collection<?> c) {
263 		boolean result = false;
264 		for (Object value : c) {
265 			result = result || remove(value);
266 		}
267 		return result;
268 	}
269 
270 	@Override
271 	public boolean retainAll(Collection<?> c) {
272 		boolean result = false;
273 		Iterator<T> iterator = taboo.keySet().iterator();
274 		while (iterator.hasNext()) {
275 			T value = iterator.next();
276 			if (c.contains(value)) continue;
277 			iterator.remove();
278 			result = true;
279 		}
280 		return result;
281 	}
282 
283 	/**
284 	 * Return how many items are inside taboo set.
285 	 * @return
286 	 */
287 	@Override
288 	public int size() {
289 		return taboo.size();
290 	}
291 	
292 	/**
293 	 * Clears the taboo set.
294 	 */
295 	@Override
296 	public void clear() {
297 		taboo.clear();
298 	}
299 
300 	
301 }