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', () => {
 | 
			
		||||
	const input = `RL
 | 
			
		||||
@ -17,6 +17,17 @@ AAA = (BBB, BBB)
 | 
			
		||||
BBB = (AAA, 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', () => {
 | 
			
		||||
		const map = new DesertMap(input);
 | 
			
		||||
		expect(map.stepsTo('ZZZ')).toEqual(2);
 | 
			
		||||
@ -25,5 +36,16 @@ ZZZ = (ZZZ, ZZZ)`
 | 
			
		||||
	it('should repeat the pattern', () => {
 | 
			
		||||
		const map = new DesertMap(repeatedInput);
 | 
			
		||||
		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 {between, exactly, manySepBy, manyTill, stringify, then} from "parjs/combinators";
 | 
			
		||||
import {anyCharOf, int, newline, uniDecimal, uniLetter, whitespace} from "parjs";
 | 
			
		||||
import {between, exactly, manySepBy, manyTill, or, stringify, then} from "parjs/combinators";
 | 
			
		||||
import fs from "fs";
 | 
			
		||||
import { Set } from 'immutable';
 | 
			
		||||
 | 
			
		||||
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 nodeParser = nodeNameParser.pipe(then(childParser.pipe(between(" = ", whitespace()))))
 | 
			
		||||
 | 
			
		||||
@ -16,6 +17,16 @@ type Instruction = "L" | "R";
 | 
			
		||||
type NodeName = string;
 | 
			
		||||
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 {
 | 
			
		||||
	private readonly pattern: Instruction[];
 | 
			
		||||
 | 
			
		||||
@ -30,7 +41,7 @@ export class DesertMap {
 | 
			
		||||
			if (!this.map[name]) {
 | 
			
		||||
				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;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@ -56,11 +67,46 @@ export class DesertMap {
 | 
			
		||||
		}
 | 
			
		||||
		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 = () => {
 | 
			
		||||
	const input = fs.readFileSync('./inputs/day_eight_input.txt', 'utf-8').trimEnd();
 | 
			
		||||
 | 
			
		||||
	const map = new DesertMap(input);
 | 
			
		||||
	console.log(map.stepsTo('ZZZ'));
 | 
			
		||||
 | 
			
		||||
	console.log(map.ghostStepsToZ());
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user