Part One complete
This commit is contained in:
parent
08947d2c47
commit
35f5601f1e
@ -1,7 +1,6 @@
|
|||||||
import {anyCharOf, newline, rest, uniLetter, whitespace} from "parjs";
|
import {anyCharOf, newline, uniLetter, whitespace} from "parjs";
|
||||||
import {then, many, manyTill, exactly, between, manySepBy, stringify} from "parjs/combinators";
|
import {between, exactly, manySepBy, manyTill, stringify, then} from "parjs/combinators";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import {CamelCards} from "./day_seven";
|
|
||||||
|
|
||||||
const patternParser = anyCharOf("LR").pipe(manyTill(newline().pipe(exactly(2))));
|
const patternParser = anyCharOf("LR").pipe(manyTill(newline().pipe(exactly(2))));
|
||||||
|
|
||||||
@ -11,64 +10,16 @@ const nodeParser = nodeNameParser.pipe(then(childParser.pipe(between(" = ", whit
|
|||||||
|
|
||||||
const parser = patternParser.pipe(then(nodeParser.pipe(manySepBy(whitespace()))));
|
const parser = patternParser.pipe(then(nodeParser.pipe(manySepBy(whitespace()))));
|
||||||
|
|
||||||
class Node {
|
type Maybe<T> = T | undefined;
|
||||||
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";
|
type Instruction = "L" | "R";
|
||||||
|
type NodeName = string;
|
||||||
|
type NodeChildren = [Maybe<NodeName>, Maybe<NodeName>];
|
||||||
|
|
||||||
export class DesertMap {
|
export class DesertMap {
|
||||||
private readonly pattern: Instruction[];
|
private readonly pattern: Instruction[];
|
||||||
private tree?: Node;
|
|
||||||
|
private map: Record<NodeName, NodeChildren> = {};
|
||||||
|
|
||||||
constructor(input: string) {
|
constructor(input: string) {
|
||||||
const [pattern, nodes] = parser.parse(input).value;
|
const [pattern, nodes] = parser.parse(input).value;
|
||||||
@ -76,38 +27,27 @@ export class DesertMap {
|
|||||||
this.pattern = pattern as Instruction[];
|
this.pattern = pattern as Instruction[];
|
||||||
|
|
||||||
for (const [name, [[leftNode, rightNode]]] of nodes) {
|
for (const [name, [[leftNode, rightNode]]] of nodes) {
|
||||||
if (!this.tree) {
|
if (!this.map[name]) {
|
||||||
this.tree = new Node(name);
|
this.map[name] = [undefined, undefined];
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
const children = [leftNode !== name ? leftNode : undefined, rightNode !== name ? rightNode : undefined];
|
||||||
|
this.map[name] = children as NodeChildren;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public stepsTo(node: string): number {
|
public stepsTo(node: string): number {
|
||||||
if (!this.tree) return 0;
|
|
||||||
|
|
||||||
let step = 0;
|
let step = 0;
|
||||||
let curr = this.tree;
|
let curr = "AAA";
|
||||||
|
|
||||||
while (curr.label !== node) {
|
while (curr !== node) {
|
||||||
const instruction = this.pattern[step % this.pattern.length];
|
const instruction = this.pattern[step % this.pattern.length];
|
||||||
|
|
||||||
if (instruction === "L" && curr.left) {
|
const [left, right] = this.map[curr];
|
||||||
curr = curr.left;
|
|
||||||
} else if (instruction === "R" && curr.right) {
|
if (instruction === "L" && left) {
|
||||||
curr = curr.right;
|
curr = left;
|
||||||
|
} else if (instruction === "R" && right) {
|
||||||
|
curr = right;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!curr) return 0;
|
if (!curr) return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user