@alexaegis/advent-of-code-lib
Version:
Advent of Code Library
340 lines (339 loc) • 10.3 kB
JavaScript
"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;