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}