/******************************************************************************* * TurtleKit 3 - Agent Based and Artificial Life Simulation Platform * Copyright (C) 2011-2014 Fabien Michel * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package turtlekit.kernel; import java.awt.Color; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; public class Patch { final private Collection<Turtle> turtlesHere = new HashSet<>(); private Color color; public int x; public int y; private TKEnvironment environment; private ArrayList<Patch> neighbors = new ArrayList<>();// TODO bench lazy // creation private HashMap<String, Object> marks; public Patch() { color = Color.BLACK; neighbors.add(this);// for including this when computing neighbors with true for inclusion } public void setCoordinates(int x, int y){ this.x = x; this.y = y; } public void setEnvironment(TKEnvironment environment){ this.environment = environment; } /** * @return <code>true</code> if there is no turtle */ public boolean isEmpty() { return turtlesHere.isEmpty(); } public List<Patch> getNeighbors(int inRadius, boolean includeThisPatch) { final int height = environment.getHeight(); final int width = environment.getWidth(); int max = Math.max(height,width); if(inRadius > max - 1) inRadius = max - 1; int length = 1; for (int i = 1; i <= inRadius; i++) { length += nbOfNeighborsAt(i, width, height); } if (neighbors.size() < length) { int startIndex = length - nbOfNeighborsAt(inRadius, width, height); int startRadius = inRadius; while (startIndex != neighbors.size()) { startRadius--; startIndex -= nbOfNeighborsAt(startRadius, width, height); } for (; startRadius <= inRadius && nbOfNeighborsAt(startRadius, width, height) > 0; startRadius++) { Collection<Patch> tmp = new HashSet<>(); for (int u = -startRadius; u <= startRadius ; u++) { for (int v = -startRadius; v <= startRadius ; v++) { if (Math.abs(u) < width && Math.abs(v) < height && (Math.abs(u) == startRadius || Math.abs(v) == startRadius)) { tmp.add(environment.getPatch(x + u, y + v)); } } } neighbors.addAll(tmp); } neighbors.trimToSize(); } return neighbors.subList(includeThisPatch ? 0 : 1, length); } /** Drop a mark on the patch @param markName mark name @param value mark itself, can be any java object*/ final public void dropMark(String markName, Object value) { if (marks == null) marks = new HashMap<>(1); marks.put(markName,value); } /** get a mark deposed on the patch @return the corresponding java object which thus is removed from the patch, or <code>null</code> if not present*/ final public Object getMark(String markName){ try { return marks.remove(markName); } catch (NullPointerException e) { return null; } } /** tests if the corresponding mark is present on the patch (true or false)*/ final public boolean isMarkPresent(String markName) { try { return marks.containsKey(markName); } catch (NullPointerException e) { return false; } } final private int nbOfNeighborsAt(int radius, int width, int height){ radius *= 2;//diameter final int aSide = radius + 1; int verticalNeighbors = 0; int offset = 0; if (radius <= width) { verticalNeighbors = Math.min(aSide, height); offset++; if (radius != width) { verticalNeighbors *= 2; offset++; } } int horizontalNeighbors = 0; if (radius <= height) { horizontalNeighbors = Math.min(aSide, width); if (radius != height) { horizontalNeighbors *= 2; offset *= 2; } } else { offset=0; } return verticalNeighbors + horizontalNeighbors - offset; } public <T extends Turtle> List<T> getTurtles(int inRadius, boolean includeThisPatch, Class<T> turtleType) { List<T> l = new ArrayList<>(); for (Patch p : getNeighbors(inRadius, includeThisPatch)) { l.addAll(p.getTurtles(turtleType)); } return l; } public <T extends Turtle> List<T> getTurtlesWithRole(int inRadius, boolean includeThisPatch, String role, Class<T> turtleType) { List<T> l = new ArrayList<>(); for (Patch p : getNeighbors(inRadius, includeThisPatch)) { l.addAll(p.getTurtlesWithRole(role, turtleType)); } return l; } public List<Turtle> getTurtlesWithRole(int inRadius, boolean includeThisPatch, String role) { List<Turtle> l = new ArrayList<>(); for (Patch p : getNeighbors(inRadius, includeThisPatch)) { l.addAll(p.getTurtlesWithRole(role)); } return l; } public List<Turtle> getTurtles(int inRadius, boolean includeThisPatch) { List<Turtle> l = new ArrayList<>(); for (Patch p : getNeighbors(inRadius, includeThisPatch)) { l.addAll(p.getTurtles()); } return l; } /** * Gets the nearest turtle of type T in the vicinity of the patch. * * @param inRadius the range of the search * @param includeThisPatch for the search * @param turtleType the type of the turtle as a {@link Class} * @return the corresponding turtle or <code>null</code> if no such turtle is found */ @SuppressWarnings("unchecked") public <T extends Turtle> T getNearestTurtle(int inRadius, boolean includeThisPatch, Class<T> turtleType) { for (final Patch p : getNeighbors(inRadius, includeThisPatch)) { final List<Turtle> turtles = p.getTurtles(); for (final Turtle t : turtles) { if (turtleType.isAssignableFrom(t.getClass())) { return (T) t; } } } return null; } /** * Gets the nearest turtle of type T in the vicinity of the patch. * * @param inRadius the range of the search * @param includeThisPatch for the search * @return the corresponding turtle or <code>null</code> if there is * no turtle around * */ public Turtle getNearestTurtle(int inRadius, boolean includeThisPatch) { for (Patch p : getNeighbors(inRadius, includeThisPatch)) { for (final Turtle t : p.getTurtles()) { return t; } } return null; } void installTurtles(final List<Turtle> l) { turtlesHere.addAll(l); for (final Turtle turtle : l) { turtle.setPatch(this); } } /** * Get all the turtles on this patch * according to their type. * * @param turtleType * @return a list of turtles which could be empty */ @SuppressWarnings("unchecked") public <T extends Turtle> List<T> getTurtles(Class<T> turtleType) { final ArrayList<T> turtles = new ArrayList<>(); final ArrayList<Turtle> tmp; synchronized (turtlesHere) { tmp = new ArrayList<Turtle>(turtlesHere); } for (final Turtle t : tmp) { if (turtleType.isAssignableFrom(t.getClass())) { turtles.add((T) t); } } return turtles; } /** * Get all the turtles on this patch * according to their type and role. * * @param role * @param turtleType * @return a list of turtles which could be empty */ @SuppressWarnings("unchecked") public <T extends Turtle> List<T> getTurtlesWithRole(String role, Class<T> turtleType) { final List<T> turtles = new ArrayList<>(); for (final Turtle t : turtlesHere) { if (turtleType.isAssignableFrom(t.getClass()) && t.isPlayingRole(role)) { turtles.add((T) t); } } return turtles; } /** * Get all the turtles which are on this patch * and having this role. * * @param role * @return a list of turtles which could be empty */ @SuppressWarnings("unchecked") public <T extends Turtle> List<T> getTurtlesWithRole(String role) { final List<T> turtles = new ArrayList<>(); for (final Turtle t : turtlesHere) { if (t.isPlayingRole(role)) { turtles.add((T) t); } } return turtles; } public List<Turtle> getTurtles() { synchronized (turtlesHere) { return new ArrayList<>(turtlesHere); } } public int countTurtles() { return turtlesHere.size(); } public Color getColor() { return color; } public void setColor(Color c) { color = c; } final void removeAgent(Turtle a) { synchronized (turtlesHere) { turtlesHere.remove(a); } } final void addAgent(Turtle a) { synchronized (turtlesHere) { turtlesHere.add(a); } a.setPosition(this); } protected void update() { } @Override public String toString() { return "P(" + x + "," + y + ")"; } public void dropPheromone(String name, float quantity, Float... parameters) { environment.getPheromone(name).incValue(x, y, quantity); } }