001package squidpony.squidai; 002 003import squidpony.squidgrid.Radius; 004import squidpony.squidmath.Coord; 005import squidpony.squidmath.OrderedMap; 006 007import java.io.Serializable; 008import java.util.ArrayList; 009import java.util.Collection; 010 011/** 012 * An AOE type that has a center Coord only and only affects that single Coord. Useful if you need an AOE implementation 013 * for something that does not actually affect an area. 014 * This will produce doubles for its {@link #findArea()} method which are equal to 1.0. 015 * 016 * This class doesn't use any other SquidLib class to create its area of effect. 017 * Created by Tommy Ettinger on 7/13/2015. 018 */ 019public class PointAOE implements AOE, Serializable { 020 private static final long serialVersionUID = 2L; 021 private Coord center, origin; 022 private int mapWidth, mapHeight; 023 private Reach reach = new Reach(1, 1, Radius.SQUARE, AimLimit.FREE); 024 025 public PointAOE(Coord center) 026 { 027 this.center = center; 028 } 029 public PointAOE(Coord center, int minRange, int maxRange) 030 { 031 this.center = center; 032 reach.minDistance = minRange; 033 reach.maxDistance = maxRange; 034 } 035 036 public Coord getCenter() { 037 return center; 038 } 039 040 041 public void setCenter(Coord center) { 042 043 if (center.isWithin(mapWidth, mapHeight) && 044 AreaUtils.verifyReach(reach, origin, center)) 045 { 046 this.center = center; 047 } 048 } 049 050 @Override 051 public void shift(Coord aim) { 052 setCenter(aim); 053 } 054 055 @Override 056 public boolean mayContainTarget(Collection<Coord> targets) { 057 for (Coord p : targets) 058 { 059 if(center.x == p.x && center.y == p.y) 060 return true; 061 } 062 return false; 063 } 064 065 @Override 066 public OrderedMap<Coord, ArrayList<Coord>> idealLocations(Collection<Coord> targets, Collection<Coord> requiredExclusions) { 067 if(targets == null) 068 return new OrderedMap<>(); 069 070 int totalTargets = targets.size(); 071 OrderedMap<Coord, ArrayList<Coord>> bestPoints = new OrderedMap<>(totalTargets); 072 073 if(totalTargets == 0) 074 return bestPoints; 075 076 077 double dist; 078 for(Coord p : targets) { 079 if (AreaUtils.verifyReach(reach, origin, p)) { 080 081 dist = reach.metric.radius(origin.x, origin.y, p.x, p.y); 082 if (dist <= reach.maxDistance && dist >= reach.minDistance) { 083 ArrayList<Coord> ap = new ArrayList<>(); 084 ap.add(p); 085 bestPoints.put(p, ap); 086 } 087 } 088 } 089 return bestPoints; 090 } 091 092 093 @Override 094 public OrderedMap<Coord, ArrayList<Coord>> idealLocations(Collection<Coord> priorityTargets, Collection<Coord> lesserTargets, Collection<Coord> requiredExclusions) { 095 if(priorityTargets == null) 096 return idealLocations(lesserTargets, requiredExclusions); 097 098 int totalTargets = priorityTargets.size() + lesserTargets.size(); 099 OrderedMap<Coord, ArrayList<Coord>> bestPoints = new OrderedMap<>(totalTargets * 4); 100 101 if(totalTargets == 0) 102 return bestPoints; 103 104 double dist; 105 106 for(Coord p : priorityTargets) { 107 if (AreaUtils.verifyReach(reach, origin, p)) { 108 109 dist = reach.metric.radius(origin.x, origin.y, p.x, p.y); 110 if (dist <= reach.maxDistance && dist >= reach.minDistance) { 111 ArrayList<Coord> ap = new ArrayList<>(); 112 ap.add(p); 113 ap.add(p); 114 ap.add(p); 115 ap.add(p); 116 bestPoints.put(p, ap); 117 } 118 } 119 } 120 if(bestPoints.isEmpty()) { 121 for (Coord p : lesserTargets) { 122 if (AreaUtils.verifyReach(reach, origin, p)) { 123 124 dist = reach.metric.radius(origin.x, origin.y, p.x, p.y); 125 if (dist <= reach.maxDistance && dist >= reach.minDistance) { 126 ArrayList<Coord> ap = new ArrayList<>(); 127 ap.add(p); 128 bestPoints.put(p, ap); 129 } 130 } 131 } 132 } 133 return bestPoints; 134 135 } 136 137 /* 138 @Override 139 public ArrayList<ArrayList<Coord>> idealLocations(Set<Coord> targets, Set<Coord> requiredExclusions) { 140 int totalTargets = targets.size() + 1; 141 int maxEffect = (int)radiusType.volume2D(radius); 142 ArrayList<ArrayList<Coord>> locs = new ArrayList<ArrayList<Coord>>(totalTargets); 143 144 for(int i = 0; i < totalTargets; i++) 145 { 146 locs.add(new ArrayList<Coord>(maxEffect)); 147 } 148 if(totalTargets == 1) 149 return locs; 150 151 int ctr = 0; 152 if(radius < 1) 153 { 154 locs.get(totalTargets - 2).addAll(targets); 155 return locs; 156 } 157 158 boolean[][] tested = new boolean[dungeon.length][dungeon[0].length]; 159 for (int x = 1; x < dungeon.length - 1; x += radius) { 160 BY_POINT: 161 for (int y = 1; y < dungeon[x].length - 1; y += radius) { 162 for(Coord ex : requiredExclusions) 163 { 164 if(radiusType.radius(x, y, ex.x, ex.y) <= radius) 165 continue BY_POINT; 166 } 167 ctr = 0; 168 for(Coord tgt : targets) 169 { 170 if(radiusType.radius(x, y, tgt.x, tgt.y) <= radius) 171 ctr++; 172 } 173 if(ctr > 0) 174 locs.get(totalTargets - ctr).add(Coord.get(x, y)); 175 } 176 } 177 Coord it; 178 for(int t = 0; t < totalTargets - 1; t++) 179 { 180 if(locs.get(t).size() > 0) { 181 int numPoints = locs.get(t).size(); 182 for (int i = 0; i < numPoints; i++) { 183 it = locs.get(t).get(i); 184 for (int x = Math.max(1, it.x - radius / 2); x < it.x + (radius + 1) / 2 && x < dungeon.length - 1; x++) { 185 BY_POINT: 186 for (int y = Math.max(1, it.y - radius / 2); y <= it.y + (radius - 1) / 2 && y < dungeon[0].length - 1; y++) 187 { 188 if(tested[x][y]) 189 continue; 190 tested[x][y] = true; 191 192 for(Coord ex : requiredExclusions) 193 { 194 if(radiusType.radius(x, y, ex.x, ex.y) <= radius) 195 continue BY_POINT; 196 } 197 198 ctr = 0; 199 for(Coord tgt : targets) 200 { 201 if(radiusType.radius(x, y, tgt.x, tgt.y) <= radius) 202 ctr++; 203 } 204 if(ctr > 0) 205 locs.get(totalTargets - ctr).add(Coord.get(x, y)); 206 } 207 } 208 } 209 } 210 } 211 return locs; 212 } 213*/ 214 @Override 215 public void setMap(char[][] map) { 216 if (map != null && map.length > 0) { 217 mapWidth = map.length; 218 mapHeight = map[0].length; 219 } 220 } 221 222 @Override 223 public OrderedMap<Coord, Double> findArea() { 224 OrderedMap<Coord, Double> ret = new OrderedMap<>(1); 225 ret.put(Coord.get(center.x, center.y), 1.0); 226 return ret; 227 } 228 229 230 @Override 231 public Coord getOrigin() { 232 return origin; 233 } 234 235 @Override 236 public void setOrigin(Coord origin) { 237 this.origin = origin; 238 239 } 240 241 @Override 242 public AimLimit getLimitType() { 243 return reach.limit; 244 } 245 246 @Override 247 public int getMinRange() { 248 return reach.minDistance; 249 } 250 251 @Override 252 public int getMaxRange() { 253 return reach.maxDistance; 254 } 255 256 @Override 257 public Radius getMetric() { 258 return reach.metric; 259 } 260 261 /** 262 * Gets the same values returned by getLimitType(), getMinRange(), getMaxRange(), and getMetric() bundled into one 263 * Reach object. 264 * 265 * @return a non-null Reach object. 266 */ 267 @Override 268 public Reach getReach() { 269 return reach; 270 } 271 272 @Override 273 public void setLimitType(AimLimit limitType) { 274 reach.limit = limitType; 275 276 } 277 278 @Override 279 public void setMinRange(int minRange) { 280 reach.minDistance = minRange; 281 } 282 283 @Override 284 public void setMaxRange(int maxRange) { 285 reach.maxDistance = maxRange; 286 287 } 288 289 @Override 290 public void setMetric(Radius metric) { 291 reach.metric = metric; 292 } 293 294 /** 295 * Sets the same values as setLimitType(), setMinRange(), setMaxRange(), and setMetric() using one Reach object. 296 * 297 * @param reach a non-null Reach object. 298 */ 299 @Override 300 public void setReach(Reach reach) { 301 302 } 303 304}