pub mod day1 { fn day1_preprocess(input: &str) -> Vec { input .lines() .map(|line| { ( line.starts_with('L'), line.chars() .skip(1) .collect::() .parse::() .unwrap(), ) }) .map(|(is_left, distance)| if is_left { -distance } else { distance }) .collect() } pub fn day1_part1(input: &str) -> String { let rotations = day1_preprocess(input); let mut popcnt = 0; let mut pointing_at = 50; for rotation in rotations { pointing_at += rotation; pointing_at %= 100; if pointing_at == 0 { popcnt += 1; } } popcnt.to_string() } pub fn day1_part2(input: &str) -> String { let rotations = day1_preprocess(input); let mut popcnt = 0; let mut pointing_at = 50; for mut rotation in rotations { while rotation != 0 { if rotation < 0 { let distance = rotation.max(-(if pointing_at != 0 { pointing_at } else { 100 })); pointing_at += distance; rotation -= distance; } else if rotation > 0 { let distance = rotation.min(100 - pointing_at); pointing_at += distance; rotation -= distance; } pointing_at %= 100; if pointing_at < 0 { pointing_at += 100; } else if pointing_at == 0 { popcnt += 1; } } } popcnt.to_string() } } pub mod day2 { use std::ops::RangeInclusive; pub fn day2_part1(input: &str) -> String { let ranges = parse(input); let invalid = ranges .into_iter() .flatten() .filter(|&id| !is_id_valid(id, true)); let invalid_sum: u64 = invalid.sum(); invalid_sum.to_string() } pub fn day2_part2(input: &str) -> String { let ranges = parse(input); let invalid = ranges .into_iter() .flatten() .filter(|&id| !is_id_valid(id, false)); let invalid_sum: u64 = invalid.sum(); invalid_sum.to_string() } fn parse(input: &str) -> Vec> { input .split(',') .map(|range| range.split_once('-').unwrap()) .map(|(from, to)| from.parse().unwrap()..=to.parse().unwrap()) .collect() } fn is_id_valid(id: u64, max_two_chunks: bool) -> bool { let charnum = id.ilog10() as usize + 1; for chunk_count in 2..=if max_two_chunks { 2 } else { charnum } { if !charnum.is_multiple_of(chunk_count) { continue; } let chunk_size = charnum / chunk_count; let mut equal = true; 'chunking: for intra_chunk_index in 0..chunk_size { let first_digit = index(id, intra_chunk_index); for inter_chunk_index in 1..chunk_count { let digit_under_test = index(id, inter_chunk_index * chunk_size + intra_chunk_index); if digit_under_test != first_digit { equal = false; break 'chunking; } } } if equal { return false; } } true } #[inline] fn index(id: u64, index: usize) -> u64 { (id / 10u64.pow(index as u32)) % 10 } } pub mod day3; pub mod day4; pub mod day5; pub mod day6; pub mod day7; pub mod day8; pub mod day9; mod spatial; mod union_find; #[cfg(test)] mod tests { use super::*; #[test] fn day9_part1_test() { let test_result = day9::day9_part1(include_str!("../input/day9.test.txt")); assert_eq!(test_result, "50"); let result = day9::day9_part1(include_str!("../input/day9.txt")); assert_eq!(result, "4760959496"); } #[test] fn day9_part2_test() { let test_result = day9::day9_part2(include_str!("../input/day9.test.txt")); assert_eq!(test_result, "24"); let result = day9::day9_part2(include_str!("../input/day9.txt")); assert_eq!(result, "1343576598"); } #[test] fn day8_part1_test() { let test_result = day8::day8_part1(include_str!("../input/day8.test.txt"), 10); assert_eq!(test_result, "40"); let result = day8::day8_part1(include_str!("../input/day8.txt"), 1000); assert_eq!(result, "90036"); } #[test] fn day8_part2_test() { let test_result = day8::day8_part2(include_str!("../input/day8.test.txt"), 1_000_000); assert_eq!(test_result, "25272"); let result = day8::day8_part2(include_str!("../input/day8.txt"), 1_000_000); assert_eq!(result, "6083499488"); } #[test] fn day7_part1_test() { let test_result = day7::day7_part1(include_str!("../input/day7.test.txt")); assert_eq!(test_result, "21"); let result = day7::day7_part1(include_str!("../input/day7.txt")); assert_eq!(result, "1490"); } #[test] fn day7_part2_test() { let test_result = day7::day7_part2(include_str!("../input/day7.test.txt")); assert_eq!(test_result, "40"); let result = day7::day7_part2(include_str!("../input/day7.txt")); assert_eq!(result, "3806264447357"); } #[test] fn day6_part1_test() { let test_result = day6::day6_part1(include_str!("../input/day6.test.txt")); assert_eq!(test_result, "4277556"); let result = day6::day6_part1(include_str!("../input/day6.txt")); assert_eq!(result, "4951502530386"); } #[test] fn day6_part2_test() { let test_result = day6::day6_part2(include_str!("../input/day6.test.txt")); assert_eq!(test_result, "3263827"); let result = day6::day6_part2(include_str!("../input/day6.txt")); assert_eq!(result, "8486156119946"); } #[test] fn day5_part1_test() { let test_result = day5::day5_part1(include_str!("../input/day5.test.txt")); assert_eq!(test_result, "3"); let result = day5::day5_part1(include_str!("../input/day5.txt")); assert_eq!(result, "885"); } #[test] fn day5_part2_test() { let test_result = day5::day5_part2(include_str!("../input/day5.test.txt")); assert_eq!(test_result, "14"); let result = day5::day5_part2(include_str!("../input/day5.txt")); assert_eq!(result, "348115621205535"); } #[test] fn day4_part1_test() { let test_result = day4::day4_part1(include_str!("../input/day4.test.txt")); assert_eq!(test_result, "13"); let result = day4::day4_part1(include_str!("../input/day4.txt")); assert_eq!(result, "1372"); } #[test] fn day4_part2_test() { let test_result = day4::day4_part2(include_str!("../input/day4.test.txt")); assert_eq!(test_result, "43"); let result = day4::day4_part2(include_str!("../input/day4.txt")); assert_eq!(result, "7922"); } #[test] fn day3_part1_test() { let test_result = day3::day3_part1(include_str!("../input/day3.test.txt")); assert_eq!(test_result, "357"); let result = day3::day3_part1(include_str!("../input/day3.txt")); assert_eq!(result, "17613"); } #[test] fn day3_part2_test() { let test_result = day3::day3_part2(include_str!("../input/day3.test.txt")); assert_eq!(test_result, "3121910778619"); let result = day3::day3_part2(include_str!("../input/day3.txt")); assert_eq!(result, "175304218462560"); } #[test] fn day2_part1_test() { let test_result = day2::day2_part1(include_str!("../input/day2.test.txt")); assert_eq!(test_result, "1227775554"); let result = day2::day2_part1(include_str!("../input/day2.txt")); assert_eq!(result, "38158151648"); } #[test] fn day2_part2_test() { let test_result = day2::day2_part2(include_str!("../input/day2.test.txt")); assert_eq!(test_result, "4174379265"); let result = day2::day2_part2(include_str!("../input/day2.txt")); assert_eq!(result, "45283684555"); } #[test] fn day1_part1_test() { let test_result = day1::day1_part1(include_str!("../input/day1.test.txt")); assert_eq!(test_result, "3"); let result = day1::day1_part1(include_str!("../input/day1.txt")); assert_eq!(result, "1021"); } #[test] fn day1_part2_test() { let test_result = day1::day1_part2(include_str!("../input/day1.test.txt")); assert_eq!(test_result, "6"); let result = day1::day1_part2(include_str!("../input/day1.txt")); assert_eq!(result, "5933"); } }