Add solutions for part 1
This commit is contained in:
205
projects/09/CellAutomaton1D/CellularAutomaton.jack
Normal file
205
projects/09/CellAutomaton1D/CellularAutomaton.jack
Normal file
@@ -0,0 +1,205 @@
|
||||
/** Represents a 1D cellular automaton that can be printed to the screen. */
|
||||
class CellularAutomaton {
|
||||
|
||||
field Array currentConfig; // an array where each field represents one cell
|
||||
field int currentRule; // the current rule used by nextState
|
||||
field int currentRow; // the row on the screen where the last state was printed
|
||||
field int size; // cells per row
|
||||
field boolean debug; // print debugging help to screen if true
|
||||
|
||||
/** Create a new automaton where size is the number of cells per row. */
|
||||
constructor CellularAutomaton new() {
|
||||
var int i;
|
||||
let currentRule = 0;
|
||||
let currentRow = 0;
|
||||
let size = 512;
|
||||
let debug = false;
|
||||
|
||||
let currentConfig = Array.new(size);
|
||||
let i = 0;
|
||||
while (i < size) {
|
||||
let currentConfig[i] = 0;
|
||||
let i = i + 1;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Returns a reference to the current config. Be careful, step creates a
|
||||
* new configuration so using the reference after calling step points to
|
||||
* invalid memory.
|
||||
*/
|
||||
method Array getCurrentConfig() {
|
||||
return currentConfig;
|
||||
}
|
||||
|
||||
method void dispose() {
|
||||
do currentConfig.dispose();
|
||||
do Memory.deAlloc(this);
|
||||
return;
|
||||
}
|
||||
|
||||
method void setRule(int rule) {
|
||||
let currentRule = rule;
|
||||
return;
|
||||
}
|
||||
|
||||
/** Draws the current configuration to the currentRow on the screen. */
|
||||
method void draw() {
|
||||
if (currentRow > 255) {
|
||||
// This works, but is slow and I don't know how to make it faster.
|
||||
// So we simply start from the top instead again.
|
||||
// do drawLastRow();
|
||||
let currentRow = 0;
|
||||
do Screen.clearScreen();
|
||||
do drawNewRow();
|
||||
} else {
|
||||
do drawNewRow();
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
do Screen.setColor(true);
|
||||
do Output.moveCursor(0, 0);
|
||||
do Output.printInt(currentRow);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/** If we are not yet in the last row we can simply
|
||||
* print the new config to the next row. */
|
||||
method void drawNewRow() {
|
||||
var int i;
|
||||
let i = 0;
|
||||
while (i < size) {
|
||||
if (currentConfig[i]) {
|
||||
do Screen.setColor(true);
|
||||
} else {
|
||||
do Screen.setColor(false);
|
||||
}
|
||||
do Screen.drawPixel(i, currentRow);
|
||||
let i = i + 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
method void copy(int sourceAddress, int targetAddress) {
|
||||
var int value;
|
||||
let value = Memory.peek(sourceAddress);
|
||||
do Memory.poke(targetAddress, value);
|
||||
return;
|
||||
}
|
||||
|
||||
/** If we are in the last row we first have to move all existing rows one
|
||||
* row up. We can then draw the last row. XXX: This works, but we are
|
||||
* currently not using it because it is too slow. */
|
||||
method void drawLastRow() {
|
||||
var int i;
|
||||
var int sourceAddress;
|
||||
|
||||
// Screen Base + Words = 16384 + 8160 = 24544
|
||||
let i = 16383;
|
||||
while (i < 24544) {
|
||||
let sourceAddress = i + 32;
|
||||
do copy(sourceAddress, i);
|
||||
let i = i + 1;
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
while (i < size) {
|
||||
if (currentConfig[i]) {
|
||||
do Screen.setColor(true);
|
||||
} else {
|
||||
do Screen.setColor(false);
|
||||
}
|
||||
do Screen.drawPixel(i, currentRow);
|
||||
let i = i + 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
method int rule_57(int left, int middle, int right) {
|
||||
if (left = 1) { if (middle = 1) { if (right = 1) { return 0; } } }
|
||||
if (left = 1) { if (middle = 1) { if (right = 0) { return 0; } } }
|
||||
if (left = 0) { if (middle = 1) { if (right = 0) { return 0; } } }
|
||||
if (left = 0) { if (middle = 0) { if (right = 1) { return 0; } } }
|
||||
return 1;
|
||||
}
|
||||
|
||||
method int rule_90(int left, int middle, int right) {
|
||||
let middle = left + right;
|
||||
if (middle = 1) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
method int rule_101(int left, int middle, int right) {
|
||||
if (left = 1) { if (middle = 1) { if (right = 1) { return 0; } } }
|
||||
if (left = 1) { if (middle = 0) { if (right = 0) { return 0; } } }
|
||||
if (left = 0) { if (middle = 1) { if (right = 1) { return 0; } } }
|
||||
if (left = 0) { if (middle = 0) { if (right = 1) { return 0; } } }
|
||||
return 1;
|
||||
}
|
||||
|
||||
method int rule_110(int left, int middle, int right) {
|
||||
if (left = 1) { if (middle = 1) { if (right = 1) { return 0; } } }
|
||||
if (left = 1) { if (middle = 0) { if (right = 0) { return 0; } } }
|
||||
if (left = 0) { if (middle = 0) { if (right = 0) { return 0; } } }
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Calculates the next configuration based on currentConfig and
|
||||
* currentRule */
|
||||
method void step() {
|
||||
var int i, limit;
|
||||
var Array newConfig;
|
||||
let newConfig = Array.new(size);
|
||||
let currentRow = currentRow + 1;
|
||||
|
||||
if (currentRule = 57) {
|
||||
// Calculate new state of first cell
|
||||
let newConfig[0] = rule_57(0, currentConfig[0], currentConfig[1]);
|
||||
// Calculate new state of last cell
|
||||
let newConfig[511] = rule_57(currentConfig[510], currentConfig[511], 0);
|
||||
// All the other cells
|
||||
let i = 1; // Skip first cell and last cell
|
||||
while (i < 511) {
|
||||
let newConfig[i] = rule_57(currentConfig[i - 1], currentConfig[i], currentConfig[i + 1]);
|
||||
let i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentRule = 90) {
|
||||
let newConfig[0] = rule_90(0, currentConfig[0], currentConfig[1]);
|
||||
let newConfig[511] = rule_90(currentConfig[510], currentConfig[511], 0);
|
||||
let i = 1;
|
||||
while (i < 511) {
|
||||
let newConfig[i] = rule_90(currentConfig[i - 1], currentConfig[i], currentConfig[i + 1]);
|
||||
let i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentRule = 101) {
|
||||
let newConfig[0] = rule_101(0, currentConfig[0], currentConfig[1]);
|
||||
let newConfig[511] = rule_101(currentConfig[510], currentConfig[511], 0);
|
||||
let i = 1;
|
||||
while (i < 511) {
|
||||
let newConfig[i] = rule_101(currentConfig[i - 1], currentConfig[i], currentConfig[i + 1]);
|
||||
let i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentRule = 110) {
|
||||
let newConfig[0] = rule_110(0, currentConfig[0], currentConfig[1]);
|
||||
let newConfig[511] = rule_110(currentConfig[510], currentConfig[511], 0);
|
||||
let i = 1;
|
||||
while (i < 511) {
|
||||
let newConfig[i] = rule_110(currentConfig[i - 1], currentConfig[i], currentConfig[i + 1]);
|
||||
let i = i + 1;
|
||||
}
|
||||
}
|
||||
do currentConfig.dispose();
|
||||
let currentConfig = newConfig;
|
||||
return;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user