diff --git a/Cargo.lock b/Cargo.lock index 036bd67..6f688e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,6 +24,10 @@ version = "0.1.0" name = "day_16" version = "0.1.0" +[[package]] +name = "day_17" +version = "0.1.0" + [[package]] name = "day_18" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 0b74949..7998132 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ members = [ "day_13", "day_15", "day_16", + "day_17", "day_18", "day_19", "day_23", diff --git a/day_17/Cargo.toml b/day_17/Cargo.toml new file mode 100644 index 0000000..7b95bed --- /dev/null +++ b/day_17/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "day_17" +version = "0.1.0" +authors = ["Smaug123 "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/day_17/input.txt b/day_17/input.txt new file mode 100644 index 0000000..873b744 --- /dev/null +++ b/day_17/input.txt @@ -0,0 +1 @@ +304 diff --git a/day_17/src/main.rs b/day_17/src/main.rs new file mode 100644 index 0000000..d265f0e --- /dev/null +++ b/day_17/src/main.rs @@ -0,0 +1,105 @@ +fn input() -> usize { + let input = include_str!("../input.txt"); + input.trim().parse().unwrap() +} + +struct CircularBuffer { + elts: Vec, + current_size: usize, +} + +fn new_buffer(size: usize) -> CircularBuffer +where + T: Default + Clone, +{ + CircularBuffer { + elts: vec![Default::default(); size], + current_size: 0, + } +} + +fn walk(current_pos: usize, i: usize, buf: &CircularBuffer) -> usize { + (i + current_pos) % buf.current_size +} + +fn element_at(pos: usize, buf: &CircularBuffer) -> &T { + &buf.elts[pos % buf.current_size] +} + +fn insert_after(pos: usize, i: T, buf: &mut CircularBuffer) +where + T: Copy, +{ + for j in (pos + 2..=buf.current_size).rev() { + buf.elts[j] = buf.elts[j - 1]; + } + buf.elts[pos + 1] = i; + buf.current_size += 1; +} + +// Returns the position of the write head, and the buffer. +fn proceed(step_size: usize, count: usize) -> (usize, CircularBuffer) { + let mut buffer = new_buffer::(count + 1); + insert_after(0, 0, &mut buffer); + let mut pos = 0; + for i in 1..=count { + // + 1 because we need to pick up the inserted element too + pos = walk(pos + 1, step_size, &buffer); + insert_after(pos, i as u32, &mut buffer); + } + (pos + 1, buffer) +} + +fn part_1(step_size: usize) -> u32 { + let (head, buffer) = proceed(step_size, 2017); + *element_at(head + 1, &buffer) +} + +fn part_2(step_size: usize, bound: usize) -> u32 { + let mut after_zero = 1u32; + let mut current_head: usize = 1; + for i in 2usize..=bound { + let insert_after = (current_head + step_size) % i; + if insert_after == 0 { + after_zero = i as u32; + } + current_head = (insert_after + 1) % (i + 1); + } + + after_zero +} + +fn main() { + let input = input(); + println!("part 1 => {}", part_1(input)); + println!("part 2 => {}", part_2(input, 50000000)); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn part1_known() { + assert_eq!(part_1(3), 638); + } + + #[test] + fn part2_known() { + assert_eq!(part_2(3, 2), 2); + assert_eq!(part_2(3, 3), 2); + assert_eq!(part_2(3, 4), 2); + assert_eq!(part_2(3, 5), 5); + assert_eq!(part_2(3, 6), 5); + assert_eq!(part_2(3, 7), 5); + assert_eq!(part_2(3, 8), 5); + assert_eq!(part_2(3, 9), 9); + } + + #[test] + fn test_day_17() { + let input = input(); + assert_eq!(part_1(input), 1173); + assert_eq!(part_2(input, 50000000), 1930815); + } +}