123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- const ComputerParameterMode = require("./ComputerParameterMode");
- /**
- * The stack, or memory, for the Intcode Computer
- *
- * @author Apis Necros
- */
- module.exports = class Stack {
- constructor(stack) {
- this.pointer = 0;
- this._stack = stack;
- /**
- * The relative base offset for the stack
- *
- * This value is used when finding a parameter in Relative Parameter Mode.
- * It is added to an address to find the needed value at the calculated
- * address.
- */
- this.relativeBaseOffset = 0;
- }
- /**
- * Move the stack's pointer to the right by 1
- * @returns {void}
- */
- Next() {
- this.pointer++;
- return this;
- }
- /**
- * Move the stack's pointer to the left by 1
- * @returns {void}
- */
- Prev() {
- this.pointer--;
- }
- /**
- * Get the value from the stack by the pointer's current position
- *
- * When `isOutput` is set to `true`, then a value retrieved in Immediate Mode,
- * or the result of a Relative Mode offset is returned.
- *
- * @param {number} [parameterMode=0] The Parameter Mode to use to retrieve the value
- * @param {boolean} [isOutput=false] Is the parameter going to be an output position
- * @returns {number} The value at the current pointer position on the stack
- */
- Get(parameterMode = ComputerParameterMode.POSITION_MODE, isOutput = false) {
- let value = this._stack[this.pointer];
- if (!isOutput && parameterMode == ComputerParameterMode.POSITION_MODE) {
- value = this._stack[value];
- }
- else if (parameterMode == ComputerParameterMode.RELATIVE_MODE) {
- const newPointer = value + this.relativeBaseOffset;
- value = isOutput ? newPointer : this._stack[newPointer];
- }
- return value ?? 0;
- }
- /**
- * Get a value at a given index on the stack
- *
- * @param {number} index The index of the value to retrieve
- * @param {number} [parameterMode=0] The Parameter Mode to use to retrieve the value
- * @returns {number} The value at the given index, or 0 if the index hasn't been defined yet
- */
- GetAtIndex(index, parameterMode = ComputerParameterMode.POSITION_MODE) {
- if (index == null || Number.isNaN(index) || !Number.isInteger(index)) {
- throw new TypeError("index must be an integer");
- }
- let value = this._stack[index];
- if (parameterMode == ComputerParameterMode.POSITION_MODE) {
- value = this._stack[value];
- }
- else if (parameterMode == ComputerParameterMode.RELATIVE_MODE) {
- value = this._stack[value + this.relativeBaseOffset];
- }
- return value ?? 0;
- }
- /**
- * Use the value at the current pointer to get a value at another position
- *
- * This is essentially shorthand for `stack.Get(stack.Get())`
- *
- * @returns {number} The value at the index given by the pointer's current position
- */
- GetUsingStackValue() {
- return this.Get(this._stack[this.pointer]);
- }
- /**
- * Push a new value onto the end of the stack
- *
- * @param {number} value The value to add
- * @returns {void}
- */
- Push(value) {
- this._stack[++this.pointer] = value;
- }
- /**
- * Pop a value off the end of the stack
- *
- * @returns {number}
- * @returns {void}
- */
- Pop() {
- return this._stack.pop();
- }
- /**
- * Overwrite the value at a given index with a new value
- *
- * The index need not be defined
- *
- * @param {number} index The index on the stack to write a value to
- * @param {number} value The value to write to that position
- * @returns {void}
- */
- Put(index, value) {
- this._stack[index] = value;
- }
- /**
- * Sets the pointer to a new address in memory
- *
- * If the address is out of the upper bounds of the current memory stack,
- * the stack will be expanded, filling with 0's as needed.
- *
- * @param {number} newAddress The new pointer address
- * @returns {void}
- */
- SetPointerAddress(newAddress) {
- if (newAddress > this._stack.length) {
- // Expand the stack if needed
- const oldLength = this._stack.length;
- this._stack[newAddress] = 0;
- this._stack.fill(0, oldLength, newAddress);
- }
- this.pointer = newAddress;
- }
- /**
- * Adjust the Relative Base Offset by an amount
- *
- * @param {number} adjustment A positive or negative integer to add to the Relative Base Offset
- * @returns {void}
- */
- AdjustRelativeBaseOffset(adjustment) {
- this.relativeBaseOffset += adjustment;
- }
- /**
- * Return the whole stack
- *
- * @returns {number[]} The current stack
- */
- Dump() {
- return this._stack;
- }
- };
|