1. /**
  2. * Overrides the default set methods to use `JSON.stringify`. This allows it to
  3. * work with objects and arrays. See the docs for the built in [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set).
  4. * @extends {Set}
  5. */
  6. export class _Set extends Set {
  7. /**
  8. * Creates a new set. Can also be done with {@link constructors.S}.
  9. * @param {Iterable.<*>} iterable Optional iterable to initialize the set with
  10. * @returns {_Set}
  11. */
  12. constructor(iterable = []) {
  13. super()
  14. for (const element of iterable) {
  15. this.add(element)
  16. }
  17. }
  18. add(item) {
  19. return super.add(JSON.stringify(item))
  20. }
  21. has(item) {
  22. return super.has(JSON.stringify(item))
  23. }
  24. delete(item) {
  25. super.delete(JSON.stringify(item))
  26. return item
  27. }
  28. /**
  29. * Makes a copy of the set
  30. * @returns {_Set}
  31. */
  32. clone() {
  33. return new _Set(this)
  34. }
  35. /**
  36. * Creates set union in place with `other` and returns this set
  37. * @param {_Set} other
  38. * @returns {_Set}
  39. * @example S([1, 2, 3]).union(S([3, 4, 5])) // { 1, 2, 3, 4, 5 }
  40. */
  41. union(other) {
  42. for (const item of other) this.add(item)
  43. return this
  44. }
  45. /**
  46. * Creates set intersection in place with `other` and returns this set
  47. * @param {_Set} other
  48. * @returns {_Set}
  49. * @example S([1, 2, 3]).intersect(S([3, 4, 5])) // { 3 }
  50. */
  51. intersect(other) {
  52. for (const item of this)
  53. if (!other.has(item))
  54. this.delete(item)
  55. return this
  56. }
  57. /**
  58. * Creates set difference in place with `other` and returns this set
  59. * @param {_Set} other
  60. * @returns {_Set}
  61. * @example S([1, 2, 3]).diff(S([3, 4, 5])) // { 1, 2 }
  62. */
  63. diff(other) {
  64. for (const item of other) this.delete(item)
  65. return this
  66. }
  67. /**
  68. * Creates symmetric set difference in place with `other` and returns this set
  69. * @param {_Set} other
  70. * @returns {_Set}
  71. * @example S([1, 2, 3]).symdiff(S([3, 4, 5])) // { 1, 2, 4, 5 }
  72. */
  73. symdiff(other) {
  74. for (const item of other)
  75. if (this.has(item)) this.delete(item)
  76. else this.add(item)
  77. return this
  78. }
  79. *[Symbol.iterator]() {
  80. for (const item of super[Symbol.iterator]()) {
  81. yield JSON.parse(item)
  82. }
  83. }
  84. values() {
  85. return super.values().map(JSON.parse)
  86. }
  87. }
  88. /** Represents a 2D vector. */
  89. export class Vec {
  90. /**
  91. * Creates a new vector. Can also be done with {@link constructors.V}.
  92. * @param {number} x The x component
  93. * @param {number} y The y component
  94. * @returns {Vec}
  95. */
  96. constructor(x, y) {
  97. if (Array.isArray(x)) {
  98. [x, y] = x
  99. } if (typeof x === "object") {
  100. y = x.y
  101. x = x.x
  102. }
  103. if (typeof x !== "number" || typeof y !== "number") {
  104. throw new TypeError(`Vec constructor must be given two numbers (not ${x} and ${y})`)
  105. }
  106. this.x = x
  107. this.y = y
  108. }
  109. /**
  110. * Moves the vector up by `n` units (decreases `y`), in place.
  111. * @param {number} n The number of units to move
  112. * @returns {Vec} The new vector
  113. */
  114. upn(n) { this.y -= n; return this }
  115. /**
  116. * Moves the vector down by `n` units (increases `y`), in place.
  117. * @param {number} n The number of units to move
  118. * @returns {Vec} The new vector
  119. */
  120. downn(n) { this.y += n; return this }
  121. /**
  122. * Moves the vector left by `n` units (decreases `x`), in place.
  123. * @param {number} n The number of units to move
  124. * @returns {Vec} The new vector
  125. */
  126. leftn(n) { this.x -= n; return this }
  127. /**
  128. * Moves the vector right by `n` units (increases `x`), in place.
  129. * @param {number} n The number of units to move
  130. * @returns {Vec} The new vector
  131. */
  132. rightn(n) { this.x += n; return this }
  133. /**
  134. * Moves the vector up by 1 unit using {@link Vec.upn}
  135. * @returns {Vec} The new vector
  136. */
  137. up() { return this.upn(1) }
  138. /**
  139. * Moves the vector down by 1 unit using {@link Vec.downn}
  140. * @returns {Vec} The new vector
  141. */
  142. down() { return this.downn(1) }
  143. /**
  144. * Moves the vector left by 1 unit using {@link Vec.leftn}
  145. * @returns {Vec} The new vector
  146. */
  147. left() { return this.leftn(1) }
  148. /**
  149. * Moves the vector right by 1 unit using {@link Vec.rightn}
  150. * @returns {Vec} The new vector
  151. */
  152. right() { return this.rightn(1) }
  153. /**
  154. * Add another vector to this one
  155. * @param {Vec} other The other vector
  156. * @returns {Vec} A new vector
  157. */
  158. add(other) {
  159. return new Vec(this.x + other.x, this.y + other.y)
  160. }
  161. /**
  162. * Subtract another vector from this one
  163. * @param {Vec} other The other vector
  164. * @returns {Vec} A new vector
  165. */
  166. sub(other) {
  167. return new Vec(this.x - other.x, this.y - other.y)
  168. }
  169. /**
  170. * Multiplies this vector by `factor`
  171. * @param {number} factor The factor to multiply by
  172. * @returns {Vec} A new vector
  173. */
  174. mul(factor) {
  175. return new Vec(this.x * factor, this.y * factor)
  176. }
  177. /**
  178. * Divides this vector by `factor`
  179. * @param {number} factor The factor to divide by
  180. * @returns {Vec} A new vector
  181. */
  182. div(factor) {
  183. return new Vec(this.x / factor, this.y / factor)
  184. }
  185. /**
  186. * Gets a list of the four adjacent vectors to this one
  187. * @returns {Vec[]}
  188. */
  189. adj() {
  190. return [
  191. this.add(new Vec(0, -1)),
  192. this.add(new Vec(0, 1)),
  193. this.add(new Vec(-1, 0)),
  194. this.add(new Vec(1, 0))
  195. ]
  196. }
  197. inrect(a, b) {
  198. if (b === undefined) {
  199. b = a
  200. a = new Vec(0, 0)
  201. }
  202. if (typeof b === "number") b = new Vec(b - 1, b - 1)
  203. return this.x >= a.x && this.x <= b.x && this.y >= a.y && this.y <= b.y
  204. }
  205. /**
  206. * Gets the cell at this vector on `grid`
  207. * @template T
  208. * @param {T[][]} grid The grid to get the cell from
  209. * @returns {T}
  210. */
  211. on(grid) {
  212. return grid[this.y]?.[this.x]
  213. }
  214. /**
  215. * Gets the size of the vector
  216. * @returns {number}
  217. */
  218. get size() {
  219. return Math.hypot(this.x, this.y)
  220. }
  221. /**
  222. * Clones the vector
  223. * @returns {Vec}
  224. */
  225. clone() {
  226. return new Vec(this.x, this.y)
  227. }
  228. *[Symbol.iterator]() {
  229. yield this.x
  230. yield this.y
  231. }
  232. [Symbol.toPrimitive](hint) {
  233. // if (hint === "string") return this.toString()
  234. return this.size
  235. }
  236. }