Stack.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. const ComputerParameterMode = require("./ComputerParameterMode");
  2. /**
  3. * The stack, or memory, for the Intcode Computer
  4. *
  5. * @author Apis Necros
  6. */
  7. module.exports = class Stack {
  8. constructor(stack) {
  9. this.pointer = 0;
  10. this._stack = stack;
  11. /**
  12. * The relative base offset for the stack
  13. *
  14. * This value is used when finding a parameter in Relative Parameter Mode.
  15. * It is added to an address to find the needed value at the calculated
  16. * address.
  17. */
  18. this.relativeBaseOffset = 0;
  19. }
  20. /**
  21. * Move the stack's pointer to the right by 1
  22. * @returns {void}
  23. */
  24. Next() {
  25. this.pointer++;
  26. return this;
  27. }
  28. /**
  29. * Move the stack's pointer to the left by 1
  30. * @returns {void}
  31. */
  32. Prev() {
  33. this.pointer--;
  34. }
  35. /**
  36. * Get the value from the stack by the pointer's current position
  37. *
  38. * When `isOutput` is set to `true`, then a value retrieved in Immediate Mode,
  39. * or the result of a Relative Mode offset is returned.
  40. *
  41. * @param {number} [parameterMode=0] The Parameter Mode to use to retrieve the value
  42. * @param {boolean} [isOutput=false] Is the parameter going to be an output position
  43. * @returns {number} The value at the current pointer position on the stack
  44. */
  45. Get(parameterMode = ComputerParameterMode.POSITION_MODE, isOutput = false) {
  46. let value = this._stack[this.pointer];
  47. if (!isOutput && parameterMode == ComputerParameterMode.POSITION_MODE) {
  48. value = this._stack[value];
  49. }
  50. else if (parameterMode == ComputerParameterMode.RELATIVE_MODE) {
  51. const newPointer = value + this.relativeBaseOffset;
  52. value = isOutput ? newPointer : this._stack[newPointer];
  53. }
  54. return value ?? 0;
  55. }
  56. /**
  57. * Get a value at a given index on the stack
  58. *
  59. * @param {number} index The index of the value to retrieve
  60. * @param {number} [parameterMode=0] The Parameter Mode to use to retrieve the value
  61. * @returns {number} The value at the given index, or 0 if the index hasn't been defined yet
  62. */
  63. GetAtIndex(index, parameterMode = ComputerParameterMode.POSITION_MODE) {
  64. if (index == null || Number.isNaN(index) || !Number.isInteger(index)) {
  65. throw new TypeError("index must be an integer");
  66. }
  67. let value = this._stack[index];
  68. if (parameterMode == ComputerParameterMode.POSITION_MODE) {
  69. value = this._stack[value];
  70. }
  71. else if (parameterMode == ComputerParameterMode.RELATIVE_MODE) {
  72. value = this._stack[value + this.relativeBaseOffset];
  73. }
  74. return value ?? 0;
  75. }
  76. /**
  77. * Push a new value onto the end of the stack
  78. *
  79. * @param {number} value The value to add
  80. * @returns {void}
  81. */
  82. Push(value) {
  83. this._stack[++this.pointer] = value;
  84. }
  85. /**
  86. * Pop a value off the end of the stack
  87. *
  88. * @returns {number}
  89. * @returns {void}
  90. */
  91. Pop() {
  92. return this._stack.pop();
  93. }
  94. /**
  95. * Overwrite the value at a given index with a new value
  96. *
  97. * The index need not be defined
  98. *
  99. * @param {number} index The index on the stack to write a value to
  100. * @param {number} value The value to write to that position
  101. * @returns {void}
  102. */
  103. Put(index, value) {
  104. this._stack[index] = value;
  105. }
  106. /**
  107. * Sets the pointer to a new address in memory
  108. *
  109. * If the address is out of the upper bounds of the current memory stack,
  110. * the stack will be expanded, filling with 0's as needed.
  111. *
  112. * @param {number} newAddress The new pointer address
  113. * @returns {void}
  114. */
  115. SetPointerAddress(newAddress) {
  116. if (newAddress > this._stack.length) {
  117. // Expand the stack if needed
  118. const oldLength = this._stack.length;
  119. this._stack[newAddress] = 0;
  120. this._stack.fill(0, oldLength, newAddress);
  121. }
  122. this.pointer = newAddress;
  123. }
  124. /**
  125. * Adjust the Relative Base Offset by an amount
  126. *
  127. * @param {number} adjustment A positive or negative integer to add to the Relative Base Offset
  128. * @returns {void}
  129. */
  130. AdjustRelativeBaseOffset(adjustment) {
  131. this.relativeBaseOffset += adjustment;
  132. }
  133. /**
  134. * Return the whole stack
  135. *
  136. * @returns {number[]} The current stack
  137. */
  138. Dump() {
  139. return this._stack;
  140. }
  141. };