UNPKG

@alexaegis/advent-of-code-lib

Version:
340 lines (339 loc) 10.3 kB
"use strict"; const common = require("@alexaegis/common"); const array_polyfill = require("./array.polyfill-uI4B25o5.cjs"); require("js-sdsl"); require("./index-ZPyfgNVR.cjs"); require("./map.cjs"); require("node:perf_hooks"); require("node:fs/promises"); require("node:path"); require("node:fs"); require("kolorist"); require("./set.cjs"); const frequencyMap_function = require("./frequency-map.function-Yy-m-ein.cjs"); const cartesianCombinations = (...arrays) => { const r = []; const max = arrays.length - 1; const cartesianHelper = (arr, i) => { const row = arrays[i]; if (common.isNotNullish(row)) { for (let j = 0, l = row.length; j < l; j++) { const a = [...arr]; a.push(row[j]); if (i === max) r.push(a); else cartesianHelper(a, i + 1); } } }; cartesianHelper([], 0); return r; }; const clamp = (a, high = 1, low = -high, mid = 0) => { if (a > mid) return high; else if (a < mid) return low; else return mid; }; const divisible = (a, b) => a % b === 0; const hzToMs = (hz) => 1 / hz * 1e3; const lcmOverTwo = (x, y) => !x || !y ? 0 : Math.abs(x * y / array_polyfill.gcd(x, y)); const lcm = (x, y) => Array.isArray(x) ? x.reduce((a, n) => lcmOverTwo(a, n), 1) : lcmOverTwo(x, y); const quadratic = (a, b, c) => { const sqrt = Math.sqrt(Math.pow(b, 2) - 4 * a * c); return [(-b - sqrt) / 2 * a, (-b + sqrt) / 2 * a]; }; const crt = (mods) => { return Number( crtBigInt( mods.map(({ remainder, modulo }) => ({ remainder: BigInt(remainder), modulo: BigInt(modulo) })) ) ); }; const crtBigInt = (mods) => { let p = 1n; let sm = 0n; const prod = mods.reduce((acc, { modulo }) => acc * modulo, 1n); for (const { remainder, modulo } of mods) { p = prod / modulo; sm = sm + remainder * array_polyfill.invModBigInt(p, modulo) * p; } return sm % prod; }; class ManhattanCircle { constructor(center, radius) { this.center = center; this.radius = radius; } contains(point) { return this.center.manhattan(point) <= this.radius; } isOnEdge(point) { return this.center.manhattan(point) === this.radius; } vertices() { return this.radius === 0 ? [this.center] : [ new array_polyfill.Vec2(this.center.x - this.radius, this.center.y), // left new array_polyfill.Vec2(this.center.x + this.radius, this.center.y), // right new array_polyfill.Vec2(this.center.x, this.center.y + this.radius), // top new array_polyfill.Vec2(this.center.x, this.center.y - this.radius) // bottom ]; } intersect(other) { return ManhattanCircle.intersect(this, other); } /** * The 'range' of S is 3 in manhattan distance. The effective range at point 'e' * is then 1, because from 'e', at most at 1 manhattan distance is every point * covered by the range of S. * * ...#.... * ..###... * .#####.. * ###S###. * .###e#.. * ..###... * ...#..f. * * Similarly the effective range of S at f is 0 because it's outside the range * of S */ getEffectiveRange(pos) { return Math.max(this.radius - this.center.manhattan(pos), -1); } rowAt(y) { const effectiveRange = this.getEffectiveRange({ x: this.center.x, y }); return effectiveRange >= 0 ? array_polyfill.Interval.closed(this.center.x - effectiveRange, this.center.x + effectiveRange) : array_polyfill.Interval.open(this.center.x, this.center.x); } heightAt(x) { const effectiveRange = this.getEffectiveRange({ x, y: this.center.y }); return effectiveRange >= 0 ? array_polyfill.Interval.closed(this.center.y - effectiveRange, this.center.y + effectiveRange) : array_polyfill.Interval.open(this.center.y, this.center.y); } /** * Returns two points so that both points satisfy * result.center.manhattan(a) === a.radius && result.center.manhattan(b) === b.radius * * If two manhattan circles intersect they have exactly one of their points inside the other * this defines a rectangle, and their opposite ends distance is the same as the other opposing ends * so the distance between the two points that are inside the other, is the same as the distance of the intersections * * taking the half of that, */ static intersect(ac, bc) { const verticesOfAInsideB = ac.vertices().filter((vertex) => bc.contains(vertex)); const verticesOfBInsideA = bc.vertices().filter((vertex) => ac.contains(vertex)); const verticesInsideEachother = [...verticesOfAInsideB, ...verticesOfBInsideA]; if (verticesInsideEachother.length === 2) { const [av, bv] = verticesInsideEachother; const d = av.manhattan(bv); const areFromTheSameCircle = verticesOfAInsideB.length === 2 || verticesOfBInsideA.length === 2; const halver = areFromTheSameCircle ? 4 : 2; const hd = d / halver; const y1 = av.y + hd; const y2 = av.y - hd; const y3 = bv.y + hd; const y4 = bv.y - hd; const x1 = av.x - hd; const x2 = av.x + hd; const x3 = bv.x - hd; const x4 = bv.x + hd; return [ new array_polyfill.Vec2(x1, y1), // new Vec2(x1, y2), // new Vec2(x1, y3), // new Vec2(x1, y4), new array_polyfill.Vec2(x2, y1), new array_polyfill.Vec2(x2, y2), // new Vec2(x2, y3), // new Vec2(x2, y4), // new Vec2(x3, y1), // new Vec2(x3, y2), new array_polyfill.Vec2(x3, y3), new array_polyfill.Vec2(x3, y4), // new Vec2(x4, y1), new array_polyfill.Vec2(x4, y2), // new Vec2(x4, y3), new array_polyfill.Vec2(x4, y4) ].filter((v) => ac.isOnEdge(v) && bc.isOnEdge(v)).reduce((a, n) => { if (!a.some((v) => v.equals(n))) { a.push(n); } return a; }, []); } else { return void 0; } } static *walkIntersections(circles, onlyIntegerIntersections = true) { for (const [a, b] of circles.walkPairs()) { const intersecion = a.intersect(b); if (intersecion) { for (const v of intersecion) { if (!onlyIntegerIntersections || v.isInt()) { yield v; } } } } } static *walkEdges(sensorData) { for (const data of sensorData) { yield* data.center.generateVectorsAroundInManhattanRadius(data.radius + 1); } } clone() { return new ManhattanCircle(this.center.clone(), this.radius); } setRadius(radius) { this.radius = radius; return this; } } class HuffmannNode { constructor(frequency, code) { this.frequency = frequency; this.code = code; } left; right; toString(prefix = "") { let s = `${prefix}${this.code ?? "("}:${this.frequency} `; if (this.left) { s += this.left.toString(prefix + " "); } if (this.right) { s += this.right.toString(prefix + " "); } return s; } *codeTable(prefix = "") { if (this.left) { yield* this.left.codeTable(prefix + "1"); } if (this.code) { yield [this.code, prefix]; } if (this.right) { yield* this.right.codeTable(prefix + "0"); } } } class Huffmann { constructor(input) { this.input = input; this.frequencies = frequencyMap_function.frequencyMap(input); for (const [code, frequency] of this.frequencies) { this.forest.push(new HuffmannNode(frequency, code)); } } frequencies; forest = []; deforest() { while (this.forest.length > 1) { const sortedForest = this.forest.sort((an, bn) => an.frequency - bn.frequency); const a = sortedForest.shift(); const b = sortedForest.shift(); if (a && b) { const n = new HuffmannNode(a.frequency + b.frequency); n.left = a; n.right = b; this.forest = [...sortedForest, n]; } } return this.forest[0]; } } class LZPointer { constructor(jump, length) { this.jump = jump; this.length = length; } } class LZW { tape; dictionary = /* @__PURE__ */ new Map(); symbolSize = 0; constructor(input) { this.tape = input.map((i) => i.toString()); for (const [i, fragment] of [ ...this.tape.reduce((a, n) => a.add(n), /* @__PURE__ */ new Set()).values() ].entries()) { this.dictionary.set(fragment, i); } this.symbolSize = this.dictionary.size; } multiPass(untilDistinctResultSize = 3) { const res = this.compress(1); const lzw = new LZW(res); if (res.reduce((a, n) => a.add(n), /* @__PURE__ */ new Set()).size <= untilDistinctResultSize) { return [res, res.map((r) => r.toString())]; } else { const [r, look] = lzw.multiPass(untilDistinctResultSize); return [r, look]; } } reverse(result) { return result.map((re) => [...this.dictionary.keys()][re]); } compress(rounds = 1, maxDistinctKeys = Number.POSITIVE_INFINITY) { let p = this.tape[0]; let result = []; let i = 0; let r = rounds; let prevDictLength = this.dictionary.size; while (i < r && (maxDistinctKeys === Number.POSITIVE_INFINITY || result.reduce((a, n) => a.add(n), /* @__PURE__ */ new Set()).size > maxDistinctKeys)) { const localTape = [...this.tape]; p = localTape.shift(); result = []; for (const c of localTape) { const pc = p + c; if (this.dictionary.has(pc)) { p = pc; } else if (p !== void 0) { result.push(this.dictionary.get(p)); this.dictionary.set(pc, this.symbolSize++); p = c; } } if (maxDistinctKeys !== Number.POSITIVE_INFINITY && this.dictionary.size > prevDictLength) { prevDictLength = this.dictionary.size; r++; } if (p) { result.push(this.dictionary.get(p)); } i++; } return result; } } exports.Huffmann = Huffmann; exports.HuffmannNode = HuffmannNode; exports.LZPointer = LZPointer; exports.LZW = LZW; exports.ManhattanCircle = ManhattanCircle; exports.cartesianCombinations = cartesianCombinations; exports.clamp = clamp; exports.crt = crt; exports.crtBigInt = crtBigInt; exports.divisible = divisible; exports.hzToMs = hzToMs; exports.lcm = lcm; exports.quadratic = quadratic;