diff --git a/README.md b/README.md index 960e348..8a4f7f9 100644 --- a/README.md +++ b/README.md @@ -194,6 +194,7 @@ pie | Day | Problem | Solution | Benchmark (μs) | | --- | --- | --- | --: | | 1 | [The Tyranny of the Rocket Equation](https://adventofcode.com/2019/day/1) | [Source](src/year2019/day01.rs) | 1 | +| 2 | [1202 Program Alarm](https://adventofcode.com/2019/day/2) | [Source](src/year2019/day02.rs) | 1 | ## 2015 diff --git a/benches/benchmark.rs b/benches/benchmark.rs index 82399cc..3c08680 100644 --- a/benches/benchmark.rs +++ b/benches/benchmark.rs @@ -121,6 +121,7 @@ mod year2020 { mod year2019 { benchmark!(year2019, day01); + benchmark!(year2019, day02); } mod year2015 { diff --git a/input/year2019/day02.txt b/input/year2019/day02.txt new file mode 100644 index 0000000..99d3840 --- /dev/null +++ b/input/year2019/day02.txt @@ -0,0 +1 @@ +1,0,0,3,1,1,2,3,1,3,4,3,1,5,0,3,2,10,1,19,1,6,19,23,1,23,13,27,2,6,27,31,1,5,31,35,2,10,35,39,1,6,39,43,1,13,43,47,2,47,6,51,1,51,5,55,1,55,6,59,2,59,10,63,1,63,6,67,2,67,10,71,1,71,9,75,2,75,10,79,1,79,5,83,2,10,83,87,1,87,6,91,2,9,91,95,1,95,5,99,1,5,99,103,1,103,10,107,1,9,107,111,1,6,111,115,1,115,5,119,1,10,119,123,2,6,123,127,2,127,6,131,1,131,2,135,1,10,135,0,99,2,0,14,0 diff --git a/src/lib.rs b/src/lib.rs index 413ae49..c851724 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -174,6 +174,7 @@ pub mod year2020 { /// # Rescue Santa from deep space with a solar system adventure. pub mod year2019 { pub mod day01; + pub mod day02; } /// # Help Santa by solving puzzles to fix the weather machine's snow function. diff --git a/src/main.rs b/src/main.rs index 697f981..0ac1b48 100644 --- a/src/main.rs +++ b/src/main.rs @@ -161,6 +161,7 @@ fn all_solutions() -> Vec { solution!(year2020, day25), // 2019 solution!(year2019, day01), + solution!(year2019, day02), // 2015 solution!(year2015, day01), solution!(year2015, day02), diff --git a/src/year2019/day02.rs b/src/year2019/day02.rs new file mode 100644 index 0000000..7b8393f --- /dev/null +++ b/src/year2019/day02.rs @@ -0,0 +1,71 @@ +//! # 1202 Program Alarm +//! +//! Substituting symbols instead of numbers into the program shows that it calculates the value of +//! +//! `a * noun + b * verb + c` +//! +//! We can isolate the value of the constants a, b, c in order to speed up subsequent calculations. +//! +//! As the equation is monotonically increasing in both noun and verb, we can efficiently solve +//! part two by binary searching in two dimensions, instead of a slow brute force check of all +//! possible 10,000 combinations. +use crate::util::parse::*; +use std::cmp::Ordering::*; + +type Input = [i32; 3]; + +pub fn parse(input: &str) -> Input { + let code: Vec<_> = input.iter_unsigned().collect(); + + let c = check(&code, 0, 0) as i32; + let a = check(&code, 1, 0) as i32; + let b = check(&code, 0, 1) as i32; + + [a - c, b - c, c] +} + +pub fn part1([a, b, c]: &Input) -> i32 { + a * 12 + b * 2 + c +} + +pub fn part2(input: &Input) -> i32 { + search(input, 0, 99, 0, 99).unwrap() +} + +fn check(input: &[usize], first: usize, second: usize) -> usize { + let code = &mut input.to_vec(); + code[1] = first; + code[2] = second; + + execute(code) +} + +fn execute(code: &mut [usize]) -> usize { + let mut pc = 0; + + loop { + match code[pc] { + 1 => code[code[pc + 3]] = code[code[pc + 1]] + code[code[pc + 2]], + 2 => code[code[pc + 3]] = code[code[pc + 1]] * code[code[pc + 2]], + _ => break code[0], + } + pc += 4; + } +} + +fn search(input: &Input, x1: i32, x2: i32, y1: i32, y2: i32) -> Option { + if x1 > x2 || y1 > y2 { + return None; + } + + let x = (x1 + x2) / 2; + let y = (y1 + y2) / 2; + let [a, b, c] = input; + let result = a * x + b * y + c; + + match result.cmp(&19690720) { + Equal => Some(100 * x + y), + Less => search(input, x + 1, x2, y1, y2).or_else(|| search(input, x1, x2, y + 1, y2)), + Greater => search(input, x1, x - 1, y1, y2).or_else(|| search(input, x1, x2, y1, y - 1)), + } +} diff --git a/tests/test.rs b/tests/test.rs index a12debd..b22e16d 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -84,6 +84,7 @@ mod year2020 { mod year2019 { mod day01_test; + mod day02_test; } mod year2015 { diff --git a/tests/year2019/day02_test.rs b/tests/year2019/day02_test.rs new file mode 100644 index 0000000..118a2ea --- /dev/null +++ b/tests/year2019/day02_test.rs @@ -0,0 +1,40 @@ +use aoc::year2019::day02::*; + +const EXAMPLE: &str = "\ +1, 0, 0, 0, +2, 32, 0, 0, +2, 33, 1, 1, +2, 34, 2, 2, +1, 35, 0, 0, +1, 1, 0, 0, +1, 2, 0, 0, +99, 0, 0, 0, +0, 1000000, 10000, 7350720, +0, 0, 0, 0, +0, 0, 0, 0, +0, 0, 0, 0, +0, 0, 0, 0, +0, 0, 0, 0, +0, 0, 0, 0, +0, 0, 0, 0, +0, 0, 0, 0, +0, 0, 0, 0, +0, 0, 0, 0, +0, 0, 0, 0, +0, 0, 0, 0, +0, 0, 0, 0, +0, 0, 0, 0, +0, 0, 0, 0, +0, 0, 0, 0"; + +#[test] +fn part1_test() { + let input = parse(EXAMPLE); + assert_eq!(part1(&input), 19370720); +} + +#[test] +fn part2_test() { + let input = parse(EXAMPLE); + assert_eq!(part2(&input), 1234); +}