123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 |
- /**
- * The code box class
- */
- class CodeBox {
- constructor(codeBoxID, initialStackID, outputID) {
- /**
- * Possible vectors the pointer can move in
- * @type {Object}
- */
- this.directions = {
- NORTH: [-1, 0],
- EAST: [ 0, 1],
- SOUTH: [ 1, 0],
- WEST: [ 0, -1],
- };
- /**
- * The current vector of the pointer
- * @type {int[]}
- */
- this.curr_direction = this.directions.EAST;
- /**
- * The Set of instructions to execute
- *
- * Either a 1 or 2-dimensional array
- * @type {Array|Array[]}
- */
- this.box = [];
- /**
- * The coordinates of the currently executing instruction inside the code box
- * @type {int[]}
- */
- this.pointer = [0,0];
- /**
- * Was the instruction last moving in the left direction
- *
- * Used by the {@link Fisherman}
- * @type {boolean}
- */
- this.dirWasLeft = false;
- /**
- * Are we currently under the influence of the {@link Fisherman}
- * @type {boolean}
- */
- this.onTheHook = false;
- /**
- * Are we currently processing code box instructions as a string
- *
- * 0 when false, otherwise it holds the char code for string delimiter, either
- * 34 or 39
- *
- * @type {int}
- */
- this.stringMode = 0;
- /**
- * The stack for the code box to work with
- *
- * @TODO Implement multiple stacks
- *
- * @type {Stack}
- */
- this.stack = new Stack();
- this.codeBoxDOM = document.getElementById(codeBoxID);
- if(!this.codeBoxDOM) {
- throw new Error(`Failed to find textarea with ID: ${codeBoxID}`);
- }
- this.outputDOM = document.getElementById(outputID);
- if(!this.outputDOM) {
- throw new Error(`Failed to find textarea with ID: ${outputID}`);
- }
- this.initialStackDOM = document.getElementById(initialStackID);
- if(!this.initialStackDOM) {
- throw new Error(`Failed to find input with ID: ${initialStackID}`);
- }
- }
- /**
- * Print the value to the display
- *
- * @TODO Set up an actual display
- * @param {*} value
- */
- Output(value) {
- this.outputDOM.value += value;
- }
- Execute(instruction) {
- let output = null;
- switch(instruction) {
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- case 0:
- case "a":
- case "b":
- case "c":
- case "d":
- case "e":
- case "f":
- this.stack.Push(parseInt(instruction, 16));
- break;
- case "+": {
- const x = this.stack.Pop();
- const y = this.stack.Pop();
- this.stack.Push(x + y);
- break;
- }
- case "-": {
- const x = this.stack.Pop();
- const y = this.stack.Pop();
- this.stack.Push(x - y);
- break;
- }
- case "n":
- output = this.stack.Pop();
- break;
- case "o":
- output = String.fromCharCode(this.stack.Pop());
- break;
- case ";":
- output = true;
- break;
- default:
- throw new Error("Something's fishy!");
- }
- return output;
- }
- Swim() {
- const instruction = this.box[this.pointer[0], this.pointer[1]];
- if(this.stringMode != 0 && instruction != this.stringMode) {
- this.stack.Push(dec(instruction));
- }
- else {
- const exeResult = this.Execute(instruction);
- if(exeResult === true) {
- return true;
- }
- else if(exeResult != null) {
- this.Output(exeResult);
- }
- }
- this.Move();
- }
- Move() {
- const newX = this.pointer[0] + this.curr_direction[0];
- const newY = this.pointer[1] + this.curr_direction[1];
- this.SetPointer(newX, newY);
- }
- /**
- * Implement C and .
- */
- SetPointer(x, y) {
- this.pointer = [x, y];
- }
- /**
- * Implement ^
- *
- * Changes the swim direction upward
- */
- MoveUp() {
- this.curr_direction = this.directions.NORTH;
- }
- /**
- * Implement >
- *
- * Changes the swim direction rightward
- */
- MoveRight() {
- this.curr_direction = this.directions.EAST;
- this.dirWasLeft = false;
- }
- /**
- * Implement v
- *
- * Changes the swim direction downward
- */
- MoveDown() {
- this.curr_direction = this.directions.SOUTH;
- }
- /**
- * Implement <
- *
- * Changes the swim direction leftward
- */
- MoveLeft() {
- this.curr_direction = this.directions.WEST;
- this.dirWasLeft = true;
- }
- /**
- * Implement /
- *
- * Reflects the swim direction depending on its starting value
- */
- ReflectForward() {
- if (this.curr_direction == this.directions.NORTH) {
- this.MoveRight();
- }
- else if (this.curr_direction == this.directions.EAST) {
- this.MoveUp();
- }
- else if (this.curr_direction == this.directions.SOUTH) {
- this.MoveLeft();
- }
- else {
- this.MoveDown();
- }
- }
- /**
- * Implement \
- *
- * Reflects the swim direction depending on its starting value
- */
- ReflectBack() {
- if (this.curr_direction == this.directions.NORTH) {
- this.MoveLeft();
- }
- else if (this.curr_direction == this.directions.EAST) {
- this.MoveDown();
- }
- else if (this.curr_direction == this.directions.SOUTH) {
- this.MoveRight();
- }
- else {
- this.MoveUp();
- }
- }
- /**
- * Implement |
- *
- * Swaps the horizontal swim direction to its opposite
- */
- HorizontalMirror() {
- if (this.curr_direction == this.directions.EAST) {
- this.MoveLeft();
- }
- else {
- this.MoveRight();
- }
- }
- /**
- * Implement _
- *
- * Swaps the horizontal swim direction to its opposite
- */
- VerticalMirror() {
- if (this.curr_direction == this.directions.NORTH) {
- this.MoveDown();
- }
- else {
- this.MoveUp();
- }
- }
- /**
- * Implement #
- *
- * A combination of the vertical and the horizontal mirror
- */
- OmniMirror() {
- if (this.curr_direction[0]) {
- this.VerticalMirror();
- }
- else {
- this.HorizontalMirror();
- }
- }
- /**
- * Implement x
- *
- * Pseudo-randomly switches the swim direction
- */
- ShuffleDirection() {
- this.curr_direction = Object.values(this.directions)[Math.floor(Math.random() * 4)];
- }
- /**
- * Implement `
- *
- * Changes the swim direction based on the previous direction
- * @see https://esolangs.org/wiki/Starfish#Fisherman
- */
- Fisherman() {
- if (this.curr_direction[0]) {
- if (this.dirWasLeft) {
- this.MoveLeft();
- }
- else {
- this.MoveRight();
- }
- }
- else {
- if (this.onTheHook) {
- this.onTheHook = false;
- this.MoveUp();
- }
- else {
- this.onTheHook = true;
- this.MoveDown();
- }
- }
- }
- }
- /**
- * The stack class
- */
- class Stack {
- constructor() {
- /**
- * The stack
- * @type {int[]}
- */
- this.stack = [];
- /**
- * A single value saved off the stack
- * @type {int}
- */
- this.register = null;
- }
- /**
- * Wrapper function for Array.prototype.push
- * @param {*} newValue
- */
- Push(newValue) {
- this.stack.push(newValue);
- }
- /**
- * Wrapper function for Array.prototype.pop
- * @returns {*}
- */
- Pop() {
- return this.stack.pop();
- }
- /**
- * Implement }
- *
- * Shifts the entire stack leftward by one value
- */
- ShiftLeft() {
- const temp = this.stack.shift();
- this.stack.push(temp);
- }
- /**
- * Implement {
- *
- * Shifts the entire stack rightward by one value
- */
- ShiftRight() {
- const temp = this.stack.pop();
- this.stack.unshift(temp);
- }
- /**
- * Implement $
- *
- * Swaps the top two values of the stack
- */
- SwapTwo() {
- // TODO
- }
- /**
- * Implement :
- *
- * Duplicates the element on the top of the stack
- */
- Duplicate() {
- this.stack.push(this.stack[this.stack.length-1]);
- }
- /**
- * Implements ~
- *
- * Removes the element on the top of the stack
- */
- Remove() {
- this.stack.pop();
- }
- /**
- * Implement r
- *
- * Reverses the entire stack
- */
- Reverse() {
- this.stack.reverse();
- }
- /**
- * Implement l
- *
- * Pushes the length of the stack onto the top of the stack
- */
- PushLength() {
- this.stack.push(this.stack.length);
- }
- }
- /**
- * Get the char code of any character
- *
- * Can actually take any length of a value, but only returns the
- * char code of the first character.
- *
- * @param {*} value Any character
- * @returns {int} The value's char code
- */
- function dec(value) {
- return value.toString().charCodeAt(0);
- }
|