/**
* 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/>.
*
* Copyright Tim Hutton and Berlin Brown <berlin dot brown at gmail.com> 2011
* Copyright Berlin Brown 2012 modifications
*
* Tim Hutton is the original author, but a license not provided in source,
* GPL was used for similar projects. If Tim or anyone else has questions, please contact Berlin Brown.
*
* http://www.sq3.org.uk/Evolution/Squirm3/
*
* Squirm3 is an artificial chemistry simulation
*/
package org.berlin.chem.gae;
// SquirmChemistry.java
import java.util.Enumeration;
import java.util.Vector;
import java.util.logging.Logger;
/**
* Stateful with reactions.
*
* @author bbrown
*
*/
public class DBSquirmChemistry {
private static final Logger LOGGER = Logger.getLogger(DBSquirmChemistry.class.getCanonicalName());
private final Vector<DBModelSquirmReaction> reactionsDatabase;
/**
* Constructor for squirm chemistry.
*/
public DBSquirmChemistry(final Vector<DBModelSquirmReaction> db) {
reactionsDatabase = db;
}
public void removeAllReactions() {
reactionsDatabase.removeAllElements();
}
public void addReaction(final DBModelSquirmReaction r) {
reactionsDatabase.addElement(r);
}
public void react(final DBModelSquirmCellSlot cell_grid[][], final DBSquirmCell cell, Vector<DBSquirmCell> neighbours) {
// try all the reactions in turn
for (Enumeration<DBModelSquirmReaction> e = reactionsDatabase.elements(); e.hasMoreElements();) {
tryReaction(cell_grid, cell, neighbours, (DBModelSquirmReaction) e.nextElement());
} // End of the for //
}
protected void tryReaction(final DBModelSquirmCellSlot cell_grid[][], DBSquirmCell cell, Vector<DBSquirmCell> neighbours, final DBModelSquirmReaction r) {
tryReaction(cell_grid, cell, neighbours, r.us_type, r.us_state, r.current_bond, r.them_type, r.them_state,
r.future_us_state, r.future_bond, r.future_them_state);
}
protected void tryReaction(final DBModelSquirmCellSlot cell_grid[][], final DBSquirmCell cell, final Vector<DBSquirmCell> neighbours,
char us_type, int us_state, boolean current_bond, char them_type, int them_state, int future_us_state,
boolean future_bond, int future_them_state) {
// us_type is one of {e,f,a,b,c,d,x}
if (us_type != 'e' && us_type != 'f' && us_type != 'a' && us_type != 'b' && us_type != 'c' && us_type != 'd'
&& us_type != 'x')
throw new Error("SquirmChemistry::Reaction() : invalid us_type");
// them_type is one of {e,f,a,b,c,d,x,y}
if (them_type != 'e' && them_type != 'f' && them_type != 'a' && them_type != 'b' && them_type != 'c'
&& them_type != 'd' && them_type != 'x' && them_type != 'y')
throw new Error("SquirmChemistry::Reaction() : invalid them_type");
// sanity check on the states requested
if (us_state < 0 || them_state < 0 || future_us_state < 0 || future_them_state < 0)
throw new Error("SquirmChemistry::tryReaction() : states less than zero not permitted");
// are we the right kind of cell for this reaction?
if ((us_type != 'x' && cell.isTypeAndState(us_type, us_state)) || (us_type == 'x' && cell.isState(us_state))) {
// do we have a neighbour (bonded/not) that is the right kind for
// this reaction?
Vector<DBSquirmCell> search_from = current_bond ? cell.getBonds() : neighbours;
Vector<DBSquirmCell> ns;
// if them_type specified then search for it
if (them_type != 'x' && them_type != 'y')
ns = getThoseOfTypeAndState(search_from, them_type, them_state);
// if unspecified but to be same as us_type then search for it
else if (them_type == 'x' && us_type == 'x')
ns = getThoseOfTypeAndState(search_from, cell.getType(), them_state);
// must be unspecified
else if ((them_type == 'x' && us_type != 'x') || them_type == 'y')
ns = getThoseOfState(search_from, them_state);
else
throw new Error("SquirmChemistry::tryReaction() : unexpected case statement");
// try the reaction on each of the possibles
for (Enumeration<DBSquirmCell> e = ns.elements(); e.hasMoreElements();) {
DBSquirmCell n = (DBSquirmCell) e.nextElement();
// reactions can happen if the two cells are right next to each
// other (share a face) or over a diagonal (share a corner) if
// the other diagonal
// doesn't have a bond
boolean can_react = false;
if (rightNextToEachOther(cell, n)) {
can_react = true;
} else {
// if either other diagonal square is empty then OK
if (cell_grid[cell.getX()][n.getY()].queryEmpty() || cell_grid[n.getX()][cell.getY()].queryEmpty())
can_react = true;
else {
// otherwise, if there is no bond between diagonals then
// still OK
DBSquirmCell cellA = cell_grid[cell.getX()][n.getY()].getOccupant();
DBSquirmCell cellB = cell_grid[n.getX()][cell.getY()].getOccupant();
if (!cellA.getBonds().contains(cellB))
can_react = true;
}
} // End of the if - else //
if (can_react) {
// make or break bonds as specified
if (current_bond && !future_bond) {
LOGGER.info("Breaking bond : UsType=" + us_type + " UsState=" + us_state + " ThemType=" + them_type + " ThemState=" + them_state);
cell.breakBondWith(n);
} else if (!current_bond && future_bond) {
LOGGER.info("Making bond : UsType=" + us_type + " UsState=" + us_state + " ThemType=" + them_type + " ThemState=" + them_state);
cell.makeBondWith(n);
} // End of the if //
// set our states to their new values
cell.setState(future_us_state);
n.setState(future_them_state);
break;
} // End of the if //
}
}
} // End of the method //
protected Vector<DBSquirmCell> getThoseOfTypeAndState(Vector<DBSquirmCell> cells, char type, int state) {
return getThoseOfTypeAndState(cells, DBModelSquirmCellProperties.getType(type), state);
}
protected Vector<DBSquirmCell> getThoseOfTypeAndState(Vector<DBSquirmCell> cells, int type, int state) {
// do any of these cells match the type and state specified?
// if so return all that match (empty list if none)
final Vector<DBSquirmCell> v = new Vector<DBSquirmCell>();
DBSquirmCell c;
for (Enumeration<DBSquirmCell> enumx = cells.elements(); enumx.hasMoreElements();) {
c = ((DBSquirmCell) enumx.nextElement());
if (type != -1) {
if (c.isTypeAndState(type, state))
v.addElement(c);
} else if (c.isState(state))
v.addElement(c);
}
return v;
}
protected Vector<DBSquirmCell> getThoseOfState(final Vector<DBSquirmCell> cells, int state) {
// do any of these cells match the state specified? (any type)
// if so return all that match (empty list if none)
final Vector<DBSquirmCell> v = new Vector<DBSquirmCell>();
DBSquirmCell c;
for (Enumeration<DBSquirmCell> enumx = cells.elements(); enumx.hasMoreElements();) {
c = ((DBSquirmCell) enumx.nextElement());
if (c.isState(state)) {
v.addElement(c);
}
}
return v;
}
protected boolean rightNextToEachOther(final DBSquirmCell cell1, final DBSquirmCell cell2) {
return (Math.abs(cell1.getX() - cell2.getX()) + Math.abs(cell1.getY() - cell2.getY()) < 2);
}
} // End of the class //
|