Committing tree structure used, for posterity
This commit is contained in:
parent
16a4bdffd7
commit
08947d2c47
4
index.ts
4
index.ts
@ -1,3 +1,3 @@
|
||||
import {runDaySeven} from "./src/day_seven";
|
||||
import {runDayEight} from "./src/day_eight";
|
||||
|
||||
runDaySeven();
|
||||
runDayEight();
|
29
src/day_eight.test.ts
Normal file
29
src/day_eight.test.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import {DesertMap} from "./day_eight";
|
||||
|
||||
describe('Day Eight', () => {
|
||||
const input = `RL
|
||||
|
||||
AAA = (BBB, CCC)
|
||||
BBB = (DDD, EEE)
|
||||
CCC = (ZZZ, GGG)
|
||||
DDD = (DDD, DDD)
|
||||
EEE = (EEE, EEE)
|
||||
GGG = (GGG, GGG)
|
||||
ZZZ = (ZZZ, ZZZ)`;
|
||||
|
||||
const repeatedInput = `LLR
|
||||
|
||||
AAA = (BBB, BBB)
|
||||
BBB = (AAA, ZZZ)
|
||||
ZZZ = (ZZZ, ZZZ)`
|
||||
|
||||
it('should calculate the number of steps needed to reach ZZZ', () => {
|
||||
const map = new DesertMap(input);
|
||||
expect(map.stepsTo('ZZZ')).toEqual(2);
|
||||
});
|
||||
|
||||
it('should repeat the pattern', () => {
|
||||
const map = new DesertMap(repeatedInput);
|
||||
expect(map.stepsTo('ZZZ')).toEqual(6);
|
||||
})
|
||||
});
|
126
src/day_eight.ts
Normal file
126
src/day_eight.ts
Normal file
@ -0,0 +1,126 @@
|
||||
import {anyCharOf, newline, rest, uniLetter, whitespace} from "parjs";
|
||||
import {then, many, manyTill, exactly, between, manySepBy, stringify} from "parjs/combinators";
|
||||
import fs from "fs";
|
||||
import {CamelCards} from "./day_seven";
|
||||
|
||||
const patternParser = anyCharOf("LR").pipe(manyTill(newline().pipe(exactly(2))));
|
||||
|
||||
const nodeNameParser = uniLetter().pipe(exactly(3), stringify());
|
||||
const childParser = nodeNameParser.pipe(manySepBy(", "), exactly(2), between("(", ")"));
|
||||
const nodeParser = nodeNameParser.pipe(then(childParser.pipe(between(" = ", whitespace()))))
|
||||
|
||||
const parser = patternParser.pipe(then(nodeParser.pipe(manySepBy(whitespace()))));
|
||||
|
||||
class Node {
|
||||
constructor(
|
||||
public label: string,
|
||||
public _left?: Node,
|
||||
public _right?: Node
|
||||
) {
|
||||
if (this._left?.label === label) this._left = undefined;
|
||||
if (this._right?.label === label) this._right = undefined;
|
||||
}
|
||||
|
||||
public set left(node: Node) {
|
||||
if (node.label !== this.label) {
|
||||
this._left = node;
|
||||
}
|
||||
}
|
||||
|
||||
public set right(node: Node) {
|
||||
if (node.label !== this.label) {
|
||||
this._right = node;
|
||||
}
|
||||
}
|
||||
|
||||
public get left(): Node | undefined {
|
||||
return this._left;
|
||||
}
|
||||
|
||||
public get right(): Node | undefined {
|
||||
return this._right;
|
||||
}
|
||||
|
||||
public get isBranch(): boolean {
|
||||
return Boolean(this.left || this.right);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a node by label using basic Depth-first search
|
||||
*/
|
||||
public find(label: string, searchedNodes: string[] = []): Node | undefined {
|
||||
if (this.label === label) return this;
|
||||
if (searchedNodes.includes(this.label)) return;
|
||||
|
||||
if (this.left) {
|
||||
const leftSearch = this.left.find(label, [...searchedNodes, this.label]);
|
||||
if (leftSearch) return leftSearch;
|
||||
}
|
||||
|
||||
if (this.right) {
|
||||
const rightSearch = this.right.find(label, [...searchedNodes, this.label]);
|
||||
if (rightSearch) return rightSearch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Instruction = "L" | "R";
|
||||
|
||||
export class DesertMap {
|
||||
private readonly pattern: Instruction[];
|
||||
private tree?: Node;
|
||||
|
||||
constructor(input: string) {
|
||||
const [pattern, nodes] = parser.parse(input).value;
|
||||
|
||||
this.pattern = pattern as Instruction[];
|
||||
|
||||
for (const [name, [[leftNode, rightNode]]] of nodes) {
|
||||
if (!this.tree) {
|
||||
this.tree = new Node(name);
|
||||
}
|
||||
|
||||
const parent = this.tree.find(name);
|
||||
|
||||
if (!parent) {
|
||||
console.log(`No parent found for label ${name}`)
|
||||
} else {
|
||||
|
||||
const foundLeft = this.tree.find(leftNode);
|
||||
parent.left = foundLeft || new Node(leftNode);
|
||||
|
||||
const foundRight = this.tree.find(rightNode);
|
||||
parent.right = foundRight || new Node(rightNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public stepsTo(node: string): number {
|
||||
if (!this.tree) return 0;
|
||||
|
||||
let step = 0;
|
||||
let curr = this.tree;
|
||||
|
||||
while (curr.label !== node) {
|
||||
const instruction = this.pattern[step % this.pattern.length];
|
||||
|
||||
if (instruction === "L" && curr.left) {
|
||||
curr = curr.left;
|
||||
} else if (instruction === "R" && curr.right) {
|
||||
curr = curr.right;
|
||||
}
|
||||
|
||||
if (!curr) return 0;
|
||||
|
||||
step++;
|
||||
}
|
||||
return step;
|
||||
}
|
||||
}
|
||||
|
||||
export const runDayEight = () => {
|
||||
const input = fs.readFileSync('./inputs/day_eight_input.txt', 'utf-8').trimEnd();
|
||||
|
||||
const map = new DesertMap(input);
|
||||
console.log(map.stepsTo('ZZZ'));
|
||||
}
|
Loading…
Reference in New Issue
Block a user