Stack.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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. * @param {number} [parameterMode=0] The Parameter Mode to use to retrieve the value
  39. * @returns {number} The value at the current pointer position on the stack
  40. */
  41. Get(parameterMode = ComputerParameterMode.POSITION_MODE) {
  42. let value = this._stack[this.pointer];
  43. if (parameterMode == ComputerParameterMode.POSITION_MODE) {
  44. value = this._stack[value];
  45. }
  46. else if (parameterMode == ComputerParameterMode.RELATIVE_MODE) {
  47. value = this._stack[value + this.relativeBaseOffset];
  48. }
  49. return value ?? 0;
  50. }
  51. /**
  52. * Get a value at a given index on the stack
  53. *
  54. * @param {number} index The index of the value to retrieve
  55. * @param {number} [parameterMode=0] The Parameter Mode to use to retrieve the value
  56. * @returns {number} The value at the given index, or 0 if the index hasn't been defined yet
  57. */
  58. GetAtIndex(index, parameterMode = ComputerParameterMode.POSITION_MODE) {
  59. if (index == null || Number.isNaN(index) || !Number.isInteger(index)) {
  60. throw new TypeError("index must be an integer");
  61. }
  62. let value = this._stack[index];
  63. if (parameterMode == ComputerParameterMode.POSITION_MODE) {
  64. value = this._stack[value];
  65. }
  66. else if (parameterMode == ComputerParameterMode.RELATIVE_MODE) {
  67. value = this._stack[value + this.relativeBaseOffset];
  68. }
  69. return value ?? 0;
  70. }
  71. /**
  72. * Use the value at the current pointer to get a value at another position
  73. *
  74. * This is essentially shorthand for `stack.Get(stack.Get())`
  75. *
  76. * @returns {number} The value at the index given by the pointer's current position
  77. */
  78. GetUsingStackValue() {
  79. return this.Get(this._stack[this.pointer]);
  80. }
  81. /**
  82. * Push a new value onto the end of the stack
  83. *
  84. * @param {number} value The value to add
  85. * @returns {void}
  86. */
  87. Push(value) {
  88. this._stack[++this.pointer] = value;
  89. }
  90. /**
  91. * Pop a value off the end of the stack
  92. *
  93. * @returns {number}
  94. * @returns {void}
  95. */
  96. Pop() {
  97. return this._stack.pop();
  98. }
  99. /**
  100. * Overwrite the value at a given index with a new value
  101. *
  102. * The index need not be defined
  103. *
  104. * @param {number} index The index on the stack to write a value to
  105. * @param {number} value The value to write to that position
  106. * @returns {void}
  107. */
  108. Put(index, value) {
  109. this._stack[index] = value;
  110. }
  111. /**
  112. * Sets the pointer to a new address in memory
  113. *
  114. * If the address is out of the upper bounds of the current memory stack,
  115. * the stack will be expanded, filling with 0's as needed.
  116. *
  117. * @param {number} newAddress The new pointer address
  118. * @returns {void}
  119. */
  120. SetPointerAddress(newAddress) {
  121. if (newAddress > this._stack.length) {
  122. // Expand the stack if needed
  123. const oldLength = this._stack.length;
  124. this._stack[newAddress] = 0;
  125. this._stack.fill(0, oldLength, newAddress);
  126. }
  127. this.pointer = newAddress;
  128. }
  129. /**
  130. * Adjust the Relative Base Offset by an amount
  131. *
  132. * @param {number} adjustment A positive or negative integer to add to the Relative Base Offset
  133. * @returns {void}
  134. */
  135. AdjustRelativeBaseOffset(adjustment) {
  136. this.relativeBaseOffset += adjustment;
  137. }
  138. /**
  139. * Return the whole stack
  140. *
  141. * @returns {number[]} The current stack
  142. */
  143. Dump() {
  144. return this._stack;
  145. }
  146. };