diff --git a/day-13/Cargo.lock b/day-13/Cargo.lock new file mode 100644 index 0000000..d0515ae --- /dev/null +++ b/day-13/Cargo.lock @@ -0,0 +1,78 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "day-13" +version = "0.1.0" +dependencies = [ + "indoc", +] + +[[package]] +name = "indoc" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47741a8bc60fb26eb8d6e0238bbb26d8575ff623fdc97b1a2c00c050b9684ed8" +dependencies = [ + "indoc-impl", + "proc-macro-hack", +] + +[[package]] +name = "indoc-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", + "unindent", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "unindent" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7" diff --git a/day-13/Cargo.toml b/day-13/Cargo.toml new file mode 100644 index 0000000..a4e1f5b --- /dev/null +++ b/day-13/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "day-13" +version = "0.1.0" +authors = ["Tristan Daniƫl Maat "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +indoc = "0.3" diff --git a/day-13/input b/day-13/input new file mode 100644 index 0000000..e614056 --- /dev/null +++ b/day-13/input @@ -0,0 +1,2 @@ +1000391 +19,x,x,x,x,x,x,x,x,x,x,x,x,37,x,x,x,x,x,383,x,x,x,x,x,x,x,23,x,x,x,x,13,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,29,x,457,x,x,x,x,x,x,x,x,x,41,x,x,x,x,x,x,17 diff --git a/day-13/src/main.rs b/day-13/src/main.rs new file mode 100644 index 0000000..be4bd15 --- /dev/null +++ b/day-13/src/main.rs @@ -0,0 +1,172 @@ +use std::fs; + +fn main() -> Result<(), Box> { + let input = fs::read_to_string("input")?; + let (time, ids) = parse_notes(&input)?; + + // Part 1 + let (earliest, arrival) = find_closest_bus(time, &ids); + println!("{}", (arrival - time) * earliest); + + // Part 2 + let timestamp = find_gauss(&ids); + println!("{}", timestamp); + + Ok(()) +} + +fn parse_notes(input: &str) -> Result<(u32, Vec), &str> { + let mut lines = input.lines(); + + let estimate = lines + .next() + .ok_or("Input too short")? + .parse() + .map_err(|_| "Estimate is not a number")?; + + let ids = lines + .next() + .ok_or("Input too short")? + .split(',') + .map(|id| id.parse().unwrap_or(1)) + .collect(); + + Ok((estimate, ids)) +} + +fn find_closest_bus(time: u32, ids: &Vec) -> (u32, u32) { + ids.iter() + .filter(|id| **id != 1) + .map(|id| { + let mut arrival = *id; + + while arrival < time { + arrival += id + } + + (*id, arrival) + }) + .min_by_key(|id| id.1) + .expect("Must have at least one bus ID") +} + +fn find_gauss(ids: &Vec) -> u128 { + let ids: Vec = ids.iter().map(|id| *id as u128).collect(); + let product: u128 = ids.iter().product(); + + let gauss = |mut n: u128, mut d: u128, m: u128| -> u128 { + while d != 1 { + if m == 1 { + return 0; + }; + + let multiplier = if m > d { + m / d + (m % d != 0) as u128 + } else { + 1 + }; + + n = (n * multiplier) % m; + d = (d * multiplier) % m; + } + + n / d + }; + + (0..ids.len()) + .map(|a| { + let b = product / ids[a]; + let bi = gauss(1, b, ids[a]); + let a = (ids[a] * a as u128 - a as u128) % ids[a] as u128; + + a * b * bi + }) + .sum::() + % product +} + +#[cfg(test)] +mod tests { + use super::*; + use indoc::indoc; + + #[test] + fn test_simple() -> Result<(), Box> { + let input = indoc!( + "939 + 7,13,x,x,59,x,31,19 + " + ); + + let (time, ids) = parse_notes(input)?; + let (earliest, arrival) = find_closest_bus(time, &ids); + + assert_eq!(arrival, 944); + + Ok(()) + } + + #[test] + fn test_simple2() -> Result<(), Box> { + let input = indoc!( + "939 + 17,x,13,19 + " + ); + + let (time, ids) = parse_notes(input)?; + let timestamp = find_gauss(&ids); + + assert_eq!(timestamp, 3417); + + Ok(()) + } + + #[test] + fn test_simple3() -> Result<(), Box> { + let input = indoc!( + "939 + 7,13,x,x,59,x,31,19 + " + ); + + let (time, ids) = parse_notes(input)?; + let timestamp = find_gauss(&ids); + + assert_eq!(timestamp, 1068781); + + Ok(()) + } + + #[test] + fn test_simple4() -> Result<(), Box> { + let input = indoc!( + "939 + 67,7,59,61 + " + ); + + let (time, ids) = parse_notes(input)?; + let timestamp = find_gauss(&ids); + + assert_eq!(timestamp, 754018); + + Ok(()) + } + + #[test] + fn test_simple5() -> Result<(), Box> { + let input = indoc!( + "939 + 67,x,7,59,61 + " + ); + + let (time, ids) = parse_notes(input)?; + let timestamp = find_gauss(&ids); + + assert_eq!(timestamp, 779210); + + Ok(()) + } +}