Compare commits
9 Commits
59a21265c6
...
main
Author | SHA1 | Date | |
---|---|---|---|
272761b05c | |||
f9d58356cd | |||
a0c9ce9882 | |||
9fc94b0e06 | |||
c88b97182d | |||
0407edf928 | |||
b44361e14d | |||
90561f8fa9 | |||
2c499e9efe |
52
Cargo.lock
generated
52
Cargo.lock
generated
@@ -9,10 +9,21 @@ dependencies = [
|
|||||||
"aoc-runner",
|
"aoc-runner",
|
||||||
"aoc-runner-derive",
|
"aoc-runner-derive",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"lazy_static",
|
||||||
|
"regex",
|
||||||
"strum",
|
"strum",
|
||||||
"strum_macros",
|
"strum_macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aoc-runner"
|
name = "aoc-runner"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@@ -69,6 +80,18 @@ version = "1.0.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.71"
|
version = "1.0.71"
|
||||||
@@ -87,6 +110,35 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.14"
|
version = "1.0.14"
|
||||||
|
@@ -14,3 +14,5 @@ aoc-runner-derive = "0.3.0"
|
|||||||
itertools = "0.12.0"
|
itertools = "0.12.0"
|
||||||
strum = "0.25.0"
|
strum = "0.25.0"
|
||||||
strum_macros = "0.25"
|
strum_macros = "0.25"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
regex = "1.10.2"
|
109
src/day10.rs
Normal file
109
src/day10.rs
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
#[aoc_generator(day10)]
|
||||||
|
fn parse(input: &str) -> Vec<u32> {
|
||||||
|
input.lines().map(str::parse).map(Result::unwrap).sorted().collect_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day10, part1)]
|
||||||
|
fn part1(input: &Vec<u32>) -> u32 {
|
||||||
|
let mut count1 = 1;
|
||||||
|
let mut count3 = 1;
|
||||||
|
for (lhs, rhs) in input.iter().tuple_windows() {
|
||||||
|
match rhs - lhs {
|
||||||
|
1 => count1 += 1,
|
||||||
|
3 => count3 += 1,
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
count1 * count3
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day10, part2)]
|
||||||
|
fn part2(input: &Vec<u32>) -> i64 {
|
||||||
|
let mut ans = HashMap::new();
|
||||||
|
ans.insert(0, 1);
|
||||||
|
for adapter in input.iter().cloned().map(|x| x as i32) {
|
||||||
|
let to_insert = ans.get(&(adapter as i32 - 1)).unwrap_or(&0)
|
||||||
|
+ ans.get(&(adapter as i32 - 2)).unwrap_or(&0)
|
||||||
|
+ ans.get(&(adapter as i32 - 3)).unwrap_or(&0);
|
||||||
|
|
||||||
|
ans.insert(adapter, to_insert.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ans[&(*input.last().unwrap() as i32)]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const EX: &str = r"16
|
||||||
|
10
|
||||||
|
15
|
||||||
|
5
|
||||||
|
1
|
||||||
|
11
|
||||||
|
7
|
||||||
|
19
|
||||||
|
6
|
||||||
|
12
|
||||||
|
4";
|
||||||
|
|
||||||
|
const EX_2: &str = r"28
|
||||||
|
33
|
||||||
|
18
|
||||||
|
42
|
||||||
|
31
|
||||||
|
14
|
||||||
|
46
|
||||||
|
20
|
||||||
|
48
|
||||||
|
47
|
||||||
|
24
|
||||||
|
23
|
||||||
|
49
|
||||||
|
45
|
||||||
|
19
|
||||||
|
38
|
||||||
|
39
|
||||||
|
11
|
||||||
|
1
|
||||||
|
32
|
||||||
|
25
|
||||||
|
35
|
||||||
|
8
|
||||||
|
17
|
||||||
|
7
|
||||||
|
9
|
||||||
|
4
|
||||||
|
2
|
||||||
|
34
|
||||||
|
10
|
||||||
|
3";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example() {
|
||||||
|
assert_eq!(part1(&parse(EX)), 35);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example2() {
|
||||||
|
assert_eq!(part1(&parse(EX_2)), 220);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example() {
|
||||||
|
assert_eq!(part2(&parse(EX)), 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example2() {
|
||||||
|
assert_eq!(part2(&parse(EX_2)), 19208);
|
||||||
|
}
|
||||||
|
}
|
137
src/day12.rs
Normal file
137
src/day12.rs
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
|
||||||
|
use Instruction::*;
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Instruction {
|
||||||
|
MoveNorth(i32),
|
||||||
|
MoveSouth(i32),
|
||||||
|
MoveEast(i32),
|
||||||
|
MoveWest(i32),
|
||||||
|
TurnLeft(i32),
|
||||||
|
TurnRight(i32),
|
||||||
|
MoveForward(i32)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(char, i32)> for Instruction {
|
||||||
|
fn from(value: (char, i32)) -> Self {
|
||||||
|
match value {
|
||||||
|
(i, v) if i == 'N' => MoveNorth(v),
|
||||||
|
(i, v) if i == 'S' => MoveSouth(v),
|
||||||
|
(i, v) if i == 'E' => MoveEast(v),
|
||||||
|
(i, v) if i == 'W' => MoveWest(v),
|
||||||
|
(i, v) if i == 'L' => TurnLeft(v),
|
||||||
|
(i, v) if i == 'R' => TurnRight(v),
|
||||||
|
(i, v) if i == 'F' => MoveForward(v),
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc_generator(day12)]
|
||||||
|
fn parse(input: &str) -> Vec<Instruction> {
|
||||||
|
input
|
||||||
|
.lines()
|
||||||
|
.map(|line| {
|
||||||
|
(line.chars().next().unwrap(), line[1..].parse::<i32>().unwrap()).into()
|
||||||
|
})
|
||||||
|
.collect_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
const DIR_POS_MODIFIER: [(i32, i32); 4] = [(1, 0), (0, -1), (-1, 0), (0, 1)];
|
||||||
|
|
||||||
|
#[aoc(day12, part1)]
|
||||||
|
fn part1(input: &Vec<Instruction>) -> i32 {
|
||||||
|
let mut x = 0;
|
||||||
|
let mut y = 0;
|
||||||
|
let mut direction = 0; // 0 is east, thus 90 is south, 180 is west, and 270 is north
|
||||||
|
|
||||||
|
for instr in input {
|
||||||
|
match instr {
|
||||||
|
MoveNorth(val) => y += val,
|
||||||
|
MoveSouth(val) => y -= val,
|
||||||
|
MoveEast(val) => x += val,
|
||||||
|
MoveWest(val) => x -= val,
|
||||||
|
TurnLeft(val) => {
|
||||||
|
direction -= val;
|
||||||
|
if direction < 0 {
|
||||||
|
direction += 360;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TurnRight(val) => {
|
||||||
|
direction += val;
|
||||||
|
if direction >= 360 {
|
||||||
|
direction -= 360
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MoveForward(val) => {
|
||||||
|
let (xmod, ymod) = DIR_POS_MODIFIER[(direction / 90) as usize];
|
||||||
|
x += xmod * val;
|
||||||
|
y += ymod * val;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
x.abs() + y.abs()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day12, part2)]
|
||||||
|
fn part2(input: &Vec<Instruction>) -> i32 {
|
||||||
|
let mut way_x = 10;
|
||||||
|
let mut way_y = 1;
|
||||||
|
|
||||||
|
let mut ship_x: i32 = 0;
|
||||||
|
let mut ship_y: i32 = 0;
|
||||||
|
|
||||||
|
for instr in input {
|
||||||
|
match instr {
|
||||||
|
MoveNorth(val) => way_y += val,
|
||||||
|
MoveSouth(val) => way_y -= val,
|
||||||
|
MoveEast(val) => way_x += val,
|
||||||
|
MoveWest(val) => way_x -= val,
|
||||||
|
TurnLeft(val) => {
|
||||||
|
for _ in 0..(val / 90) {
|
||||||
|
let tmp = way_y;
|
||||||
|
way_y = way_x;
|
||||||
|
way_x = -tmp;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TurnRight(val) => {
|
||||||
|
for _ in 0..(val / 90) {
|
||||||
|
let tmp = way_y;
|
||||||
|
way_y = -way_x;
|
||||||
|
way_x = tmp;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MoveForward(val) => {
|
||||||
|
ship_x += way_x * val;
|
||||||
|
ship_y += way_y * val;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ship_x.abs() + ship_y.abs()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const EX: &str = r"F10
|
||||||
|
N3
|
||||||
|
F7
|
||||||
|
R90
|
||||||
|
F11";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example() {
|
||||||
|
assert_eq!(part1(&parse(EX)), 25);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example() {
|
||||||
|
assert_eq!(part2(&parse(EX)), 286);
|
||||||
|
}
|
||||||
|
}
|
76
src/day13.rs
Normal file
76
src/day13.rs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
use itertools::Itertools;
|
||||||
|
#[aoc_generator(day13, part1)]
|
||||||
|
fn parse(input: &str) -> (i32, Vec<i32>) {
|
||||||
|
let (start, buses) = input
|
||||||
|
.lines()
|
||||||
|
.collect_tuple()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let buses = buses
|
||||||
|
.split(',')
|
||||||
|
.filter_map(|num| num.parse::<i32>().ok())
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
(start.parse::<i32>().unwrap(), buses)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day13, part1)]
|
||||||
|
fn part1((start, buses): &(i32, Vec<i32>)) -> i32 {
|
||||||
|
let mut cur = 0;
|
||||||
|
loop {
|
||||||
|
if let Some(bus) = buses.iter().find(|x| (cur + start) % *x == 0) {
|
||||||
|
return bus * cur;
|
||||||
|
}
|
||||||
|
cur += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc_generator(day13, part2)]
|
||||||
|
fn parse2(input: &str) -> Vec<Option<i64>> {
|
||||||
|
let buses = input
|
||||||
|
.lines().skip(1).next().unwrap();
|
||||||
|
|
||||||
|
let buses = buses
|
||||||
|
.split(',')
|
||||||
|
.map(|num| num.parse::<i64>().ok())
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
buses
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day13, part2)]
|
||||||
|
fn part2(input: &Vec<Option<i64>>) -> i64 {
|
||||||
|
let mut min_value = 0;
|
||||||
|
let mut running_product = 1;
|
||||||
|
|
||||||
|
for (index, bus) in input.iter().enumerate() {
|
||||||
|
if let Some(bus) = bus {
|
||||||
|
while (min_value + index as i64) % bus != 0 {
|
||||||
|
min_value += running_product;
|
||||||
|
}
|
||||||
|
running_product *= bus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
min_value
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const EX: &str = r"939
|
||||||
|
7,13,x,x,59,x,31,19";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example() {
|
||||||
|
assert_eq!(part1(&parse(EX)), 295);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example() {
|
||||||
|
assert_eq!(part2(&parse2(EX)), 1068781);
|
||||||
|
}
|
||||||
|
}
|
149
src/day14.rs
Normal file
149
src/day14.rs
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
use std::{collections::HashMap, iter::zip};
|
||||||
|
|
||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
use itertools::{Itertools, iproduct};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum ProgramStep {
|
||||||
|
Mask(String),
|
||||||
|
Mem(u64, u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for ProgramStep {
|
||||||
|
fn from(value: &str) -> Self {
|
||||||
|
let (name, value) = value.split(" = ").collect_tuple().unwrap();
|
||||||
|
|
||||||
|
return match name {
|
||||||
|
"mask" => Self::Mask(value.to_string()),
|
||||||
|
name if name.starts_with("mem") => {
|
||||||
|
Self::Mem(name[4..name.len() - 1].parse::<u64>().unwrap(), value.parse::<u64>().unwrap())
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc_generator(day14)]
|
||||||
|
fn parse(input: &str) -> Vec<ProgramStep> {
|
||||||
|
input.lines().map(ProgramStep::from).collect_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_mask(mask: &str, val: u64) -> u64 {
|
||||||
|
let mut val = val;
|
||||||
|
for (i, char) in mask.chars().enumerate() {
|
||||||
|
match char {
|
||||||
|
'X' => continue,
|
||||||
|
'1' => val = val | (2_u64.pow((36 - i - 1).try_into().unwrap())),
|
||||||
|
'0' => val = val & !(2_u64.pow((36 - i - 1).try_into().unwrap())),
|
||||||
|
_ => unreachable!()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
val
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day14, part1)]
|
||||||
|
fn part1(program: &Vec<ProgramStep>) -> u64 {
|
||||||
|
let mut mem: HashMap<u64, u64> = HashMap::new();
|
||||||
|
let mut mask = "";
|
||||||
|
|
||||||
|
for step in program {
|
||||||
|
match step {
|
||||||
|
ProgramStep::Mask(val) => mask = val,
|
||||||
|
ProgramStep::Mem(addr, val) => {
|
||||||
|
let val = apply_mask(mask, *val);
|
||||||
|
mem.insert(*addr, val);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mem.values().sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn permute_masks(mask: &str) -> Vec<String> {
|
||||||
|
let mut masks: Vec<String> = vec![];
|
||||||
|
let bits = mask.chars().enumerate().filter(|(_, v)| *v == 'X').map(|(i, _)| i).collect_vec();
|
||||||
|
let perms = kproduct("21".to_string(), bits.len() as u32);
|
||||||
|
|
||||||
|
let mut new_mask = mask.to_string();
|
||||||
|
for perm in perms {
|
||||||
|
let bit_vals = zip(bits.clone(), perm.chars()).collect::<HashMap<usize, char>>();
|
||||||
|
for (k, val) in bit_vals {
|
||||||
|
new_mask = new_mask[0..k].to_string() + &val.to_string() + &new_mask[k+1..];
|
||||||
|
}
|
||||||
|
masks.push(new_mask.clone());
|
||||||
|
}
|
||||||
|
masks
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kproduct(seq: String, k: u32) -> Vec<String> {
|
||||||
|
match k {
|
||||||
|
0 => vec![],
|
||||||
|
1 => seq.chars().map(|c| c.to_string()).collect(),
|
||||||
|
2 => iproduct!(seq.chars(), seq.chars()).map(|(a, b)| format!("{}{}", a, b)).collect(),
|
||||||
|
_ => iproduct!(kproduct(seq.clone(), k - 1), seq.chars()).map(|(a, b)| format!("{}{}", a, b)).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_addrs(addr: u64, mask: &str) -> Vec<u64> {
|
||||||
|
let mut addrs = vec![];
|
||||||
|
let masks = permute_masks(mask);
|
||||||
|
for mask in masks {
|
||||||
|
let mut addr = addr;
|
||||||
|
for (i, char) in mask.chars().enumerate() {
|
||||||
|
match char {
|
||||||
|
'1' => addr = addr | (2_u64.pow((36 - i - 1).try_into().unwrap())),
|
||||||
|
'2' => addr = addr & !(2_u64.pow((36 - i - 1).try_into().unwrap())),
|
||||||
|
'0' => continue,
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addrs.push(addr)
|
||||||
|
}
|
||||||
|
addrs
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day14, part2)]
|
||||||
|
fn part2(program: &Vec<ProgramStep>) -> u64 {
|
||||||
|
let mut mem: HashMap<u64, u64> = HashMap::new();
|
||||||
|
let mut mask = "";
|
||||||
|
|
||||||
|
for step in program {
|
||||||
|
match step {
|
||||||
|
ProgramStep::Mask(val) => mask = val,
|
||||||
|
ProgramStep::Mem(addr, val) => {
|
||||||
|
let addrs = get_addrs(*addr, mask);
|
||||||
|
for addr in addrs {
|
||||||
|
mem.insert(addr, *val);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mem.values().sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const EX: &str = r"mask = XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X
|
||||||
|
mem[8] = 11
|
||||||
|
mem[7] = 101
|
||||||
|
mem[8] = 0";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example() {
|
||||||
|
assert_eq!(part1(&parse(EX)), 165);
|
||||||
|
}
|
||||||
|
|
||||||
|
const EX_2: &str = r"mask = 000000000000000000000000000000X1001X
|
||||||
|
mem[42] = 100
|
||||||
|
mask = 00000000000000000000000000000000X0XX
|
||||||
|
mem[26] = 1";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example() {
|
||||||
|
assert_eq!(part2(&parse(EX_2)), 208);
|
||||||
|
}
|
||||||
|
}
|
60
src/day15.rs
Normal file
60
src/day15.rs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
|
||||||
|
#[aoc_generator(day15)]
|
||||||
|
fn parse(input: &str) -> Vec<u64> {
|
||||||
|
input.split(',').map(str::parse::<u64>).map(Result::unwrap).collect_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day15, part1)]
|
||||||
|
fn part1(input: &Vec<u64>) -> u64 {
|
||||||
|
let mut list = input.iter().take(input.len() - 1).cloned().enumerate().map(|(i,v)| (v,i)).collect::<HashMap<_, _>>();
|
||||||
|
let mut cur = *input.last().unwrap();
|
||||||
|
|
||||||
|
for turn in input.len() - 1..2020 - 1 {
|
||||||
|
let mut next = 0;
|
||||||
|
if let Some(last_turn) = list.get_mut(&cur) {
|
||||||
|
next = (turn - *last_turn) as u64;
|
||||||
|
}
|
||||||
|
list.insert(cur, turn);
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
cur
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day15, part2)]
|
||||||
|
fn part2(input: &Vec<u64>) -> u64 {
|
||||||
|
let mut list = input.iter().take(input.len() - 1).cloned().enumerate().map(|(i,v)| (v,i)).collect::<HashMap<_, _>>();
|
||||||
|
let mut cur = *input.last().unwrap();
|
||||||
|
|
||||||
|
for turn in input.len() - 1..30000000 - 1 {
|
||||||
|
let mut next = 0;
|
||||||
|
if let Some(last_turn) = list.get_mut(&cur) {
|
||||||
|
next = (turn - *last_turn) as u64;
|
||||||
|
}
|
||||||
|
list.insert(cur, turn);
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
cur
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const EX: &str = r"0,3,6";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example() {
|
||||||
|
assert_eq!(part1(&parse(EX)), 436);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example() {
|
||||||
|
assert_eq!(part2(&parse(EX)), 175594);
|
||||||
|
}
|
||||||
|
}
|
145
src/day16.rs
Normal file
145
src/day16.rs
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
use std::{ops::RangeInclusive, collections::HashSet};
|
||||||
|
|
||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
use itertools::Itertools;
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
lazy_static!(
|
||||||
|
static ref RULE_RE: Regex = Regex::new(r"(.*): (\d+)-(\d+) or (\d+)-(\d+)").unwrap();
|
||||||
|
);
|
||||||
|
|
||||||
|
#[aoc_generator(day16)]
|
||||||
|
fn parse(input: &str) -> (Vec<(String, RangeInclusive<usize>, RangeInclusive<usize>)>, Vec<usize>, Vec<Vec<usize>>) {
|
||||||
|
let (rules, my_ticket, tickets) = input
|
||||||
|
.split("\n\n")
|
||||||
|
.collect_tuple()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let rules = RULE_RE
|
||||||
|
.captures_iter(rules)
|
||||||
|
.filter_map(|captures| {
|
||||||
|
Some((
|
||||||
|
captures.get(1)?.as_str().to_string(),
|
||||||
|
captures.get(2)?.as_str().parse::<usize>().ok()?..=captures.get(3)?.as_str().parse::<usize>().ok()?,
|
||||||
|
captures.get(4)?.as_str().parse::<usize>().ok()?..=captures.get(5)?.as_str().parse::<usize>().ok()?,
|
||||||
|
))
|
||||||
|
}).collect_vec();
|
||||||
|
|
||||||
|
let my_ticket = my_ticket
|
||||||
|
.lines()
|
||||||
|
.last()
|
||||||
|
.unwrap()
|
||||||
|
.split(',')
|
||||||
|
.filter_map(|num| num.parse::<usize>().ok())
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
let tickets = tickets
|
||||||
|
.lines()
|
||||||
|
.skip(1)
|
||||||
|
.map(|line| {
|
||||||
|
line
|
||||||
|
.split(',')
|
||||||
|
.filter_map(|num| num.parse::<usize>().ok())
|
||||||
|
.collect_vec()
|
||||||
|
}).collect_vec();
|
||||||
|
|
||||||
|
(rules, my_ticket, tickets)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day16, part1)]
|
||||||
|
fn part1((rules, _, tickets): &(Vec<(String, RangeInclusive<usize>, RangeInclusive<usize>)>, Vec<usize>, Vec<Vec<usize>>)) -> usize {
|
||||||
|
let mut invalid = 0;
|
||||||
|
for ticket in tickets {
|
||||||
|
for item in ticket {
|
||||||
|
if !rules.iter().any(|rule| {
|
||||||
|
rule.1.contains(item) || rule.2.contains(item)
|
||||||
|
}) {
|
||||||
|
invalid += item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
invalid
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day16, part2)]
|
||||||
|
fn part2((rules, my_ticket, tickets): &(Vec<(String, RangeInclusive<usize>, RangeInclusive<usize>)>, Vec<usize>, Vec<Vec<usize>>)) -> usize {
|
||||||
|
let mut tickets = tickets.clone();
|
||||||
|
let mut rem = 0;
|
||||||
|
for (i, ticket) in tickets.clone().iter().enumerate() {
|
||||||
|
for item in ticket {
|
||||||
|
if !rules.iter().any(|rule| {
|
||||||
|
rule.1.contains(item) || rule.2.contains(item)
|
||||||
|
}) {
|
||||||
|
tickets.remove(i - rem);
|
||||||
|
rem += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut possible_rules = get_possible_rules(&tickets, rules);
|
||||||
|
let mut assigned_rules = [0; 20];
|
||||||
|
while let Some(i) = possible_rules.iter().position(|s| s.len() == 1) {
|
||||||
|
let v = *possible_rules[i].iter().next().unwrap();
|
||||||
|
assigned_rules[i] = v;
|
||||||
|
for s in &mut possible_rules { s.remove(&v); }
|
||||||
|
}
|
||||||
|
assigned_rules.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_,&rule)| rule < 6)
|
||||||
|
.map(|(i,_)| my_ticket[i])
|
||||||
|
.product()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_possible_rules(tickets: &Vec<Vec<usize>>, rules: &Vec<(String, RangeInclusive<usize>, RangeInclusive<usize>)>) -> Vec<HashSet<usize>> {
|
||||||
|
(0..20).map(|i|
|
||||||
|
(0..20).filter(|&j|
|
||||||
|
tickets.iter().all(|t| fits_rule(&rules[j], t[i]))
|
||||||
|
).collect()
|
||||||
|
).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fits_rule((_, r1,r2): &(String, RangeInclusive<usize>, RangeInclusive<usize>), v: usize) -> bool {
|
||||||
|
r1.contains(&v) || r2.contains(&v)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const EX: &str = r"class: 1-3 or 5-7
|
||||||
|
row: 6-11 or 33-44
|
||||||
|
seat: 13-40 or 45-50
|
||||||
|
|
||||||
|
your ticket:
|
||||||
|
7,1,14
|
||||||
|
|
||||||
|
nearby tickets:
|
||||||
|
7,3,47
|
||||||
|
40,4,50
|
||||||
|
55,2,20
|
||||||
|
38,6,12";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example() {
|
||||||
|
assert_eq!(part1(&parse(EX)), 71);
|
||||||
|
}
|
||||||
|
|
||||||
|
const EX2: &str = r"class: 0-1 or 4-19
|
||||||
|
row: 0-5 or 8-19
|
||||||
|
seat: 0-13 or 16-19
|
||||||
|
|
||||||
|
your ticket:
|
||||||
|
11,12,13
|
||||||
|
|
||||||
|
nearby tickets:
|
||||||
|
3,9,18
|
||||||
|
15,1,5
|
||||||
|
5,14,9";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example() {
|
||||||
|
assert_eq!(part2(&parse(EX2)), 1716);
|
||||||
|
}
|
||||||
|
}
|
119
src/day7.rs
Normal file
119
src/day7.rs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
|
||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
const GOAL: &str = "shiny gold";
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref LINE_RE: Regex = Regex::new(r"(\w+ \w+) bags contain (.*)").unwrap();
|
||||||
|
static ref ITEM_RE: Regex = Regex::new(r"(\d+) (\w+ \w+) bags?").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc_generator(day7)]
|
||||||
|
fn parse(input: &str) -> HashMap<String, Vec<(usize, String)>> {
|
||||||
|
let mut bags = HashMap::<String, Vec<(usize, String)>>::new();
|
||||||
|
for line in input.lines() {
|
||||||
|
if let Some((item, items)) = LINE_RE
|
||||||
|
.captures(line.as_ref())
|
||||||
|
.and_then(|captures| {
|
||||||
|
Some((captures.get(1)?.as_str(), captures.get(2)?.as_str()))
|
||||||
|
}) {
|
||||||
|
bags.insert(
|
||||||
|
item.to_string(),
|
||||||
|
ITEM_RE
|
||||||
|
.captures_iter(items)
|
||||||
|
.filter_map(|captures| {
|
||||||
|
Some((
|
||||||
|
captures.get(1)?.as_str().parse().ok()?,
|
||||||
|
captures.get(2)?.as_str().to_string(),
|
||||||
|
))
|
||||||
|
}).collect()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
bags
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Expand<'a> {
|
||||||
|
bags: &'a HashMap<String, Vec<(usize, String)>>,
|
||||||
|
queue: VecDeque<(usize, &'a str)>
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expand<'a>(bags: &'a HashMap<String, Vec<(usize, String)>>, bag: &str) -> Expand<'a> {
|
||||||
|
Expand {
|
||||||
|
bags,
|
||||||
|
queue: bags.get(bag).map_or_else(VecDeque::new, |items| {
|
||||||
|
items.iter()
|
||||||
|
.map(|(count, item)| (*count, item.as_str()))
|
||||||
|
.collect()
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for Expand<'a> {
|
||||||
|
type Item = (usize, &'a str);
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.queue.pop_front().map(|(count, item)| {
|
||||||
|
if let Some(items) = self.bags.get(item) {
|
||||||
|
for (subcount, subitem) in items {
|
||||||
|
self.queue.push_back((count * subcount, subitem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(count, item)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day7, part1)]
|
||||||
|
fn part1(bags: &HashMap<String, Vec<(usize, String)>>) -> usize {
|
||||||
|
bags.keys()
|
||||||
|
.filter(|key| expand(&bags, key).any(|(_, item)| item == GOAL))
|
||||||
|
.count()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day7, part2)]
|
||||||
|
fn part2(bags: &HashMap<String, Vec<(usize, String)>>) -> usize {
|
||||||
|
expand(bags, GOAL).map(|(count, _)| count).sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const EX: &str = r"light red bags contain 1 bright white bag, 2 muted yellow bags.
|
||||||
|
dark orange bags contain 3 bright white bags, 4 muted yellow bags.
|
||||||
|
bright white bags contain 1 shiny gold bag.
|
||||||
|
muted yellow bags contain 2 shiny gold bags, 9 faded blue bags.
|
||||||
|
shiny gold bags contain 1 dark olive bag, 2 vibrant plum bags.
|
||||||
|
dark olive bags contain 3 faded blue bags, 4 dotted black bags.
|
||||||
|
vibrant plum bags contain 5 faded blue bags, 6 dotted black bags.
|
||||||
|
faded blue bags contain no other bags.
|
||||||
|
dotted black bags contain no other bags.";
|
||||||
|
|
||||||
|
const EX_2: &str = r"shiny gold bags contain 2 dark red bags.
|
||||||
|
dark red bags contain 2 dark orange bags.
|
||||||
|
dark orange bags contain 2 dark yellow bags.
|
||||||
|
dark yellow bags contain 2 dark green bags.
|
||||||
|
dark green bags contain 2 dark blue bags.
|
||||||
|
dark blue bags contain 2 dark violet bags.
|
||||||
|
dark violet bags contain no other bags.";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example() {
|
||||||
|
assert_eq!(part1(&parse(EX)), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example() {
|
||||||
|
assert_eq!(part2(&parse(EX)), 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example2() {
|
||||||
|
assert_eq!(part2(&parse(EX_2)), 126);
|
||||||
|
}
|
||||||
|
}
|
180
src/day8.rs
Normal file
180
src/day8.rs
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
use itertools::Itertools;
|
||||||
|
#[aoc_generator(day8)]
|
||||||
|
fn parse(input: &str) -> Box<[Instruction]> {
|
||||||
|
let input: Vec<Instruction> = input.lines()
|
||||||
|
.map(|line| {
|
||||||
|
let (instruction, arg) = line.split(' ').collect_tuple().unwrap();
|
||||||
|
(instruction, arg.parse::<i32>().unwrap()).into()
|
||||||
|
}).collect_vec();
|
||||||
|
input.try_into().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
use Instruction::*;
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum Instruction {
|
||||||
|
ACC(i32),
|
||||||
|
JMP(i32),
|
||||||
|
NOP(i32)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(&str, i32)> for Instruction {
|
||||||
|
fn from(value: (&str, i32)) -> Self {
|
||||||
|
match value {
|
||||||
|
(i, v) if i == "acc" => ACC(v),
|
||||||
|
(i, v) if i == "jmp" => JMP(v),
|
||||||
|
(i, v) if i == "nop" => NOP(v),
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day8, part1)]
|
||||||
|
fn part1(input: &[Instruction]) -> i32 {
|
||||||
|
let mut visited: Vec<bool> = vec![false; input.len()];
|
||||||
|
let mut next = 0;
|
||||||
|
let mut acc = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let inst = &input[next];
|
||||||
|
if visited[next] {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
visited[next] = true;
|
||||||
|
|
||||||
|
match inst {
|
||||||
|
ACC(arg) => acc += arg,
|
||||||
|
JMP(arg) => {next = (next as i32 + *arg) as usize; continue;},
|
||||||
|
NOP(_) => {},
|
||||||
|
}
|
||||||
|
next += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day8, part2)]
|
||||||
|
fn part2(input: &[Instruction]) -> i32 {
|
||||||
|
let mut visited: Vec<bool> = vec![false; input.len()];
|
||||||
|
let mut next = 0;
|
||||||
|
let mut acc = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let inst = &input[next];
|
||||||
|
if visited[next] {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
visited[next] = true;
|
||||||
|
|
||||||
|
match inst {
|
||||||
|
ACC(arg) => acc += arg,
|
||||||
|
JMP(arg) => {next = (next as i32 + *arg) as usize; continue;},
|
||||||
|
NOP(_) => {},
|
||||||
|
}
|
||||||
|
next += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut landing_spots = vec![false; input.len() + 1];
|
||||||
|
let mut i = input.len();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
landing_spots[i] = true;
|
||||||
|
i -= 1;
|
||||||
|
|
||||||
|
if let JMP(x) = input[i] {
|
||||||
|
if x < 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let start = i;
|
||||||
|
let swap = if visited[i] {
|
||||||
|
i
|
||||||
|
} else {
|
||||||
|
loop {
|
||||||
|
i -= 1;
|
||||||
|
|
||||||
|
if landing_spots[i] {
|
||||||
|
continue;
|
||||||
|
} else if let NOP(x) = input[i] {
|
||||||
|
if visited[i] && landing_spots[((i as i32) + x) as usize] {
|
||||||
|
break i;
|
||||||
|
}
|
||||||
|
} else if let JMP(x) = input[i] {
|
||||||
|
if !visited[i]
|
||||||
|
&& landing_spots[((i as i32) + x) as usize]
|
||||||
|
&& !landing_spots[i]
|
||||||
|
{
|
||||||
|
let mut j = i - 1;
|
||||||
|
loop {
|
||||||
|
if matches!(input[j], JMP(_)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
j -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if visited[j] {
|
||||||
|
break j;
|
||||||
|
} else {
|
||||||
|
landing_spots[j + 1..=i].iter_mut().for_each(|a| {
|
||||||
|
*a = true;
|
||||||
|
});
|
||||||
|
i = start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut program = input.to_vec();
|
||||||
|
program[swap] = match program[swap] {
|
||||||
|
ACC(_) => unreachable!(),
|
||||||
|
JMP(x) => NOP(x),
|
||||||
|
NOP(x) => JMP(x),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut next = 0;
|
||||||
|
let mut acc = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if next >= program.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let inst = &program[next];
|
||||||
|
|
||||||
|
match inst {
|
||||||
|
ACC(arg) => acc += arg,
|
||||||
|
JMP(arg) => {next = (next as i32 + *arg) as usize; continue;},
|
||||||
|
NOP(_) => {},
|
||||||
|
}
|
||||||
|
next += 1;
|
||||||
|
}
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const EX: &str = r"nop +0
|
||||||
|
acc +1
|
||||||
|
jmp +4
|
||||||
|
acc +3
|
||||||
|
jmp -3
|
||||||
|
acc -99
|
||||||
|
acc +1
|
||||||
|
jmp -4
|
||||||
|
acc +6";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example() {
|
||||||
|
assert_eq!(part1(&parse(EX)), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example() {
|
||||||
|
assert_eq!(part2(&parse(EX)), 8);
|
||||||
|
}
|
||||||
|
}
|
73
src/day9.rs
Normal file
73
src/day9.rs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
const PREAMBLE_LEN: usize = 5;
|
||||||
|
|
||||||
|
#[aoc_generator(day9)]
|
||||||
|
fn parse(input: &str) -> Vec<u64> {
|
||||||
|
input.lines().map(str::parse).map(Result::unwrap).collect_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day9, part1)]
|
||||||
|
fn part1(input: &Vec<u64>) -> u64 {
|
||||||
|
for i in PREAMBLE_LEN..input.len() {
|
||||||
|
if let None = input[i - PREAMBLE_LEN..i]
|
||||||
|
.iter()
|
||||||
|
.combinations(2)
|
||||||
|
.find(|x| x.iter().cloned().sum::<u64>() == input[i]) {
|
||||||
|
return input[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day9, part2)]
|
||||||
|
fn part2(input: &Vec<u64>) -> u64 {
|
||||||
|
let to_find = part1(input);
|
||||||
|
|
||||||
|
for len in 2..input.len() {
|
||||||
|
if let Some(nums) = input
|
||||||
|
.windows(len)
|
||||||
|
.find(|x| x.iter().cloned().sum::<u64>() == to_find) {
|
||||||
|
return nums.iter().min().unwrap() + nums.iter().max().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const EX: &str = r"35
|
||||||
|
20
|
||||||
|
15
|
||||||
|
25
|
||||||
|
47
|
||||||
|
40
|
||||||
|
62
|
||||||
|
55
|
||||||
|
65
|
||||||
|
95
|
||||||
|
102
|
||||||
|
117
|
||||||
|
150
|
||||||
|
182
|
||||||
|
127
|
||||||
|
219
|
||||||
|
299
|
||||||
|
277
|
||||||
|
309
|
||||||
|
576";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example() {
|
||||||
|
assert_eq!(part1(&parse(EX)), 127);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example() {
|
||||||
|
assert_eq!(part2(&parse(EX)), 62);
|
||||||
|
}
|
||||||
|
}
|
11
src/lib.rs
11
src/lib.rs
@@ -1,3 +1,12 @@
|
|||||||
|
mod day16;
|
||||||
|
mod day15;
|
||||||
|
mod day14;
|
||||||
|
mod day13;
|
||||||
|
mod day12;
|
||||||
|
mod day10;
|
||||||
|
mod day9;
|
||||||
|
mod day8;
|
||||||
|
mod day7;
|
||||||
mod day6;
|
mod day6;
|
||||||
mod day5;
|
mod day5;
|
||||||
mod day1;
|
mod day1;
|
||||||
@@ -8,5 +17,7 @@ extern crate aoc_runner;
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate aoc_runner_derive;
|
extern crate aoc_runner_derive;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
|
||||||
aoc_lib!{ year = 2020 }
|
aoc_lib!{ year = 2020 }
|
Reference in New Issue
Block a user