Stack.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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. * Use the value at the current pointer to get a value at another position
  78. *
  79. * This is essentially shorthand for `stack.Get(stack.Get())`
  80. *
  81. * @returns {number} The value at the index given by the pointer's current position
  82. */
  83. GetUsingStackValue() {
  84. return this.Get(this._stack[this.pointer]);
  85. }
  86. /**
  87. * Push a new value onto the end of the stack
  88. *
  89. * @param {number} value The value to add
  90. * @returns {void}
  91. */
  92. Push(value) {
  93. this._stack[++this.pointer] = value;
  94. }
  95. /**
  96. * Pop a value off the end of the stack
  97. *
  98. * @returns {number}
  99. * @returns {void}
  100. */
  101. Pop() {
  102. return this._stack.pop();
  103. }
  104. /**
  105. * Overwrite the value at a given index with a new value
  106. *
  107. * The index need not be defined
  108. *
  109. * @param {number} index The index on the stack to write a value to
  110. * @param {number} value The value to write to that position
  111. * @returns {void}
  112. */
  113. Put(index, value) {
  114. this._stack[index] = value;
  115. }
  116. /**
  117. * Sets the pointer to a new address in memory
  118. *
  119. * If the address is out of the upper bounds of the current memory stack,
  120. * the stack will be expanded, filling with 0's as needed.
  121. *
  122. * @param {number} newAddress The new pointer address
  123. * @returns {void}
  124. */
  125. SetPointerAddress(newAddress) {
  126. if (newAddress > this._stack.length) {
  127. // Expand the stack if needed
  128. const oldLength = this._stack.length;
  129. this._stack[newAddress] = 0;
  130. this._stack.fill(0, oldLength, newAddress);
  131. }
  132. this.pointer = newAddress;
  133. }
  134. /**
  135. * Adjust the Relative Base Offset by an amount
  136. *
  137. * @param {number} adjustment A positive or negative integer to add to the Relative Base Offset
  138. * @returns {void}
  139. */
  140. AdjustRelativeBaseOffset(adjustment) {
  141. this.relativeBaseOffset += adjustment;
  142. }
  143. /**
  144. * Return the whole stack
  145. *
  146. * @returns {number[]} The current stack
  147. */
  148. Dump() {
  149. return this._stack;
  150. }
  151. };