001package squidpony.squidai;
002
003import squidpony.squidgrid.LOS;
004import squidpony.squidgrid.Measurement;
005import squidpony.squidgrid.Radius;
006import squidpony.squidgrid.mapping.DungeonUtility;
007import squidpony.squidmath.Coord;
008import squidpony.squidmath.OrderedMap;
009import squidpony.squidmath.OrderedSet;
010
011import java.io.Serializable;
012import java.util.ArrayList;
013import java.util.Arrays;
014import java.util.Collection;
015import java.util.Queue;
016
017/**
018 * Line Area of Effect that affects an slightly expanded (DDA) line from a given origin Coord to a given end Coord,
019 * plus an optional radius of cells around the path of the line, while respecting obstacles in its path and possibly
020 * stopping if obstructed. You can specify the RadiusType to Radius.DIAMOND for Manhattan distance, RADIUS.SQUARE for
021 * Chebyshev, or RADIUS.CIRCLE for Euclidean.
022 * <br>
023 * You may want the BeamAOE class instead of this. LineAOE travels point-to-point and does not restrict length, while
024 * BeamAOE travels a specific length (and may have a radius, like LineAOE) but then stops only after the travel down the
025 * length and radius has reached its end. This difference is relevant if a game has effects that have a definite
026 * area measured in a rectangle or elongated pillbox shape, such as a "20-foot-wide bolt of lightning, 100 feet long."
027 * BeamAOE is more suitable for that effect, while LineAOE may be more suitable for things like focused lasers that
028 * pass through small (likely fleshy) obstacles but stop after hitting the aimed-at target.
029 * <br>
030 * LineAOE will strike a small area behind the user and in the opposite direction of the target if the radius is
031 * greater than 0. This behavior may be altered in a future version.
032 * <br>
033 * This will produce doubles for its {@link #findArea()} method which are equal to 1.0.
034 * <br>
035 * This class uses {@link LOS} and {@link DijkstraMap} to create its area of effect.
036 * Created by Tommy Ettinger on 7/14/2015.
037 */
038public class LineAOE implements AOE, Serializable {
039    private static final long serialVersionUID = 2L;
040    private Coord origin, end;
041    private int radius;
042    private char[][] dungeon;
043    private DijkstraMap dijkstra;
044    private Radius rt;
045    private LOS los;
046    private Reach reach = new Reach(1, 1, Radius.SQUARE, AimLimit.FREE);
047    public LineAOE(Coord origin, Coord end)
048    {
049        dijkstra = new DijkstraMap();
050        dijkstra.measurement = Measurement.CHEBYSHEV;
051        rt = Radius.SQUARE;
052        this.origin = origin;
053        this.end = end;
054        radius = 0;
055        los = new LOS(LOS.DDA);
056    }
057    public LineAOE(Coord origin, Coord end, int radius)
058    {
059        dijkstra = new DijkstraMap();
060        dijkstra.measurement = Measurement.CHEBYSHEV;
061        rt = Radius.SQUARE;
062        this.origin = origin;
063        this.end = end;
064        this.radius = radius;
065        los = new LOS(LOS.DDA);
066    }
067    public LineAOE(Coord origin, Coord end, int radius, Radius radiusType)
068    {
069        dijkstra = new DijkstraMap();
070        rt = radiusType;
071        switch (radiusType)
072        {
073            case OCTAHEDRON:
074            case DIAMOND:
075                dijkstra.measurement = Measurement.MANHATTAN;
076                break;
077            case CUBE:
078            case SQUARE:
079                dijkstra.measurement = Measurement.CHEBYSHEV;
080                break;
081            default:
082                dijkstra.measurement = Measurement.EUCLIDEAN;
083                break;
084        }
085        this.origin = origin;
086        this.end = end;
087        this.radius = radius;
088        los = new LOS(LOS.DDA);
089    }
090    public LineAOE(Coord origin, Coord end, int radius, Radius radiusType, int minRange, int maxRange)
091    {
092        dijkstra = new DijkstraMap();
093        rt = radiusType;
094        switch (radiusType)
095        {
096            case OCTAHEDRON:
097            case DIAMOND:
098                dijkstra.measurement = Measurement.MANHATTAN;
099                break;
100            case CUBE:
101            case SQUARE:
102                dijkstra.measurement = Measurement.CHEBYSHEV;
103                break;
104            default:
105                dijkstra.measurement = Measurement.EUCLIDEAN;
106                break;
107        }
108        this.origin = origin;
109        this.end = end;
110        this.radius = radius;
111        reach.minDistance = minRange;
112        reach.maxDistance = maxRange;
113        los = new LOS(LOS.DDA);
114    }
115    private double[][] initDijkstra()
116    {
117        los.isReachable(dungeon, origin.x, origin.y, end.x, end.y, rt);
118        Queue<Coord> lit = los.getLastPath();
119
120        dijkstra.initialize(dungeon);
121        for(Coord p : lit)
122        {
123            dijkstra.setGoal(p);
124        }
125        if(radius == 0)
126            return dijkstra.gradientMap;
127        return dijkstra.partialScan(radius, null);
128    }
129
130    @Override
131    public Coord getOrigin() {
132        return origin;
133    }
134
135    @Override
136    public void setOrigin(Coord origin) {
137        this.origin = origin;
138        dijkstra.resetMap();
139        dijkstra.clearGoals();
140    }
141
142    @Override
143    public AimLimit getLimitType() {
144        return reach.limit;
145    }
146
147    @Override
148    public int getMinRange() {
149        return reach.minDistance;
150    }
151
152    @Override
153    public int getMaxRange() {
154        return reach.maxDistance;
155    }
156
157    @Override
158    public Radius getMetric() {
159        return reach.metric;
160    }
161
162    /**
163     * Gets the same values returned by getLimitType(), getMinRange(), getMaxRange(), and getMetric() bundled into one
164     * Reach object.
165     *
166     * @return a non-null Reach object.
167     */
168    @Override
169    public Reach getReach() {
170        return reach;
171    }
172
173    @Override
174    public void setLimitType(AimLimit limitType) {
175        reach.limit = limitType;
176
177    }
178
179    @Override
180    public void setMinRange(int minRange) {
181        reach.minDistance = minRange;
182    }
183
184    @Override
185    public void setMaxRange(int maxRange) {
186        reach.maxDistance = maxRange;
187
188    }
189
190    @Override
191    public void setMetric(Radius metric) {
192        reach.metric = metric;
193    }
194
195    /**
196     * Sets the same values as setLimitType(), setMinRange(), setMaxRange(), and setMetric() using one Reach object.
197     *
198     * @param reach a non-null Reach object.
199     */
200    @Override
201    public void setReach(Reach reach) {
202        if(reach != null)
203            this.reach = reach;
204    }
205
206
207    public Coord getEnd() {
208        return end;
209    }
210
211    public void setEnd(Coord end) {
212        if (dungeon != null && end.isWithin(dungeon.length, dungeon[0].length) &&
213                AreaUtils.verifyReach(reach, origin, end)) {
214            this.end = end;
215            dijkstra.resetMap();
216            dijkstra.clearGoals();
217        }
218    }
219
220    public int getRadius() {
221        return radius;
222    }
223
224    public void setRadius(int radius) {
225        this.radius = radius;
226    }
227
228    public Radius getRadiusType()
229    {
230        return rt;
231    }
232    public void setRadiusType(Radius radiusType)
233    {
234        rt = radiusType;
235        switch (radiusType)
236        {
237            case OCTAHEDRON:
238            case DIAMOND:
239                dijkstra.measurement = Measurement.MANHATTAN;
240                break;
241            case CUBE:
242            case SQUARE:
243                dijkstra.measurement = Measurement.CHEBYSHEV;
244                break;
245            default:
246                dijkstra.measurement = Measurement.EUCLIDEAN;
247                break;
248        }
249    }
250
251    @Override
252    public void shift(Coord aim) {
253        setEnd(aim);
254    }
255
256    @Override
257    public boolean mayContainTarget(Collection<Coord> targets) {
258        for (Coord p : targets)
259        {
260            if(rt.radius(origin.x, origin.y, p.x, p.y) + rt.radius(end.x, end.y, p.x, p.y) -
261                    rt.radius(origin.x, origin.y, end.x, end.y) <= 3.0 + radius)
262                return true;
263        }
264        return false;
265    }
266
267    @Override
268    public OrderedMap<Coord, ArrayList<Coord>> idealLocations(Collection<Coord> targets, Collection<Coord> requiredExclusions) {
269        if(targets == null)
270            return new OrderedMap<>();
271        if(requiredExclusions == null) requiredExclusions = new OrderedSet<>();
272
273        //requiredExclusions.remove(origin);
274        int totalTargets = targets.size();
275        OrderedMap<Coord, ArrayList<Coord>> bestPoints = new OrderedMap<>(totalTargets * 8);
276
277        if(totalTargets == 0)
278            return bestPoints;
279
280        Coord[] ts = targets.toArray(new Coord[0]);
281        Coord[] exs = requiredExclusions.toArray(new Coord[0]);
282        Coord t;
283
284        double[][][] compositeMap = new double[ts.length][dungeon.length][dungeon[0].length];
285
286        char[][] dungeonCopy = new char[dungeon.length][dungeon[0].length];
287        for (int i = 0; i < dungeon.length; i++) {
288            System.arraycopy(dungeon[i], 0, dungeonCopy[i], 0, dungeon[i].length);
289        }
290        DijkstraMap dt = new DijkstraMap(dungeon, dijkstra.measurement);
291        double[][] resMap = DungeonUtility.generateResistances(dungeon);
292        Coord tempPt;
293        for (int i = 0; i < exs.length; ++i) {
294            t = exs[i];
295            dt.resetMap();
296            dt.clearGoals();
297
298            los.isReachable(resMap, origin.x, origin.y, t.x, t.y, rt);
299            Queue<Coord> lit = los.getLastPath();
300
301            for(Coord p : lit)
302            {
303                dt.setGoal(p);
304            }
305            if(radius > 0)
306                dt.partialScan(radius, null);
307
308            for (int x = 0; x < dungeon.length; x++) {
309                for (int y = 0; y < dungeon[x].length; y++) {
310                    tempPt = Coord.get(x, y);
311                    dungeonCopy[x][y] = (dt.gradientMap[x][y] < DijkstraMap.FLOOR || !AreaUtils.verifyReach(reach, origin, tempPt)) ? '!' : dungeonCopy[x][y];
312                }
313            }
314        }
315
316        for (int i = 0; i < ts.length; ++i) {
317            DijkstraMap dm = new DijkstraMap(dungeon, dijkstra.measurement);
318
319            t = ts[i];
320            dt.resetMap();
321            dt.clearGoals();
322            los.isReachable(resMap, origin.x, origin.y, t.x, t.y, rt);
323            Queue<Coord> lit = los.getLastPath();
324
325            for(Coord p : lit)
326            {
327                dt.setGoal(p);
328            }
329            if(radius > 0)
330                dt.partialScan(radius, null);
331
332
333            double dist;
334            for (int x = 0; x < dungeon.length; x++) {
335                for (int y = 0; y < dungeon[x].length; y++) {
336                    if (dt.gradientMap[x][y] < DijkstraMap.FLOOR){
337                        dist = reach.metric.radius(origin.x, origin.y, x, y);
338                        if(dist <= reach.maxDistance + radius && dist >= reach.minDistance - radius)
339                            compositeMap[i][x][y] = dm.physicalMap[x][y];
340                        else
341                            compositeMap[i][x][y] = DijkstraMap.WALL;
342                    }
343                    else compositeMap[i][x][y] = DijkstraMap.WALL;
344                }
345            }
346            if(compositeMap[i][ts[i].x][ts[i].y] > DijkstraMap.FLOOR)
347            {
348                for (int x = 0; x < dungeon.length; x++) {
349                    Arrays.fill(compositeMap[i][x], 99999.0);
350                }
351                continue;
352            }
353
354
355            dm.initialize(compositeMap[i]);
356            dm.setGoal(t);
357            dm.scan(null, null);
358            for (int x = 0; x < dungeon.length; x++) {
359                for (int y = 0; y < dungeon[x].length; y++) {
360                    compositeMap[i][x][y] = (dm.gradientMap[x][y] < DijkstraMap.FLOOR  && dungeonCopy[x][y] != '!') ? dm.gradientMap[x][y] : 99999.0;
361                }
362            }
363            dm.resetMap();
364            dm.clearGoals();
365        }
366        double bestQuality = 99999 * ts.length;
367        double[][] qualityMap = new double[dungeon.length][dungeon[0].length];
368        for (int x = 0; x < qualityMap.length; x++) {
369            for (int y = 0; y < qualityMap[x].length; y++) {
370                qualityMap[x][y] = 0.0;
371                long bits = 0;
372                for (int i = 0; i < ts.length; ++i) {
373                    qualityMap[x][y] += compositeMap[i][x][y];
374                    if(compositeMap[i][x][y] < 99999.0 && i < 63)
375                        bits |= 1 << i;
376                }
377                if(qualityMap[x][y] < bestQuality)
378                {
379                    ArrayList<Coord> ap = new ArrayList<>();
380
381                    for (int i = 0; i < ts.length && i < 63; ++i) {
382                        if((bits & (1 << i)) != 0)
383                            ap.add(ts[i]);
384                    }
385                    if(ap.size() > 0) {
386                        bestQuality = qualityMap[x][y];
387                        bestPoints.clear();
388                        bestPoints.put(Coord.get(x, y), ap);
389                    }
390                }
391                else if(qualityMap[x][y] == bestQuality)
392                {
393                    ArrayList<Coord> ap = new ArrayList<>();
394
395                    for (int i = 0; i < ts.length && i < 63; ++i) {
396                        if((bits & (1 << i)) != 0)
397                            ap.add(ts[i]);
398                    }
399
400                    if (ap.size() > 0) {
401                        bestPoints.put(Coord.get(x, y), ap);
402                    }
403                }
404            }
405        }
406
407        return bestPoints;
408    }
409
410    @Override
411    public OrderedMap<Coord, ArrayList<Coord>> idealLocations(Collection<Coord> priorityTargets, Collection<Coord> lesserTargets, Collection<Coord> requiredExclusions) {
412        if(priorityTargets == null)
413            return idealLocations(lesserTargets, requiredExclusions);
414        if(requiredExclusions == null) requiredExclusions = new OrderedSet<>();
415
416        //requiredExclusions.remove(origin);
417        int totalTargets = priorityTargets.size() + lesserTargets.size();
418        OrderedMap<Coord, ArrayList<Coord>> bestPoints = new OrderedMap<>(totalTargets * 8);
419
420        if(totalTargets == 0)
421            return bestPoints;
422
423        Coord[] pts = priorityTargets.toArray(new Coord[0]);
424        Coord[] lts = lesserTargets.toArray(new Coord[0]);
425        Coord[] exs = requiredExclusions.toArray(new Coord[0]);
426        Coord t;
427
428        double[][][] compositeMap = new double[totalTargets][dungeon.length][dungeon[0].length];
429
430        char[][] dungeonCopy = new char[dungeon.length][dungeon[0].length],
431                dungeonPriorities = new char[dungeon.length][dungeon[0].length];
432        for (int i = 0; i < dungeon.length; i++) {
433            System.arraycopy(dungeon[i], 0, dungeonCopy[i], 0, dungeon[i].length);
434            Arrays.fill(dungeonPriorities[i], '#');
435        }
436        DijkstraMap dt = new DijkstraMap(dungeon, dijkstra.measurement);
437        double[][] resMap = DungeonUtility.generateResistances(dungeon);
438        Coord tempPt;
439        for (int i = 0; i < exs.length; ++i) {
440            t = exs[i];
441            dt.resetMap();
442            dt.clearGoals();
443            los.isReachable(resMap, origin.x, origin.y, t.x, t.y, rt);
444            Queue<Coord> lit = los.getLastPath();
445
446            for(Coord p : lit)
447            {
448                dt.setGoal(p);
449            }
450            if(radius > 0)
451                dt.partialScan(radius, null);
452
453            for (int x = 0; x < dungeon.length; x++) {
454                for (int y = 0; y < dungeon[x].length; y++) {
455                    tempPt = Coord.get(x, y);
456                    dungeonCopy[x][y] = (dt.gradientMap[x][y] < DijkstraMap.FLOOR || !AreaUtils.verifyReach(reach, origin, tempPt)) ? '!' : dungeonCopy[x][y];
457                }
458            }
459        }
460
461        for (int i = 0; i < pts.length; ++i) {
462            DijkstraMap dm = new DijkstraMap(dungeon, dijkstra.measurement);
463            t = pts[i];
464            dt.resetMap();
465            dt.clearGoals();
466            los.isReachable(resMap, origin.x, origin.y, t.x, t.y, rt);
467            Queue<Coord> lit = los.getLastPath();
468
469            for(Coord p : lit)
470            {
471                dt.setGoal(p);
472            }
473            if(radius > 0)
474                dt.partialScan(radius, null);
475
476
477            double dist;
478            for (int x = 0; x < dungeon.length; x++) {
479                for (int y = 0; y < dungeon[x].length; y++) {
480                    if (dt.gradientMap[x][y] < DijkstraMap.FLOOR){
481                        dist = reach.metric.radius(origin.x, origin.y, x, y);
482                        if(dist <= reach.maxDistance + radius && dist >= reach.minDistance - radius) {
483                            compositeMap[i][x][y] = dm.physicalMap[x][y];
484                            dungeonPriorities[x][y] = dungeon[x][y];
485                        }
486                        else
487                            compositeMap[i][x][y] = DijkstraMap.WALL;
488                    }
489                    else compositeMap[i][x][y] = DijkstraMap.WALL;
490                }
491            }
492            if(compositeMap[i][pts[i].x][pts[i].y] > DijkstraMap.FLOOR)
493            {
494                for (int x = 0; x < dungeon.length; x++) {
495                    Arrays.fill(compositeMap[i][x], 399999.0);
496                }
497                continue;
498            }
499
500
501            dm.initialize(compositeMap[i]);
502            dm.setGoal(t);
503            dm.scan(null, null);
504            for (int x = 0; x < dungeon.length; x++) {
505                for (int y = 0; y < dungeon[x].length; y++) {
506                    compositeMap[i][x][y] = (dm.gradientMap[x][y] < DijkstraMap.FLOOR  && dungeonCopy[x][y] != '!') ? dm.gradientMap[x][y] : 399999.0;
507                }
508            }
509            dm.resetMap();
510            dm.clearGoals();
511        }
512
513        for (int i = pts.length; i < totalTargets; ++i) {
514            DijkstraMap dm = new DijkstraMap(dungeon, dijkstra.measurement);
515            t = lts[i - pts.length];
516            dt.resetMap();
517            dt.clearGoals();
518            los.isReachable(resMap, origin.x, origin.y, t.x, t.y, rt);
519            Queue<Coord> lit = los.getLastPath();
520
521            for(Coord p : lit)
522            {
523                dt.setGoal(p);
524            }
525            if(radius > 0)
526                dt.partialScan(radius, null);
527
528            double dist;
529            for (int x = 0; x < dungeon.length; x++) {
530                for (int y = 0; y < dungeon[x].length; y++) {
531                    if (dt.gradientMap[x][y] < DijkstraMap.FLOOR){
532                        dist = reach.metric.radius(origin.x, origin.y, x, y);
533                        if(dist <= reach.maxDistance + radius && dist >= reach.minDistance - radius)
534                            compositeMap[i][x][y] = dm.physicalMap[x][y];
535                        else
536                            compositeMap[i][x][y] = DijkstraMap.WALL;
537                    }
538                    else compositeMap[i][x][y] = DijkstraMap.WALL;
539                }
540            }
541            if(compositeMap[i][lts[i - pts.length].x][lts[i - pts.length].y] > DijkstraMap.FLOOR)
542            {
543                for (int x = 0; x < dungeon.length; x++)
544                {
545                    Arrays.fill(compositeMap[i][x], 99999.0);
546                }
547                continue;
548            }
549
550
551            dm.initialize(compositeMap[i]);
552            dm.setGoal(t);
553            dm.scan(null, null);
554            for (int x = 0; x < dungeon.length; x++) {
555                for (int y = 0; y < dungeon[x].length; y++) {
556                    compositeMap[i][x][y] = (dm.gradientMap[x][y] < DijkstraMap.FLOOR  && dungeonCopy[x][y] != '!' && dungeonPriorities[x][y] != '#') ? dm.gradientMap[x][y] : 99999.0;
557                }
558            }
559            dm.resetMap();
560            dm.clearGoals();
561        }
562        double bestQuality = 99999 * lts.length + 399999 * pts.length;
563        double[][] qualityMap = new double[dungeon.length][dungeon[0].length];
564        for (int x = 0; x < qualityMap.length; x++) {
565            for (int y = 0; y < qualityMap[x].length; y++) {
566                qualityMap[x][y] = 0.0;
567                long pbits = 0, lbits = 0;
568                for (int i = 0; i < pts.length; ++i) {
569                    qualityMap[x][y] += compositeMap[i][x][y];
570                    if(compositeMap[i][x][y] < 399999.0 && i < 63)
571                        pbits |= 1 << i;
572                }
573                for (int i = pts.length; i < totalTargets; ++i) {
574                    qualityMap[x][y] += compositeMap[i][x][y];
575                    if(compositeMap[i][x][y] < 99999.0 && i < 63)
576                        lbits |= 1 << i;
577                }
578                if(qualityMap[x][y] < bestQuality)
579                {
580                    ArrayList<Coord> ap = new ArrayList<>();
581
582                    for (int i = 0; i < pts.length && i < 63; ++i) {
583                        if((pbits & (1 << i)) != 0)
584                            ap.add(pts[i]);
585                    }
586                    for (int i = pts.length; i < totalTargets && i < 63; ++i) {
587                        if((lbits & (1 << i)) != 0)
588                            ap.add(lts[i - pts.length]);
589                    }
590
591                    if(ap.size() > 0) {
592                        bestQuality = qualityMap[x][y];
593                        bestPoints.clear();
594                        bestPoints.put(Coord.get(x, y), ap);
595                    }
596                }
597                else if(qualityMap[x][y] == bestQuality) {
598                    ArrayList<Coord> ap = new ArrayList<>();
599
600                    for (int i = 0; i < pts.length && i < 63; ++i) {
601                        if ((pbits & (1 << i)) != 0) {
602                            ap.add(pts[i]);
603                            ap.add(pts[i]);
604                            ap.add(pts[i]);
605                            ap.add(pts[i]);
606                        }
607                    }
608                    for (int i = pts.length; i < totalTargets && i < 63; ++i) {
609                        if ((lbits & (1 << i)) != 0)
610                            ap.add(lts[i - pts.length]);
611                    }
612
613                    if (ap.size() > 0) {
614                        bestPoints.put(Coord.get(x, y), ap);
615                    }
616                }
617            }
618        }
619
620        return bestPoints;
621    }
622
623/*
624    @Override
625    public ArrayList<ArrayList<Coord>> idealLocations(Set<Coord> targets, Set<Coord> requiredExclusions) {
626        int totalTargets = targets.size() + 1;
627        int volume = (int)(rt.radius(1, 1, dungeon.length - 2, dungeon[0].length - 2) * radius * 2.1);
628        ArrayList<ArrayList<Coord>> locs = new ArrayList<ArrayList<Coord>>(totalTargets);
629        for(int i = 0; i < totalTargets; i++)
630        {
631            locs.add(new ArrayList<Coord>(volume));
632        }
633        if(totalTargets == 1)
634            return locs;
635
636        int ctr = 0;
637
638        boolean[][] tested = new boolean[dungeon.length][dungeon[0].length];
639        for (int x = 1; x < dungeon.length - 1; x += radius) {
640            for (int y = 1; y < dungeon[x].length - 1; y += radius) {
641
642                if(mayContainTarget(requiredExclusions, x, y))
643                    continue;
644                ctr = 0;
645                for(Coord tgt : targets)
646                {
647                    if(rt.radius(origin.x, origin.y, tgt.x, tgt.y) + rt.radius(end.x, end.y, tgt.x, tgt.y) -
648                        rt.radius(origin.x, origin.y, end.x, end.y) <= 3.0 + radius)
649                        ctr++;
650                }
651                if(ctr > 0)
652                    locs.get(totalTargets - ctr).add(Coord.get(x, y));
653            }
654        }
655        Coord it;
656        for(int t = 0; t < totalTargets - 1; t++)
657        {
658            if(locs.get(t).size() > 0) {
659                int numPoints = locs.get(t).size();
660                for (int i = 0; i < numPoints; i++) {
661                    it = locs.get(t).get(i);
662                    for (int x = Math.max(1, it.x - radius / 2); x < it.x + (radius + 1) / 2 && x < dungeon.length - 1; x++) {
663                        for (int y = Math.max(1, it.y - radius / 2); y <= it.y + (radius - 1) / 2 && y < dungeon[0].length - 1; y++)
664                        {
665                            if(tested[x][y])
666                                continue;
667                            tested[x][y] = true;
668
669                            if(mayContainTarget(requiredExclusions, x, y))
670                                continue;
671
672                            ctr = 0;
673                            for(Coord tgt : targets)
674                            {
675                                if(rt.radius(origin.x, origin.y, tgt.x, tgt.y) + rt.radius(end.x, end.y, tgt.x, tgt.y) -
676                                        rt.radius(origin.x, origin.y, end.x, end.y) <= 3.0 + radius)
677                                    ctr++;
678                            }
679                            if(ctr > 0)
680                                locs.get(totalTargets - ctr).add(Coord.get(x, y));
681                        }
682                    }
683                }
684            }
685        }
686        return locs;
687    }
688*/
689    @Override
690    public void setMap(char[][] map) {
691        dungeon = map;
692        dijkstra.resetMap();
693        dijkstra.clearGoals();
694    }
695
696    @Override
697    public OrderedMap<Coord, Double> findArea() {
698        double[][] dmap = initDijkstra();
699        dmap[origin.x][origin.y] = DijkstraMap.DARK;
700        dijkstra.resetMap();
701        dijkstra.clearGoals();
702        return AreaUtils.dijkstraToHashMap(dmap);
703    }
704
705}