/*
* This file is part of JGAP.
*
* JGAP offers a dual license model containing the LGPL as well as the MPL.
*
* For licensing information please see the file license.txt included with JGAP
* or have a look at the top of class org.jgap.Chromosome which representatively
* includes the JGAP license policy applicable for any file delivered with JGAP.
*/
package examples.gp.paintedDesert;
/**
* Holds the map of the painted desert sand locations
*
* @author Scott Mueller
* @since 3.2
*/
public class AntMap {
/** String containing the CVS revision. Read out via reflection!*/
private final static String CVS_REVISION = "$Revision: 1.4 $";
/** Holds the instance of the ant being processed. Assumption that some external
* single threaded process will loop through all the ants using nextAnt to sequence
* through the ants. It is expected that the clients of the AntMap can use getAnt()
* to return the Ant instance at the currentAnt index.
*/
private int m_currentAnt;
// Carrying
/**
* No Sand at this location or carried by the ant
*/
public static final int EMPTY = -1;
/**
* Black sand at this location or carried by the ant
*/
public static final int BLACK = 0;
/**
* Gray sand at this location or carried by the ant
*/
public static final int GRAY = 1;
/**
* Striped sand at this location or carried by the ant
*/
public static final int STRIPED = 2;
/**
* Ant at this location
*/
public static final int ANT_AT_POSITION = 9;
/**
* Initial sand position as [x][y]
*/
private int[][] m_initialPosition;
/**
* Width of map.
*/
private int m_sizex;
/**
* Height of map.
*/
private int m_sizey;
/**
* Population size.
*/
private int m_popSize = 1;
/**
* Holder of the current map.
*
* Sand is indicated by AntMap.EMPTY|GRAY|STRIPED|BLACK
*/
private int[][] m_currentMap;
/**
* Holds the list of ants
*/
private Ant[] m_ants;
// /**
// * Maximum number of moves allowed.
// */
//private int m_maxMoves;
/**
* Creates the map.
*
* @param a_map the map itself
* @param a_ants the list of ants
*/
public AntMap(final int[][] a_map, Ant[] a_ants) {
m_sizex = a_map.length;
m_sizey = a_map[0].length;
m_ants = a_ants;
m_popSize = m_ants.length;
m_currentAnt = -1;
m_initialPosition = new int[m_sizex][m_sizey];
this.m_currentMap = new int[m_sizex][m_sizey];
for (int x = 0; x < m_sizex; x++) {
for (int y = 0; y < m_sizey; y++) {
if (a_map[x][y] == ANT_AT_POSITION) {
m_initialPosition[x][y] = a_map[x][y]; //nextAntIndex + this.ANT_INDEX_OFFSET;
m_currentMap[x][y] = a_map[x][y];
}
else {
m_initialPosition[x][y] = a_map[x][y];
m_currentMap[x][y] = a_map[x][y];
}
}
}
}
/**
* Places sand or identifies an empty spot at the current position
* @param sandColor
* @param x
* @param y
*/
public void placeSand(int sandColor, int x, int y) {
m_currentMap[x][y] = sandColor;
}
/**
* Returns the color of sand at the provided location
* @param x
* @param y
* @return
*/
public int atLocation(int x, int y) {
return m_currentMap[x][y];
}
/**
* Returns a representation of the current map
* @return
*/
public int[][] getMap() {
return this.m_currentMap;
}
/**
* Returns a representation of the initial map
* @return
*/
public int[][] getInitialMap() {
return this.m_initialPosition;
}
/**
* Identifies whether there is sand at the provided location
* @param x
* @param y
* @return
*/
public boolean sandAtLocation(int x, int y) {
return this.m_currentMap[x][y] != AntMap.EMPTY;
}
/**
* Identifies that sand is at that location
* @param sandColor
* @param x
* @return
*/
public boolean sandBelongsHere(int sandColor, int x) {
return sandColor == x;
}
/**
* Identifies that sand may be placed here
* @param x
* @param y
* @return
*/
public boolean mayDropSand(int x, int y) {
return this.m_currentMap[x][y] == AntMap.EMPTY;
}
/**
* Removes the sand from the current position
* @param x
* @param y
* @return
*/
public int removeSand(int x, int y) {
int removed = this.m_currentMap[x][y];
this.m_currentMap[x][y] = AntMap.EMPTY;
return removed;
}
/**
* Returns the current Ant. The current ant is incremented by the NextAnt
* method.
* @return
*/
public Ant getAnt() {
if (getAnts()[m_currentAnt] == null) {
throw new IllegalStateException(
"currentAnt does not point at a valid ant instance");
}
return getAnts()[m_currentAnt];
}
/** Determine the final position of grains of sand. If an ant is carrying sand and
* there is no sand at the current position, drop the sand at this position. If there
* is sand, rubberband the sand back to where the ant picked up the sand. If
* both locations are full, then pick the nearest open spot
* @see java.lang.Object#finalize()
*/
public void finalize() {
for (int antIndex = 0; antIndex < m_popSize; antIndex++) {
if (getAnts()[antIndex].getCarrying() >= 0) {
if (getMap()[getAnts()[antIndex].getXpos()][getAnts()[antIndex].getYpos()] !=
AntMap.EMPTY) {
getMap()[getAnts()[antIndex].getXpos()][getAnts()[antIndex].getYpos()] =
getAnts()[antIndex].getCarrying();
}
else {
/*System.out.println("carrying "+ getAnts()[antIndex].getCarrying());
System.out.println("ant index = "+antIndex );
System.out.println("picked up fromX`" + getAnts()[antIndex].getPickedUpFromXLoc());
System.out.println("picked up fromY + getAnts()[antIndex].getPickedUpFromYLoc());
*/
if (getMap()[getAnts()[antIndex].getPickedUpFromXLoc()][getAnts()[
antIndex].getPickedUpFromYLoc()] != AntMap.EMPTY) {
getMap()[getAnts()[antIndex].getPickedUpFromXLoc()][getAnts()[
antIndex].getPickedUpFromYLoc()] = getAnts()[antIndex].
getCarrying();
}
else {
placeNear(getAnts()[antIndex].getCarrying(),
getAnts()[antIndex].getXpos(),
getAnts()[antIndex].getYpos());
}
}
}
}
}
/**
* Calculates how well the sand is moved to the proper columns.
* @return
*/
public int fitness() {
//Causes all ants to drop their sand at a location
this.finalize();
int fitness = 0;//(int) GPFitnessFunction.MAX_FITNESS_VALUE;
int hit = 0;
for (int x = 0; x < this.getWidth(); x++) {
for (int y = 0; y < this.getHeight(); y++) {
if (this.getMap()[x][y] != AntMap.EMPTY) {
// The proper column for the color is the same as the x = color
// Black = 0, Gray = 1, Striped = 2
// so subtract the color of sand from the x value to find the delta
// and take the absolute value
// when all sand is in the proper location fitness = 0
//fitness = fitness + Math.abs(x- antmap.getMap()[x][y]);
fitness = fitness +
fitnessValue(getMap(), getMap()[x][y], x, y);
if (getMap()[x][y] == x) {
// Sand is in the correct position - color = x value
hit++;
}
}
}
}
return fitness;
}
/**
* Calculates the fitness value for a single grain of sand
* @param antmap
* @param sandColor
* @param x
* @param y
* @return
*/
private int fitnessValue(int[][] antmap, int sandColor, int x, int y) {
if (x == antmap[x][y]) {
return 0;
}
else if (x >= antmap[x][y]) {
return (x - antmap[x][y]) * (x - antmap[x][y]);
}
else {
//penalty for moving too far to left
return (1 + antmap[x][y] - x) * (1 + antmap[x][y] - x);
}
}
/**
* Places the grain of sand near where the current location is at.
* @param sandType
* @param x
* @param y
*/
private void placeNear(int sandType, int x, int y) {
boolean placed = false;
int initX = x;
int initY = y;
while (!placed && x + 1 < this.m_sizex && y + 1 < this.m_sizey) {
x++;
if (getMap()[x][y] == AntMap.EMPTY) {
this.placeSand(sandType, x, y);
placed = true;
}
y++;
if (!placed && y < this.m_sizey && getMap()[x][y] == AntMap.EMPTY) {
this.placeSand(sandType, x, y);
placed = true;
}
}
x = initX;
y = initY;
if (!placed) {
while (!placed && x - 1 > 0 && y - 1 > 0) {
x--;
if (y == this.m_sizey) {
y--;
}
if (getMap()[x][y] == AntMap.EMPTY) {
this.placeSand(sandType, x, y);
x = this.m_sizex;
y = this.m_sizey;
placed = true;
}
y--;
if (!placed && y > 0 && getMap()[x][y] == AntMap.EMPTY) {
this.placeSand(sandType, x, y);
x = this.m_sizex;
y = this.m_sizey;
}
}
}
}
/**
* Increments the index to the next ant.
* @return
*/
public Ant nextAnt() {
if (m_currentAnt + 1 < m_popSize) {
m_currentAnt++;
}
else {
System.out.println("nextAnt with m_currentAnt=" + m_currentAnt +
" and m_popSize=" + m_popSize);
throw new IllegalStateException("Iterated beyond last ant");
}
return getAnts()[m_currentAnt];
}
/**
* Asks each ant for the number of moves and sums up the result.
* @return
*/
public int getMoveCount() {
int moves = 0;
for (int antIndex = 0; antIndex < m_popSize; antIndex++) {
if (getAnts()[antIndex] != null) {
moves = getAnts()[antIndex].getMoves();
}
}
return moves;
}
/**
* Returns the width of the map
* @return
*/
public int getWidth() {
return m_sizex;
}
/**
* Returns the height of the map
* @return
*/
public int getHeight() {
return m_sizey;
}
/**
* Returns this list of ants
* @return
*/
public Ant[] getAnts() {
return m_ants;
}
public void init() {
resetMap();
}
/**
* Resets the sand and ant back to their positions before the program was applied
*
*/
public void resetMap() {
m_currentAnt = -1;
// m_fitnessFailure = false;
for (int antIndex = 0; antIndex < m_ants.length; antIndex++) {
m_ants[antIndex].reset();
}
for (int x = 0; x < m_sizex; x++) {
for (int y = 0; y < m_sizey; y++) {
m_currentMap[x][y] = m_initialPosition[x][y];
}
}
}
}