Files
N2T/projects/09/CellAutomaton1D/CellularAutomatonController.jack
2020-11-15 13:57:48 -05:00

371 lines
11 KiB
Plaintext

/** Manages the cellular automaton and interacts with the user. */
class CellularAutomatonController {
field CellularAutomaton automaton;
field Array config;
field Array rules;
field int numRules;
constructor CellularAutomatonController new() {
// Turned out it is easiest to manage the Automaton itself from here.
let automaton = CellularAutomaton.new();
// We need the cell state array to write the initial configuration
// by the user into it.
let config = automaton.getCurrentConfig();
// Array to switch between rules.
let numRules = 4;
let rules = Array.new(numRules);
let rules[0] = 57;
let rules[1] = 90;
let rules[2] = 101;
let rules[3] = 110;
return this;
}
method void dispose() {
// config gets deAllocated by CellularAutomaton!
do automaton.dispose();
do rules.dispose();
do Memory.deAlloc(this);
return;
}
/** Greets the user and guides through the initial configuration. */
method void initialConfiguration() {
do Screen.clearScreen();
do Screen.setColor(true);
do sayHello();
do printHelpInitialConfiguration();
do createInitialConfiguration();
do selectRule();
do finishConfiguration();
return;
}
/** Prints some dots on the screen to simulate loading, because why not? */
method void makeWaitDots() {
do Sys.wait(30);
do Output.printString(".");
do Sys.wait(30);
do Output.printString(".");
do Sys.wait(30);
do Output.printString(".");
do Sys.wait(30);
do Output.printString(" ");
return;
}
method void waitForEnter() {
var int key;
var boolean exit;
let key = 0;
let exit = false;
do Output.printString("<Enter> to continue. ");
while (~exit) {
while (key = 0) {
let key = Keyboard.keyPressed();
}
if (key = 128) { let exit = true; } // enter key
while (~(key = 0)) {
let key = Keyboard.keyPressed();
}
}
return;
}
method void sayHello() {
do Output.moveCursor(0, 0);
do Output.printString("> Welcome to cellular automaton 1D! ");
do makeWaitDots();
do Output.moveCursor(1, 0);
do Output.printString("> Let's configure the automaton");
do makeWaitDots();
return;
}
method void printHelpInitialConfiguration() {
do Output.moveCursor(3, 0);
do Output.printString("> Toggle the cells that should be alive with <space>");
do makeWaitDots();
do Output.moveCursor(4, 0);
do Output.printString("> Move with <h>/<l> and use <u>/<i> to change the step size");
do makeWaitDots();
do Output.moveCursor(6, 0);
do Output.printString("> stepSize = 1 - position = - activeCells = ");
return;
}
method void printStepSize(int n) {
do Output.moveCursor(6, 15);
do Output.printString(" ");
do Output.moveCursor(6, 15);
do Output.printInt(n);
return;
}
method void printCursorPosition(int n) {
do Output.moveCursor(6, 32);
do Output.printString(" ");
do Output.moveCursor(6, 32);
do Output.printInt(n);
return;
}
method void printActiveCellsj(int n) {
do Output.moveCursor(6, 52);
do Output.printString(" ");
do Output.moveCursor(6, 52);
do Output.printInt(n);
return;
}
method void createInitialConfiguration() {
var int key;
var boolean exit;
var int cursorPosition;
var int stepSize;
var int activeCells;
// Variables for printing the cell selction UI.
var int cursorY1, cursorY2, cellY1, cellY2;
let key = 0;
let cursorY1 = 90;
let cursorY2 = 95;
let cellY1 = 85;
let cellY2 = 88;
let stepSize = 1;
let cursorPosition = 0;
let activeCells = 0;
do printStepSize(stepSize);
do printCursorPosition(cursorPosition);
do printActiveCellsj(activeCells);
do Screen.drawLine(cursorPosition, cursorY1, cursorPosition, cursorY2);
let exit = false;
while (~exit) {
while (key = 0) {
let key = Keyboard.keyPressed();
}
if (key = 128) { // enter key
if (activeCells > 0) {
let exit = true;
} else {
do Output.moveCursor(9, 0);
do Output.printString("> Toggle at least one cell!");
}
} // enter key
if (key = 72) { // h key
do Screen.setColor(false);
do Screen.drawLine(cursorPosition, cursorY1, cursorPosition, cursorY2);
if ((cursorPosition - stepSize) > 0) {
let cursorPosition = cursorPosition - stepSize;
} else {
let cursorPosition = 0;
}
do Screen.setColor(true);
do Screen.drawLine(cursorPosition, cursorY1, cursorPosition, cursorY2);
do printCursorPosition(cursorPosition);
}
if (key = 76) { // l key
do Screen.setColor(false);
do Screen.drawLine(cursorPosition, cursorY1, cursorPosition, cursorY2);
if ((cursorPosition + stepSize) < 511) {
let cursorPosition = cursorPosition + stepSize;
} else {
let cursorPosition = 511;
}
do Screen.setColor(true);
do Screen.drawLine(cursorPosition, cursorY1, cursorPosition, cursorY2);
do printCursorPosition(cursorPosition);
}
if (key = 73) { // i key
if (stepSize < 512) {
let stepSize = stepSize * 2;
do printStepSize(stepSize);
}
}
if (key = 85) { // u key
if (stepSize > 1) {
let stepSize = stepSize / 2;
do printStepSize(stepSize);
}
}
if (key = 32) { // space key
if (config[cursorPosition]) { // cell is alive -> make dead
do Screen.setColor(false);
do Screen.drawLine(cursorPosition, cellY1, cursorPosition, cellY2);
let config[cursorPosition] = 0;
let activeCells = activeCells - 1;
} else { // cell is dead -> make alive
do Screen.setColor(true);
do Screen.drawLine(cursorPosition, cellY1, cursorPosition, cellY2);
let config[cursorPosition] = 1;
let activeCells = activeCells + 1;
}
do Screen.setColor(true);
do printActiveCellsj(activeCells);
}
while (~(key = 0)) {
let key = Keyboard.keyPressed();
}
}
return;
}
method void printRule(int n) {
do Output.moveCursor(12, 8);
do Output.printString(" ");
do Output.moveCursor(12, 8);
do Output.printInt(n);
return;
}
method void selectRule() {
var int i;
var int rule;
var int key;
var boolean exit;
let i = 1;
let rule = rules[i];
let exit = false;
do Output.moveCursor(10, 0);
do Output.printString("> Good. Let's select which rule you want to simulate");
do makeWaitDots();
do Output.moveCursor(11, 0);
do Output.printString("> Use <h>/<l> to switch between rules");
do makeWaitDots();
do Output.moveCursor(12, 0);
do Output.printString("> Rule selected. Confirm with <enter>.");
do printRule(rule);
while (~exit) {
while (key = 0) {
let key = Keyboard.keyPressed();
}
if (key = 128) { // enter key
let exit = true;
}
if (key = 72) { // h key -> prev rule
if (i > 0) {
let i = i - 1;
}
}
if (key = 76) {
if (i < (numRules - 1)) {
let i = i + 1;
}
}
let rule = rules[i];
do printRule(rule);
do automaton.setRule(rule);
while (~(key = 0)) {
let key = Keyboard.keyPressed();
}
}
return;
}
method void finishConfiguration() {
do Output.moveCursor(15, 0);
do Output.printString("> Okay, nice. We are ready to go");
do makeWaitDots();
do Output.moveCursor(16, 0);
do Output.printString("> Once you press enter you will no longer see the menu");
do makeWaitDots();
do Output.moveCursor(17, 0);
do Output.printString("> So remember the following keys (or at least <q> for quit)");
do makeWaitDots();
do Output.moveCursor(19, 0);
do Output.printString("> Controls: ");
do makeWaitDots();
do Output.moveCursor(20, 0);
do Output.printString("> <p>ause, <c>ontinue, <s>tep, <r>restart, <q>quit! ");
do Output.moveCursor(22, 0);
do Output.printString(" ");
do waitForEnter();
do Screen.clearScreen();
return;
}
method void run() {
var int key;
var boolean quit;
var boolean running;
var boolean restart;
var boolean step;
let quit = false;
let restart = false;
let running = true;
let step = false;
while (~quit) {
if (restart) {
do automaton.dispose();
let automaton = CellularAutomaton.new();
do initialConfiguration();
let quit = false;
let restart = false;
let running = true;
let step = false;
}
if (running) {
do automaton.draw();
do automaton.step();
}
if (step) {
do automaton.draw();
do automaton.step();
let step = false;
}
let key = Keyboard.keyPressed();
if (key = 82) { // r key
let restart = true;
}
if (key = 80) { // p key
let running = false;
}
if (key = 67) { // c key
let running = true;
}
if (key = 83) { // s key
if (~running) {
let step = true;
}
}
if (key = 81) { // q key
let quit = true;
}
while (~(key = 0)) {
let key = Keyboard.keyPressed();
}
}
return;
}
}