//****************************************************************************** // HexagonalTotalistic.java //****************************************************************************** package springlets; import net.jmge.prj.csprings.Springlet; //============================================================================== // Extends Cellsprings with an interesting rulespace while providing an // example/template springlet definition as part of the "springlets API" // tutorial. (See the Springlet Programming section of the Cellsprings // documentation.) // // John Elliott, August 2000 //============================================================================== public class HexagonalTotalistic extends Springlet { // runtime parameter names and default values (specifies 'YChromosome' rule) private static final String[][] FIELDS = { {"BCounts", "2"}, {"SCounts", "2"} }; // quick lookup to track the ASCII rule definition private int[] ruleTable = new int[2]; //---------------------------------------------------------------------------- // We must define a default constructor that passes information to the // superclass via its only constructor. //---------------------------------------------------------------------------- public HexagonalTotalistic() { super( 3, // pass the default cellsize to the superclass true, // inform the system that we want to parameterize cellsize FIELDS // our own runtime parameter definitions ); // initialize numeric rule table from the default ASCII parameters for (int i = 0; i < FIELDS.length; ++i) parseParameter(FIELDS[i][0], FIELDS[i][1]); } //---------------------------------------------------------------------------- // We override this superclass method to provide a description of our // rulespace to the user. //---------------------------------------------------------------------------- public String[] getDescription() { return new String[] { "DEFINED SPACE - Radius-1 hexagonal hood, outer totalistic, with and", "without decay. (This hood is accomplished on our rectangular lattice", "as the von Neumann plus NW and SE.)", "PROGRAMMER - John Elliott, August 2000", "COMMENTS - Ben Schaeffer's fascinating 'YChromosome' rule inspired this", "generalization, which conveniently extends Cellsprings while providing", "a good springlet programming example. Although springlet performance", "can't match the built-in totalistic rules (which utilize a less generic", "state abstraction), the plug-in has already proven its usefulness by", "facilitating the discovery of several interesting rules." }; } //---------------------------------------------------------------------------- // We override this method because we defined runtime parameters other than // cellsize at construction. (Cellsize updates are handled by the // superclass.) The method is called when the user enters a new parameter // value; it's our responsibility to track the changes with our own instance // variables ('ruleTable' in the present class). //---------------------------------------------------------------------------- protected boolean parameterChanged(String name, String value) { return parseParameter(name, value); } //---------------------------------------------------------------------------- // This override is where the action is, i.e., where we implement our rule's // algorithm. Among other things, this example shows how to use the inherited // neighbor-index arrays. //---------------------------------------------------------------------------- protected int computeCell(int i, int j) { // copy current center cell value for handier (and faster) access int curval = mCells[i][j]; // if the cell is in a decay cycle, proceed with it if (curval > 1) return (curval + 1) % cellSize; // early RETURN - cycrement of current val // count the number of 1-valued neighbors int count = 0; if (mCells[iE[i]][jS[j]] == 1) ++count; if (mCells[iW[i]][jN[j]] == 1) ++count; if (mCells[iE[i]][ j ] == 1) ++count; if (mCells[iW[i]][ j ] == 1) ++count; if (mCells[ i ][jS[j]] == 1) ++count; if (mCells[ i ][jN[j]] == 1) ++count; // look up the OT rule's output for our present neighbor-count and center // value (the latter is either 0 or 1 if we've got this far) int entry = 1 & (ruleTable[curval] >> count); // if we're a decay rule and "death" is called for, start the decay cycle, // otherwise just return the OT table entry return cellSize > 2 && curval == 1 && entry == 0 ? 2 : entry; } //---------------------------------------------------------------------------- // We need to override this because 'ruleTable' is mutable. //---------------------------------------------------------------------------- protected Object clone() { HexagonalTotalistic copy = (HexagonalTotalistic) super.clone(); copy.ruleTable = (int[]) ruleTable.clone(); return copy; } //---------------------------------------------------------------------------- // Besides constructors and overrides, we can define any methods of our own // we care to. In this case, we're just doing a routine for parsing the // ASCII parameters. It also provides an example of how you might go about // input validation should you want to provide a polished springlet for use // by others. //---------------------------------------------------------------------------- private boolean parseParameter(String name, String value) { // check the passed name against the birth and survival field names; // notice the assumed correspondence between field index and // the value of the center cell as input to the lookup (i.e., the birth // and survival parameters are the first two, and in that order) for (int ifield = 0; ifield < ruleTable.length; ++ifield) if (name.equals(FIELDS[ifield][0])) { // we pack the output bits, where neighbor-count corresponds // directly to bit significance int bits = 0; for (int i = 0; i < value.length(); ++i) { // notice radix of 7 for validation (char must be digit 0-6) int naborcount = Character.digit(value.charAt(i), 7); if (naborcount == -1) // if invalid digit return false; // early RETURN - halt parse and say so bits |= 1 << naborcount; // otherwise OR bit into 'count' position } ruleTable[ifield] = bits; } return true; } }