Day Eight: Part Two
This commit is contained in:
parent
35f5601f1e
commit
c86bcbffb6
@ -1,4 +1,4 @@
|
|||||||
import {DesertMap} from "./day_eight";
|
import {DesertMap, lcm} from "./day_eight";
|
||||||
|
|
||||||
describe('Day Eight', () => {
|
describe('Day Eight', () => {
|
||||||
const input = `RL
|
const input = `RL
|
||||||
@ -17,6 +17,17 @@ AAA = (BBB, BBB)
|
|||||||
BBB = (AAA, ZZZ)
|
BBB = (AAA, ZZZ)
|
||||||
ZZZ = (ZZZ, ZZZ)`
|
ZZZ = (ZZZ, ZZZ)`
|
||||||
|
|
||||||
|
const ghostInput = `LR
|
||||||
|
|
||||||
|
11A = (11B, XXX)
|
||||||
|
11B = (XXX, 11Z)
|
||||||
|
11Z = (11B, XXX)
|
||||||
|
22A = (22B, XXX)
|
||||||
|
22B = (22C, 22C)
|
||||||
|
22C = (22Z, 22Z)
|
||||||
|
22Z = (22B, 22B)
|
||||||
|
XXX = (XXX, XXX)`
|
||||||
|
|
||||||
it('should calculate the number of steps needed to reach ZZZ', () => {
|
it('should calculate the number of steps needed to reach ZZZ', () => {
|
||||||
const map = new DesertMap(input);
|
const map = new DesertMap(input);
|
||||||
expect(map.stepsTo('ZZZ')).toEqual(2);
|
expect(map.stepsTo('ZZZ')).toEqual(2);
|
||||||
@ -25,5 +36,16 @@ ZZZ = (ZZZ, ZZZ)`
|
|||||||
it('should repeat the pattern', () => {
|
it('should repeat the pattern', () => {
|
||||||
const map = new DesertMap(repeatedInput);
|
const map = new DesertMap(repeatedInput);
|
||||||
expect(map.stepsTo('ZZZ')).toEqual(6);
|
expect(map.stepsTo('ZZZ')).toEqual(6);
|
||||||
})
|
});
|
||||||
|
|
||||||
|
it('should count how many steps it takes to get from every node beginning with A, to every node ending in Z simultaneously', () => {
|
||||||
|
const map = new DesertMap(ghostInput);
|
||||||
|
expect(map.ghostStepsToZ()).toEqual(6);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('lcm', () => {
|
||||||
|
it('should get the correct lowest common multiple', () => {
|
||||||
|
expect(lcm(12, 30)).toEqual(60);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
@ -1,10 +1,11 @@
|
|||||||
import {anyCharOf, newline, uniLetter, whitespace} from "parjs";
|
import {anyCharOf, int, newline, uniDecimal, uniLetter, whitespace} from "parjs";
|
||||||
import {between, exactly, manySepBy, manyTill, stringify, then} from "parjs/combinators";
|
import {between, exactly, manySepBy, manyTill, or, stringify, then} from "parjs/combinators";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
import { Set } from 'immutable';
|
||||||
|
|
||||||
const patternParser = anyCharOf("LR").pipe(manyTill(newline().pipe(exactly(2))));
|
const patternParser = anyCharOf("LR").pipe(manyTill(newline().pipe(exactly(2))));
|
||||||
|
|
||||||
const nodeNameParser = uniLetter().pipe(exactly(3), stringify());
|
const nodeNameParser = uniLetter().pipe(or(uniDecimal()), exactly(3), stringify());
|
||||||
const childParser = nodeNameParser.pipe(manySepBy(", "), exactly(2), between("(", ")"));
|
const childParser = nodeNameParser.pipe(manySepBy(", "), exactly(2), between("(", ")"));
|
||||||
const nodeParser = nodeNameParser.pipe(then(childParser.pipe(between(" = ", whitespace()))))
|
const nodeParser = nodeNameParser.pipe(then(childParser.pipe(between(" = ", whitespace()))))
|
||||||
|
|
||||||
@ -16,6 +17,16 @@ type Instruction = "L" | "R";
|
|||||||
type NodeName = string;
|
type NodeName = string;
|
||||||
type NodeChildren = [Maybe<NodeName>, Maybe<NodeName>];
|
type NodeChildren = [Maybe<NodeName>, Maybe<NodeName>];
|
||||||
|
|
||||||
|
const gcd = (a: number, b: number): number => {
|
||||||
|
if (b === 0) return a;
|
||||||
|
return gcd(b, a % b);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const lcm = (a: number, b: number): number => {
|
||||||
|
const product = a * b;
|
||||||
|
return product / gcd(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
export class DesertMap {
|
export class DesertMap {
|
||||||
private readonly pattern: Instruction[];
|
private readonly pattern: Instruction[];
|
||||||
|
|
||||||
@ -30,7 +41,7 @@ export class DesertMap {
|
|||||||
if (!this.map[name]) {
|
if (!this.map[name]) {
|
||||||
this.map[name] = [undefined, undefined];
|
this.map[name] = [undefined, undefined];
|
||||||
}
|
}
|
||||||
const children = [leftNode !== name ? leftNode : undefined, rightNode !== name ? rightNode : undefined];
|
const children = [leftNode, rightNode];
|
||||||
this.map[name] = children as NodeChildren;
|
this.map[name] = children as NodeChildren;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,11 +67,46 @@ export class DesertMap {
|
|||||||
}
|
}
|
||||||
return step;
|
return step;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public stepsToZ(from: string): number {
|
||||||
|
let step = 0;
|
||||||
|
let curr = from;
|
||||||
|
|
||||||
|
while (!curr.endsWith('Z')) {
|
||||||
|
const instruction = this.pattern[step % this.pattern.length];
|
||||||
|
|
||||||
|
const [left, right] = this.map[curr];
|
||||||
|
|
||||||
|
if (instruction === "L" && left) {
|
||||||
|
curr = left;
|
||||||
|
} else if (instruction === "R" && right) {
|
||||||
|
curr = right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!curr) return 0;
|
||||||
|
|
||||||
|
step++;
|
||||||
|
}
|
||||||
|
return step;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isComplete(keys: string[]) {
|
||||||
|
return keys.every(key => key.endsWith('Z'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ghostStepsToZ(): number {
|
||||||
|
let keys = Object.keys(this.map).filter(key => key.endsWith('A'));
|
||||||
|
|
||||||
|
return keys.map(key => this.stepsToZ(key)).reduce(lcm, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export const runDayEight = () => {
|
export const runDayEight = () => {
|
||||||
const input = fs.readFileSync('./inputs/day_eight_input.txt', 'utf-8').trimEnd();
|
const input = fs.readFileSync('./inputs/day_eight_input.txt', 'utf-8').trimEnd();
|
||||||
|
|
||||||
const map = new DesertMap(input);
|
const map = new DesertMap(input);
|
||||||
console.log(map.stepsTo('ZZZ'));
|
console.log(map.stepsTo('ZZZ'));
|
||||||
|
|
||||||
|
console.log(map.ghostStepsToZ());
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user