1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
use crate::Input; struct Disc { positions: u32, initial_position: u32, } pub fn solve(input: &mut Input) -> Result<u32, String> { const MAX_TIME: u32 = 10_000_000; let mut discs = input .text .lines() .map(|line| { let error_mapper = |_| "Invalid number".to_string(); let words = line.split(' ').collect::<Vec<_>>(); if words.len() != 12 { return Err("Invalid input - line not containing 19 words".to_string()); } let positions = words[3].parse::<u32>().map_err(error_mapper)?; let initial_position = words[11][..words[11].len() - 1] .parse::<u32>() .map_err(error_mapper)?; Ok(Disc { positions, initial_position, }) }) .collect::<Result<Vec<Disc>, String>>()?; if input.is_part_two() { discs.push(Disc { positions: 11, initial_position: 0, }); } (0..=MAX_TIME) .find(|&time| { discs.iter().enumerate().all(|(disc_idx, disc)| { let fall_time = (disc_idx + 1) as u32; let current_position = (disc.initial_position + time + fall_time) % disc.positions; current_position == 0 }) }) .ok_or_else(|| format!("No solution within {} seconds found", MAX_TIME)) } #[test] pub fn tests() { use crate::{test_part_one, test_part_two}; test_part_one!("Disc #1 has 5 positions; at time=0, it is at position 4. Disc #2 has 2 positions; at time=0, it is at position 1." => 5); let real_input = include_str!("day15_input.txt"); test_part_one!(real_input => 203_660); test_part_two!(real_input => 2_408_135); }