diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..04a2d6e --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,4 @@ +tab_spaces = 2 +hard_tabs = true +reorder_imports = true +newline_style = "Unix" diff --git a/src/day1.rs b/src/day1.rs index 54039c7..ec8e1b2 100644 --- a/src/day1.rs +++ b/src/day1.rs @@ -1,47 +1,44 @@ use std::num::ParseIntError; pub fn parse_input(input: &str) -> Result, ParseIntError> { - input.split_whitespace() - .map(|s| s.parse()) - .collect() + input.split_whitespace().map(|s| s.parse()).collect() } pub fn part1(depths: &[u32]) -> u32 { - let mut count = 0; - for i in 1..depths.len() { - if depths[i] > depths[i-1] { - count += 1; - } - } - return count; + let mut count = 0; + for i in 1..depths.len() { + if depths[i] > depths[i - 1] { + count += 1; + } + } + return count; } pub fn part2(depths: &[u32]) -> u32 { - let mut count = 0; - for i in 2..depths.len()-1 { - if depths[i+1] > depths[i-2] { - count += 1; - } - } - return count; + let mut count = 0; + for i in 2..depths.len() - 1 { + if depths[i + 1] > depths[i - 2] { + count += 1; + } + } + return count; } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let input = [199, 200, 208, 210, 200, 207, 240, 269, 260, 263]; - let result = part1(&input); - assert_eq!(result, 7); - } + #[test] + fn part1_example() { + let input = [199, 200, 208, 210, 200, 207, 240, 269, 260, 263]; + let result = part1(&input); + assert_eq!(result, 7); + } - #[test] - fn part2_example() { - let input = [199, 200, 208, 210, 200, 207, 240, 269, 260, 263]; - let result = part2(&input); - assert_eq!(result, 5); - } + #[test] + fn part2_example() { + let input = [199, 200, 208, 210, 200, 207, 240, 269, 260, 263]; + let result = part2(&input); + assert_eq!(result, 5); + } } - diff --git a/src/day10.rs b/src/day10.rs index 9a5eb39..17b5ebd 100644 --- a/src/day10.rs +++ b/src/day10.rs @@ -1,137 +1,135 @@ - #[derive(PartialEq)] enum ChunkVariant { - Parenthesis, - Bracket, - Curly, - Pointy + Parenthesis, + Bracket, + Curly, + Pointy, } pub fn parse_input(input: &str) -> Vec { - input.lines().map(|s| s.into()).collect() + input.lines().map(|s| s.into()).collect() } fn is_opening(c: char) -> bool { - c == '(' || c == '[' || c == '{' || c == '<' + c == '(' || c == '[' || c == '{' || c == '<' } // I know that it is not ideal to throw a panic here. But I'm too lazy to do // error handling. And the input is guaranteed to be correct to this is fine. fn get_chunk_variant(c: char) -> ChunkVariant { - match c { - '('|')' => ChunkVariant::Parenthesis, - '['|']' => ChunkVariant::Bracket, - '{'|'}' => ChunkVariant::Curly, - '<'|'>' => ChunkVariant::Pointy, - _ => panic!("Invalid chunk character") - } + match c { + '(' | ')' => ChunkVariant::Parenthesis, + '[' | ']' => ChunkVariant::Bracket, + '{' | '}' => ChunkVariant::Curly, + '<' | '>' => ChunkVariant::Pointy, + _ => panic!("Invalid chunk character"), + } } fn find_corrupted_chunk_symbol(line: &str) -> Option { - let mut active_chunks: Vec = Vec::new(); - for c in line.chars() { - let variant = get_chunk_variant(c); - if is_opening(c) { - active_chunks.push(variant); - } else { - if *active_chunks.last().unwrap() != variant { - return Some(variant); - } - active_chunks.pop(); - } - } - None + let mut active_chunks: Vec = Vec::new(); + for c in line.chars() { + let variant = get_chunk_variant(c); + if is_opening(c) { + active_chunks.push(variant); + } else { + if *active_chunks.last().unwrap() != variant { + return Some(variant); + } + active_chunks.pop(); + } + } + None } pub fn part1(lines: &Vec) -> u32 { - let mut score = 0; - for line in lines { - let result = find_corrupted_chunk_symbol(line); - score += match result { - Some(ChunkVariant::Parenthesis) => 3, - Some(ChunkVariant::Bracket) => 57, - Some(ChunkVariant::Curly) => 1197, - Some(ChunkVariant::Pointy) => 25137, - None => 0 - } - } - return score; + let mut score = 0; + for line in lines { + let result = find_corrupted_chunk_symbol(line); + score += match result { + Some(ChunkVariant::Parenthesis) => 3, + Some(ChunkVariant::Bracket) => 57, + Some(ChunkVariant::Curly) => 1197, + Some(ChunkVariant::Pointy) => 25137, + None => 0, + } + } + return score; } fn find_unclosed_chunks(line: &str) -> Vec { - let mut active_chunks: Vec = Vec::new(); - for c in line.chars() { - if is_opening(c) { - active_chunks.push(get_chunk_variant(c)); - } else { - active_chunks.pop(); - } - } - active_chunks + let mut active_chunks: Vec = Vec::new(); + for c in line.chars() { + if is_opening(c) { + active_chunks.push(get_chunk_variant(c)); + } else { + active_chunks.pop(); + } + } + active_chunks } pub fn part2(lines: &Vec) -> u64 { - let mut scores = Vec::new(); - for line in lines { - let corrupted = find_corrupted_chunk_symbol(line); - if corrupted == None { - let mut score = 0; - let mut unclosed_chunks = find_unclosed_chunks(line); - unclosed_chunks.reverse(); - for chunk in unclosed_chunks { - score *= 5; - score += match chunk { - ChunkVariant::Parenthesis => 1, - ChunkVariant::Bracket => 2, - ChunkVariant::Curly => 3, - ChunkVariant::Pointy => 4 - } - } - scores.push(score); - } - } - scores.sort(); - return scores[scores.len()/2]; + let mut scores = Vec::new(); + for line in lines { + let corrupted = find_corrupted_chunk_symbol(line); + if corrupted == None { + let mut score = 0; + let mut unclosed_chunks = find_unclosed_chunks(line); + unclosed_chunks.reverse(); + for chunk in unclosed_chunks { + score *= 5; + score += match chunk { + ChunkVariant::Parenthesis => 1, + ChunkVariant::Bracket => 2, + ChunkVariant::Curly => 3, + ChunkVariant::Pointy => 4, + } + } + scores.push(score); + } + } + scores.sort(); + return scores[scores.len() / 2]; } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let input = vec![ - "[({(<(())[]>[[{[]{<()<>>".into(), - "[(()[<>])]({[<{<<[]>>(".into(), - "{([(<{}[<>[]}>{[]{[(<()>".into(), - "(((({<>}<{<{<>}{[]{[]{}".into(), - "[[<[([]))<([[{}[[()]]]".into(), - "[{[{({}]{}}([{[{{{}}([]".into(), - "{<[[]]>}<{[{[{[]{()[[[]".into(), - "[<(<(<(<{}))><([]([]()".into(), - "<{([([[(<>()){}]>(<<{{".into(), - "<{([{{}}[<[[[<>{}]]]>[]]".into(), - ]; - let result = part1(&input); - assert_eq!(result, 26397); - } + #[test] + fn part1_example() { + let input = vec![ + "[({(<(())[]>[[{[]{<()<>>".into(), + "[(()[<>])]({[<{<<[]>>(".into(), + "{([(<{}[<>[]}>{[]{[(<()>".into(), + "(((({<>}<{<{<>}{[]{[]{}".into(), + "[[<[([]))<([[{}[[()]]]".into(), + "[{[{({}]{}}([{[{{{}}([]".into(), + "{<[[]]>}<{[{[{[]{()[[[]".into(), + "[<(<(<(<{}))><([]([]()".into(), + "<{([([[(<>()){}]>(<<{{".into(), + "<{([{{}}[<[[[<>{}]]]>[]]".into(), + ]; + let result = part1(&input); + assert_eq!(result, 26397); + } - #[test] - fn part2_example() { - let input = vec![ - "[({(<(())[]>[[{[]{<()<>>".into(), - "[(()[<>])]({[<{<<[]>>(".into(), - "{([(<{}[<>[]}>{[]{[(<()>".into(), - "(((({<>}<{<{<>}{[]{[]{}".into(), - "[[<[([]))<([[{}[[()]]]".into(), - "[{[{({}]{}}([{[{{{}}([]".into(), - "{<[[]]>}<{[{[{[]{()[[[]".into(), - "[<(<(<(<{}))><([]([]()".into(), - "<{([([[(<>()){}]>(<<{{".into(), - "<{([{{}}[<[[[<>{}]]]>[]]".into(), - ]; - let result = part2(&input); - assert_eq!(result, 288957); - } + #[test] + fn part2_example() { + let input = vec![ + "[({(<(())[]>[[{[]{<()<>>".into(), + "[(()[<>])]({[<{<<[]>>(".into(), + "{([(<{}[<>[]}>{[]{[(<()>".into(), + "(((({<>}<{<{<>}{[]{[]{}".into(), + "[[<[([]))<([[{}[[()]]]".into(), + "[{[{({}]{}}([{[{{{}}([]".into(), + "{<[[]]>}<{[{[{[]{()[[[]".into(), + "[<(<(<(<{}))><([]([]()".into(), + "<{([([[(<>()){}]>(<<{{".into(), + "<{([{{}}[<[[[<>{}]]]>[]]".into(), + ]; + let result = part2(&input); + assert_eq!(result, 288957); + } } - diff --git a/src/day11.rs b/src/day11.rs index fc3b915..38ed0db 100644 --- a/src/day11.rs +++ b/src/day11.rs @@ -1,171 +1,173 @@ use arrayvec::ArrayVec; pub fn parse_input(input: &str) -> [[u32; 10]; 10] { - input.lines() - .map(|s| s.chars() - .map(|s| s.to_digit(10).unwrap()) - .collect::>() - .into_inner() - .unwrap()) - .collect::>() - .into_inner() - .unwrap() + input + .lines() + .map(|s| { + s.chars() + .map(|s| s.to_digit(10).unwrap()) + .collect::>() + .into_inner() + .unwrap() + }) + .collect::>() + .into_inner() + .unwrap() } fn _display_grid(grid: &[[u32; 10]; 10]) { - for i in 0..grid.len() { - for j in 0..grid[i].len() { - print!("{:X}", grid[i][j]); - } - print!("\n"); - } - print!("\n"); + for i in 0..grid.len() { + for j in 0..grid[i].len() { + print!("{:X}", grid[i][j]); + } + print!("\n"); + } + print!("\n"); } fn bump_energy(grid: &mut [[u32; 10]; 10]) { - for i in 0..grid.len() { - for j in 0..grid[i].len() { - grid[i][j] += 1; - } - } + for i in 0..grid.len() { + for j in 0..grid[i].len() { + grid[i][j] += 1; + } + } } fn bump_energy_around(grid: &mut [[u32; 10]; 10], i: usize, j: usize) { - if j > 0 { - grid[i+0][j-1] += 1; - } - if j < 9 { - grid[i+0][j+1] += 1; - } - if i > 0 { - grid[i-1][j+0] += 1; - } - if i < 9 { - grid[i+1][j+0] += 1; - } + if j > 0 { + grid[i + 0][j - 1] += 1; + } + if j < 9 { + grid[i + 0][j + 1] += 1; + } + if i > 0 { + grid[i - 1][j + 0] += 1; + } + if i < 9 { + grid[i + 1][j + 0] += 1; + } - if i > 0 && j > 0 { - grid[i-1][j-1] += 1; - } - if i < 9 && j > 0 { - grid[i+1][j-1] += 1; - } - if i > 0 && j < 9 { - grid[i-1][j+1] += 1; - } - if i < 9 && j < 9 { - grid[i+1][j+1] += 1; - } + if i > 0 && j > 0 { + grid[i - 1][j - 1] += 1; + } + if i < 9 && j > 0 { + grid[i + 1][j - 1] += 1; + } + if i > 0 && j < 9 { + grid[i - 1][j + 1] += 1; + } + if i < 9 && j < 9 { + grid[i + 1][j + 1] += 1; + } } fn perform_flashes(grid: &mut [[u32; 10]; 10]) -> u32 { - let mut flashes = 0; - let mut has_flashed: [[bool; 10]; 10] = [[false; 10]; 10]; - let mut anyone_flashed = true; + let mut flashes = 0; + let mut has_flashed: [[bool; 10]; 10] = [[false; 10]; 10]; + let mut anyone_flashed = true; - while anyone_flashed { - anyone_flashed = false; + while anyone_flashed { + anyone_flashed = false; - for i in 0..grid.len() { - for j in 0..grid[i].len() { - if grid[i][j] > 9 && !has_flashed[i][j] { - flashes += 1; - has_flashed[i][j] = true; - anyone_flashed = true; - bump_energy_around(grid, i, j); - } - } - } - } + for i in 0..grid.len() { + for j in 0..grid[i].len() { + if grid[i][j] > 9 && !has_flashed[i][j] { + flashes += 1; + has_flashed[i][j] = true; + anyone_flashed = true; + bump_energy_around(grid, i, j); + } + } + } + } - return flashes; + return flashes; } fn reset_energy(grid: &mut [[u32; 10]; 10]) { - for i in 0..grid.len() { - for j in 0..grid[i].len() { - if grid[i][j] > 9 { - grid[i][j] = 0; - } - } - } + for i in 0..grid.len() { + for j in 0..grid[i].len() { + if grid[i][j] > 9 { + grid[i][j] = 0; + } + } + } } fn do_step(grid: &mut [[u32; 10]; 10]) -> u32 { - bump_energy(grid); - let flashes = perform_flashes(grid); - reset_energy(grid); - return flashes; + bump_energy(grid); + let flashes = perform_flashes(grid); + reset_energy(grid); + return flashes; } fn has_all_zeros(grid: &[[u32; 10]; 10]) -> bool { - for i in 0..grid.len() { - for j in 0..grid[i].len() { - if grid[i][j] != 0 { - return false; - } - } - } - return true; + for i in 0..grid.len() { + for j in 0..grid[i].len() { + if grid[i][j] != 0 { + return false; + } + } + } + return true; } pub fn part1(grid: &[[u32; 10]; 10]) -> u32 { - let mut flashes = 0; - let mut active_grid = grid.clone(); - for _ in 0..100 { - flashes += do_step(&mut active_grid); - } - return flashes; + let mut flashes = 0; + let mut active_grid = grid.clone(); + for _ in 0..100 { + flashes += do_step(&mut active_grid); + } + return flashes; } pub fn part2(grid: &[[u32; 10]; 10]) -> u32 { - let mut active_grid = grid.clone(); - let mut step = 0; - while !has_all_zeros(&active_grid) { - do_step(&mut active_grid); - step += 1; - } - return step; + let mut active_grid = grid.clone(); + let mut step = 0; + while !has_all_zeros(&active_grid) { + do_step(&mut active_grid); + step += 1; + } + return step; } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let input = [ - [5, 4, 8, 3, 1, 4, 3, 2, 2, 3], - [2, 7, 4, 5, 8, 5, 4, 7, 1, 1], - [5, 2, 6, 4, 5, 5, 6, 1, 7, 3], - [6, 1, 4, 1, 3, 3, 6, 1, 4, 6], - [6, 3, 5, 7, 3, 8, 5, 4, 7, 8], - [4, 1, 6, 7, 5, 2, 4, 6, 4, 5], - [2, 1, 7, 6, 8, 4, 1, 7, 2, 1], - [6, 8, 8, 2, 8, 8, 1, 1, 3, 4], - [4, 8, 4, 6, 8, 4, 8, 5, 5, 4], - [5, 2, 8, 3, 7, 5, 1, 5, 2, 6] - ]; - let result = part1(&input); - assert_eq!(result, 1656); - } + #[test] + fn part1_example() { + let input = [ + [5, 4, 8, 3, 1, 4, 3, 2, 2, 3], + [2, 7, 4, 5, 8, 5, 4, 7, 1, 1], + [5, 2, 6, 4, 5, 5, 6, 1, 7, 3], + [6, 1, 4, 1, 3, 3, 6, 1, 4, 6], + [6, 3, 5, 7, 3, 8, 5, 4, 7, 8], + [4, 1, 6, 7, 5, 2, 4, 6, 4, 5], + [2, 1, 7, 6, 8, 4, 1, 7, 2, 1], + [6, 8, 8, 2, 8, 8, 1, 1, 3, 4], + [4, 8, 4, 6, 8, 4, 8, 5, 5, 4], + [5, 2, 8, 3, 7, 5, 1, 5, 2, 6], + ]; + let result = part1(&input); + assert_eq!(result, 1656); + } - #[test] - fn part2_example() { - let input = [ - [5, 4, 8, 3, 1, 4, 3, 2, 2, 3], - [2, 7, 4, 5, 8, 5, 4, 7, 1, 1], - [5, 2, 6, 4, 5, 5, 6, 1, 7, 3], - [6, 1, 4, 1, 3, 3, 6, 1, 4, 6], - [6, 3, 5, 7, 3, 8, 5, 4, 7, 8], - [4, 1, 6, 7, 5, 2, 4, 6, 4, 5], - [2, 1, 7, 6, 8, 4, 1, 7, 2, 1], - [6, 8, 8, 2, 8, 8, 1, 1, 3, 4], - [4, 8, 4, 6, 8, 4, 8, 5, 5, 4], - [5, 2, 8, 3, 7, 5, 1, 5, 2, 6] - ]; - let result = part2(&input); - assert_eq!(result, 195); - } + #[test] + fn part2_example() { + let input = [ + [5, 4, 8, 3, 1, 4, 3, 2, 2, 3], + [2, 7, 4, 5, 8, 5, 4, 7, 1, 1], + [5, 2, 6, 4, 5, 5, 6, 1, 7, 3], + [6, 1, 4, 1, 3, 3, 6, 1, 4, 6], + [6, 3, 5, 7, 3, 8, 5, 4, 7, 8], + [4, 1, 6, 7, 5, 2, 4, 6, 4, 5], + [2, 1, 7, 6, 8, 4, 1, 7, 2, 1], + [6, 8, 8, 2, 8, 8, 1, 1, 3, 4], + [4, 8, 4, 6, 8, 4, 8, 5, 5, 4], + [5, 2, 8, 3, 7, 5, 1, 5, 2, 6], + ]; + let result = part2(&input); + assert_eq!(result, 195); + } } - diff --git a/src/day12.rs b/src/day12.rs index 78d01e8..bcbf456 100644 --- a/src/day12.rs +++ b/src/day12.rs @@ -1,160 +1,175 @@ use std::collections::{HashMap, HashSet}; pub fn parse_input(input: &str) -> Vec<(String, String)> { - let mut edges: Vec<(String, String)> = Vec::new(); + let mut edges: Vec<(String, String)> = Vec::new(); - for line in input.lines() { - let (from, to) = line.split_once('-').unwrap(); - edges.push((from.into(), to.into())); - } + for line in input.lines() { + let (from, to) = line.split_once('-').unwrap(); + edges.push((from.into(), to.into())); + } - return edges; + return edges; } fn edges_to_map(edges: &Vec<(String, String)>) -> HashMap> { - let mut map = HashMap::new(); + let mut map = HashMap::new(); - for line in edges { - map.entry(line.1.clone()) - .or_insert(Vec::new()) - .push(line.0.clone()); + for line in edges { + map + .entry(line.1.clone()) + .or_insert(Vec::new()) + .push(line.0.clone()); - map.entry(line.0.clone()) - .or_insert(Vec::new()) - .push(line.1.clone()); - } + map + .entry(line.0.clone()) + .or_insert(Vec::new()) + .push(line.1.clone()); + } - return map; + return map; } fn is_path_finished(path: &Vec<&str>) -> bool { - return path.contains(&"end") + return path.contains(&"end"); } fn can_be_appended_part1(path: &Vec<&str>, node: &str) -> bool { - node.to_uppercase() == node || !path.contains(&node) + node.to_uppercase() == node || !path.contains(&node) } pub fn part1(edges: &Vec<(String, String)>) -> usize { - let map = edges_to_map(edges); + let map = edges_to_map(edges); - let mut finished_paths: Vec> = Vec::new(); + let mut finished_paths: Vec> = Vec::new(); - let mut unfinished_paths: Vec> = Vec::new(); - unfinished_paths.push(vec!["start"]); - while unfinished_paths.len() > 0 { - let mut new_paths = Vec::new(); + let mut unfinished_paths: Vec> = Vec::new(); + unfinished_paths.push(vec!["start"]); + while unfinished_paths.len() > 0 { + let mut new_paths = Vec::new(); - for path in &mut unfinished_paths { - for node in map.get(*path.last().unwrap()).unwrap() { - if can_be_appended_part1(path, node) { - let mut new_path = path.clone(); - new_path.push(node); + for path in &mut unfinished_paths { + for node in map.get(*path.last().unwrap()).unwrap() { + if can_be_appended_part1(path, node) { + let mut new_path = path.clone(); + new_path.push(node); - if is_path_finished(&new_path) { - finished_paths.push(new_path); - } else { - new_paths.push(new_path); - } - } - } - } + if is_path_finished(&new_path) { + finished_paths.push(new_path); + } else { + new_paths.push(new_path); + } + } + } + } - unfinished_paths = new_paths; - } + unfinished_paths = new_paths; + } - return finished_paths.len(); + return finished_paths.len(); } fn can_be_appended_part2(path: &Vec<&str>, node: &str) -> bool { - if node == "start" { return false; } - if node == "end" { return true; } - if node.to_uppercase() == node { return true; } + if node == "start" { + return false; + } + if node == "end" { + return true; + } + if node.to_uppercase() == node { + return true; + } - // If all lowercase nodes only apear once we can be assure that any lowercase - // node that will be added will be correct. - let mut uniq = HashSet::new(); - if path.into_iter().all(move |x| x.to_lowercase() != *x || uniq.insert(x)) { - return true; - } + // If all lowercase nodes only apear once we can be assure that any lowercase + // node that will be added will be correct. + let mut uniq = HashSet::new(); + if path + .into_iter() + .all(move |x| x.to_lowercase() != *x || uniq.insert(x)) + { + return true; + } - return !path.contains(&node); + return !path.contains(&node); } pub fn part2(edges: &Vec<(String, String)>) -> usize { - let map = edges_to_map(edges); + let map = edges_to_map(edges); - let mut finished_paths: Vec> = Vec::new(); + let mut finished_paths: Vec> = Vec::new(); - let mut unfinished_paths: Vec> = Vec::new(); - unfinished_paths.push(vec!["start"]); - while unfinished_paths.len() > 0 { - let mut new_paths = Vec::new(); + let mut unfinished_paths: Vec> = Vec::new(); + unfinished_paths.push(vec!["start"]); + while unfinished_paths.len() > 0 { + let mut new_paths = Vec::new(); - for path in &mut unfinished_paths { - for node in map.get(*path.last().unwrap()).unwrap() { - if can_be_appended_part2(path, node) { - let mut new_path = path.clone(); - new_path.push(node); + for path in &mut unfinished_paths { + for node in map.get(*path.last().unwrap()).unwrap() { + if can_be_appended_part2(path, node) { + let mut new_path = path.clone(); + new_path.push(node); - if is_path_finished(&new_path) { - finished_paths.push(new_path); - } else { - new_paths.push(new_path); - } - } - } - } + if is_path_finished(&new_path) { + finished_paths.push(new_path); + } else { + new_paths.push(new_path); + } + } + } + } - unfinished_paths = new_paths; - } + unfinished_paths = new_paths; + } - return finished_paths.len(); + return finished_paths.len(); } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let cave_system = parse_input("start-A\nstart-b\nA-c\nA-b\nb-d\nA-end\nb-end"); - let result = part1(&cave_system); - assert_eq!(result, 10); - } + #[test] + fn part1_example() { + let cave_system = parse_input("start-A\nstart-b\nA-c\nA-b\nb-d\nA-end\nb-end"); + let result = part1(&cave_system); + assert_eq!(result, 10); + } - #[test] - fn part1_larger_example() { - let cave_system = parse_input("dc-end\nHN-start\nstart-kj\ndc-start\ndc-HN\nLN-dc\nHN-end\nkj-sa\nkj-HN\nkj-dc"); - let result = part1(&cave_system); - assert_eq!(result, 19); - } + #[test] + fn part1_larger_example() { + let cave_system = parse_input( + "dc-end\nHN-start\nstart-kj\ndc-start\ndc-HN\nLN-dc\nHN-end\nkj-sa\nkj-HN\nkj-dc", + ); + let result = part1(&cave_system); + assert_eq!(result, 19); + } - #[test] - fn part1_largest_example() { - let cave_system = parse_input("fs-end\nhe-DX\nfs-he\nstart-DX\npj-DX\nend-zg\nzg-sl\nzg-pj\npj-he\nRW-he\nfs-DX\npj-RW\nzg-RW\nstart-pj\nhe-WI\nzg-he\npj-fs\nstart-RW"); - let result = part1(&cave_system); - assert_eq!(result, 226); - } + #[test] + fn part1_largest_example() { + let cave_system = parse_input("fs-end\nhe-DX\nfs-he\nstart-DX\npj-DX\nend-zg\nzg-sl\nzg-pj\npj-he\nRW-he\nfs-DX\npj-RW\nzg-RW\nstart-pj\nhe-WI\nzg-he\npj-fs\nstart-RW"); + let result = part1(&cave_system); + assert_eq!(result, 226); + } - #[test] - fn part2_example() { - let cave_system = parse_input("start-A\nstart-b\nA-c\nA-b\nb-d\nA-end\nb-end"); - let result = part2(&cave_system); - assert_eq!(result, 36); - } + #[test] + fn part2_example() { + let cave_system = parse_input("start-A\nstart-b\nA-c\nA-b\nb-d\nA-end\nb-end"); + let result = part2(&cave_system); + assert_eq!(result, 36); + } - #[test] - fn part2_larger_example() { - let cave_system = parse_input("dc-end\nHN-start\nstart-kj\ndc-start\ndc-HN\nLN-dc\nHN-end\nkj-sa\nkj-HN\nkj-dc"); - let result = part2(&cave_system); - assert_eq!(result, 103); - } + #[test] + fn part2_larger_example() { + let cave_system = parse_input( + "dc-end\nHN-start\nstart-kj\ndc-start\ndc-HN\nLN-dc\nHN-end\nkj-sa\nkj-HN\nkj-dc", + ); + let result = part2(&cave_system); + assert_eq!(result, 103); + } - #[test] - fn part2_largest_example() { - let cave_system = parse_input("fs-end\nhe-DX\nfs-he\nstart-DX\npj-DX\nend-zg\nzg-sl\nzg-pj\npj-he\nRW-he\nfs-DX\npj-RW\nzg-RW\nstart-pj\nhe-WI\nzg-he\npj-fs\nstart-RW"); - let result = part2(&cave_system); - assert_eq!(result, 3509); - } + #[test] + fn part2_largest_example() { + let cave_system = parse_input("fs-end\nhe-DX\nfs-he\nstart-DX\npj-DX\nend-zg\nzg-sl\nzg-pj\npj-he\nRW-he\nfs-DX\npj-RW\nzg-RW\nstart-pj\nhe-WI\nzg-he\npj-fs\nstart-RW"); + let result = part2(&cave_system); + assert_eq!(result, 3509); + } } diff --git a/src/day13.rs b/src/day13.rs index 1f0d47e..f51db25 100644 --- a/src/day13.rs +++ b/src/day13.rs @@ -5,156 +5,143 @@ pub struct Dot(u32, u32); #[derive(Debug)] pub enum Fold { - X(u32), - Y(u32), + X(u32), + Y(u32), } pub struct InputData { - dots: Vec, - folds: Vec + dots: Vec, + folds: Vec, } fn parse_dot(line: &str) -> Dot { - let (x, y) = line.split_once(',').unwrap(); - return Dot( - x.parse().unwrap(), - y.parse().unwrap() - ); + let (x, y) = line.split_once(',').unwrap(); + return Dot(x.parse().unwrap(), y.parse().unwrap()); } fn parse_fold(line: &str) -> Fold { - let (axis, coordinate_str) = line.split_once('=').unwrap(); - let coordinate = coordinate_str.parse().unwrap(); - match axis { - "fold along x" => Fold::X(coordinate), - "fold along y" => Fold::Y(coordinate), - _ => unreachable!("Unable to parse fold direction") - } + let (axis, coordinate_str) = line.split_once('=').unwrap(); + let coordinate = coordinate_str.parse().unwrap(); + match axis { + "fold along x" => Fold::X(coordinate), + "fold along y" => Fold::Y(coordinate), + _ => unreachable!("Unable to parse fold direction"), + } } pub fn parse_input(input: &str) -> InputData { - let (dots_section, folds_section) = input.split_once("\n\n").unwrap(); + let (dots_section, folds_section) = input.split_once("\n\n").unwrap(); - let dots = dots_section.lines() - .map(parse_dot) - .collect(); - let folds = folds_section.lines() - .map(parse_fold) - .collect(); + let dots = dots_section.lines().map(parse_dot).collect(); + let folds = folds_section.lines().map(parse_fold).collect(); - return InputData { - dots, - folds - }; + return InputData { dots, folds }; } fn perform_fold(dots: &HashSet, fold: &Fold) -> HashSet { - let mut folded_dots = HashSet::new(); + let mut folded_dots = HashSet::new(); - for dot in dots.iter() { - let folded_dot = match fold { - Fold::X(x) => { - if dot.0 > *x { - Dot(2*x - dot.0, dot.1) - } else { - dot.clone() - } - }, - Fold::Y(y) => { - if dot.1 > *y { - Dot(dot.0, 2*y - dot.1) - } else { - dot.clone() - } - }, - }; - folded_dots.insert(folded_dot); - } + for dot in dots.iter() { + let folded_dot = match fold { + Fold::X(x) => { + if dot.0 > *x { + Dot(2 * x - dot.0, dot.1) + } else { + dot.clone() + } + } + Fold::Y(y) => { + if dot.1 > *y { + Dot(dot.0, 2 * y - dot.1) + } else { + dot.clone() + } + } + }; + folded_dots.insert(folded_dot); + } - return folded_dots; + return folded_dots; } pub fn part1(input: &InputData) -> usize { - let mut folded_dots = HashSet::new(); - for dot in &input.dots { - folded_dots.insert(dot.clone()); - } - folded_dots = perform_fold(&folded_dots, &input.folds[0]); - folded_dots.len() as usize + let mut folded_dots = HashSet::new(); + for dot in &input.dots { + folded_dots.insert(dot.clone()); + } + folded_dots = perform_fold(&folded_dots, &input.folds[0]); + folded_dots.len() as usize } fn determine_dot_bounds(dots: &HashSet) -> (u32, u32, u32, u32) { - let mut min_x = u32::MAX; - let mut min_y = u32::MAX; - let mut max_x = u32::MIN; - let mut max_y = u32::MIN; + let mut min_x = u32::MAX; + let mut min_y = u32::MAX; + let mut max_x = u32::MIN; + let mut max_y = u32::MIN; - for dot in dots { - min_x = min_x.min(dot.0); - min_y = min_y.min(dot.1); - max_x = max_x.max(dot.0); - max_y = max_y.max(dot.1); - } + for dot in dots { + min_x = min_x.min(dot.0); + min_y = min_y.min(dot.1); + max_x = max_x.max(dot.0); + max_y = max_y.max(dot.1); + } - return (min_x, min_y, max_x, max_y); + return (min_x, min_y, max_x, max_y); } fn render_dots(dots: &HashSet) { - let (min_x, min_y, max_x, max_y) = determine_dot_bounds(dots); - for y in min_y..=max_y { - for x in min_x..=max_x { - if dots.contains(&Dot(x, y)) { - print!("#"); - } else { - print!("."); - } - } - print!("\n"); - } + let (min_x, min_y, max_x, max_y) = determine_dot_bounds(dots); + for y in min_y..=max_y { + for x in min_x..=max_x { + if dots.contains(&Dot(x, y)) { + print!("#"); + } else { + print!("."); + } + } + print!("\n"); + } } pub fn part2(input: &InputData) { - let mut folded_dots = HashSet::new(); - for dot in &input.dots { - folded_dots.insert(dot.clone()); - } - for fold in &input.folds { - folded_dots = perform_fold(&folded_dots, fold); - } - render_dots(&folded_dots); + let mut folded_dots = HashSet::new(); + for dot in &input.dots { + folded_dots.insert(dot.clone()); + } + for fold in &input.folds { + folded_dots = perform_fold(&folded_dots, fold); + } + render_dots(&folded_dots); } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let dots = vec![ - Dot(6, 10), - Dot(0, 14), - Dot(9, 10), - Dot(0, 3), - Dot(10, 4), - Dot(4, 11), - Dot(6, 0), - Dot(6, 12), - Dot(4, 1), - Dot(0, 13), - Dot(10, 12), - Dot(3, 4), - Dot(3, 0), - Dot(8, 4), - Dot(1, 10), - Dot(2 ,14), - Dot(8 ,10), - Dot(9, 0) - ]; - let folds = vec![ - Fold::Y(7), - Fold::X(5), - ]; - let result = part1(&InputData{ dots, folds }); - assert_eq!(result, 17); - } + #[test] + fn part1_example() { + let dots = vec![ + Dot(6, 10), + Dot(0, 14), + Dot(9, 10), + Dot(0, 3), + Dot(10, 4), + Dot(4, 11), + Dot(6, 0), + Dot(6, 12), + Dot(4, 1), + Dot(0, 13), + Dot(10, 12), + Dot(3, 4), + Dot(3, 0), + Dot(8, 4), + Dot(1, 10), + Dot(2, 14), + Dot(8, 10), + Dot(9, 0), + ]; + let folds = vec![Fold::Y(7), Fold::X(5)]; + let result = part1(&InputData { dots, folds }); + assert_eq!(result, 17); + } } diff --git a/src/day14.rs b/src/day14.rs index 5650dc6..3e59aef 100644 --- a/src/day14.rs +++ b/src/day14.rs @@ -1,160 +1,187 @@ use std::collections::HashMap; pub struct InputData { - polymer_template: String, - rules: HashMap<[char; 2], char> + polymer_template: String, + rules: HashMap<[char; 2], char>, } pub fn parse_input(input: &str) -> InputData { - let (polymer_template, rules_section) = input.split_once("\n\n").unwrap(); - let mut rules = HashMap::new(); - for line in rules_section.lines() { - let (pattern, expansion) = line.split_once(" -> ").unwrap(); - rules.insert( - [pattern.chars().nth(0).unwrap(), pattern.chars().nth(1).unwrap()], - expansion.chars().nth(0).unwrap() - ); - } - return InputData { - polymer_template: polymer_template.into(), - rules - }; + let (polymer_template, rules_section) = input.split_once("\n\n").unwrap(); + let mut rules = HashMap::new(); + for line in rules_section.lines() { + let (pattern, expansion) = line.split_once(" -> ").unwrap(); + rules.insert( + [ + pattern.chars().nth(0).unwrap(), + pattern.chars().nth(1).unwrap(), + ], + expansion.chars().nth(0).unwrap(), + ); + } + return InputData { + polymer_template: polymer_template.into(), + rules, + }; } fn naive_expand_polymer(polymer: Vec, rules: &HashMap<[char; 2], char>) -> Vec { - let mut new_polymer = Vec::new(); - for i in 0..polymer.len()-1 { - new_polymer.push(polymer[i]); - let pair = [polymer[i], polymer[i+1]]; - let rule = rules.get(&pair); - if rule != None { - new_polymer.push(*rule.unwrap()); - } - } - new_polymer.push(*polymer.last().unwrap()); - return new_polymer; + let mut new_polymer = Vec::new(); + for i in 0..polymer.len() - 1 { + new_polymer.push(polymer[i]); + let pair = [polymer[i], polymer[i + 1]]; + let rule = rules.get(&pair); + if rule != None { + new_polymer.push(*rule.unwrap()); + } + } + new_polymer.push(*polymer.last().unwrap()); + return new_polymer; } pub fn part1(input: &InputData) -> u32 { - let mut polymer = input.polymer_template.chars().collect(); - for _ in 0..10 { - polymer = naive_expand_polymer(polymer, &input.rules); - } + let mut polymer = input.polymer_template.chars().collect(); + for _ in 0..10 { + polymer = naive_expand_polymer(polymer, &input.rules); + } - let mut element_amounts = HashMap::new(); - for c in polymer { - let amount = element_amounts.entry(c).or_insert(0); - *amount += 1; - } + let mut element_amounts = HashMap::new(); + for c in polymer { + let amount = element_amounts.entry(c).or_insert(0); + *amount += 1; + } - let least_common_element = element_amounts.iter().min_by(|a, b| a.1.cmp(b.1)).unwrap().1; - let most_common_element = element_amounts.iter().max_by(|a, b| a.1.cmp(b.1)).unwrap().1; - return most_common_element - least_common_element; + let least_common_element = element_amounts + .iter() + .min_by(|a, b| a.1.cmp(b.1)) + .unwrap() + .1; + let most_common_element = element_amounts + .iter() + .max_by(|a, b| a.1.cmp(b.1)) + .unwrap() + .1; + return most_common_element - least_common_element; } -fn expand_polymer(polymer_pairs: &HashMap<[char; 2], u64>, rules: &HashMap<[char; 2], char>) -> HashMap<[char; 2], u64> { - let mut new_pairs = HashMap::new(); - for entry in polymer_pairs { - let pair = entry.0; - if rules.contains_key(pair) { - let rule = *rules.get(pair).unwrap(); +fn expand_polymer( + polymer_pairs: &HashMap<[char; 2], u64>, + rules: &HashMap<[char; 2], char>, +) -> HashMap<[char; 2], u64> { + let mut new_pairs = HashMap::new(); + for entry in polymer_pairs { + let pair = entry.0; + if rules.contains_key(pair) { + let rule = *rules.get(pair).unwrap(); - let left_pair = [pair[0], rule]; - let left_entry = new_pairs.entry(left_pair).or_insert(0); - *left_entry += entry.1; + let left_pair = [pair[0], rule]; + let left_entry = new_pairs.entry(left_pair).or_insert(0); + *left_entry += entry.1; - let right_pair = [rule, pair[1]]; - let right_entry = new_pairs.entry(right_pair).or_insert(0); - *right_entry += entry.1; - } else { - let new_entry = new_pairs.entry(*entry.0).or_insert(0); - *new_entry = *entry.1; - } - } - return new_pairs; - + let right_pair = [rule, pair[1]]; + let right_entry = new_pairs.entry(right_pair).or_insert(0); + *right_entry += entry.1; + } else { + let new_entry = new_pairs.entry(*entry.0).or_insert(0); + *new_entry = *entry.1; + } + } + return new_pairs; } pub fn part2(input: &InputData) -> u64 { - let polymer_template = &input.polymer_template; - let mut polymer_pairs = HashMap::new(); - for i in 0..polymer_template.len()-1 { - let pair = [ - polymer_template.chars().nth(i).unwrap(), - polymer_template.chars().nth(i+1).unwrap() - ]; - let entry = polymer_pairs.entry(pair).or_insert(0); - *entry += 1; - } + let polymer_template = &input.polymer_template; + let mut polymer_pairs = HashMap::new(); + for i in 0..polymer_template.len() - 1 { + let pair = [ + polymer_template.chars().nth(i).unwrap(), + polymer_template.chars().nth(i + 1).unwrap(), + ]; + let entry = polymer_pairs.entry(pair).or_insert(0); + *entry += 1; + } - for _ in 0..40 { - polymer_pairs = expand_polymer(&polymer_pairs, &input.rules); - } + for _ in 0..40 { + polymer_pairs = expand_polymer(&polymer_pairs, &input.rules); + } - let mut element_amounts = HashMap::new(); - for entry in polymer_pairs { - for c in entry.0 { - let amount = element_amounts.entry(c).or_insert(0); - *amount += entry.1; - } - } + let mut element_amounts = HashMap::new(); + for entry in polymer_pairs { + for c in entry.0 { + let amount = element_amounts.entry(c).or_insert(0); + *amount += entry.1; + } + } - let least_common_element = element_amounts.iter().min_by(|a, b| a.1.cmp(b.1)).unwrap().1; - let most_common_element = element_amounts.iter().max_by(|a, b| a.1.cmp(b.1)).unwrap().1; - return (most_common_element - least_common_element)/2 + 1; + let least_common_element = element_amounts + .iter() + .min_by(|a, b| a.1.cmp(b.1)) + .unwrap() + .1; + let most_common_element = element_amounts + .iter() + .max_by(|a, b| a.1.cmp(b.1)) + .unwrap() + .1; + return (most_common_element - least_common_element) / 2 + 1; } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let polymer_template = String::from("NNCB"); - let rules = HashMap::from([ - (['C', 'H'], 'B'), - (['H', 'H'], 'N'), - (['C', 'B'], 'H'), - (['N', 'H'], 'C'), - (['H', 'B'], 'C'), - (['H', 'C'], 'B'), - (['H', 'N'], 'C'), - (['N', 'N'], 'C'), - (['B', 'H'], 'H'), - (['N', 'C'], 'B'), - (['N', 'B'], 'B'), - (['B', 'N'], 'B'), - (['B', 'B'], 'N'), - (['B', 'C'], 'B'), - (['C', 'C'], 'N'), - (['C', 'N'], 'C') - ]); - let result = part1(&InputData { polymer_template, rules }); - assert_eq!(result, 1588); - } + #[test] + fn part1_example() { + let polymer_template = String::from("NNCB"); + let rules = HashMap::from([ + (['C', 'H'], 'B'), + (['H', 'H'], 'N'), + (['C', 'B'], 'H'), + (['N', 'H'], 'C'), + (['H', 'B'], 'C'), + (['H', 'C'], 'B'), + (['H', 'N'], 'C'), + (['N', 'N'], 'C'), + (['B', 'H'], 'H'), + (['N', 'C'], 'B'), + (['N', 'B'], 'B'), + (['B', 'N'], 'B'), + (['B', 'B'], 'N'), + (['B', 'C'], 'B'), + (['C', 'C'], 'N'), + (['C', 'N'], 'C'), + ]); + let result = part1(&InputData { + polymer_template, + rules, + }); + assert_eq!(result, 1588); + } - #[test] - fn part2_example() { - let polymer_template = String::from("NNCB"); - let rules = HashMap::from([ - (['C', 'H'], 'B'), - (['H', 'H'], 'N'), - (['C', 'B'], 'H'), - (['N', 'H'], 'C'), - (['H', 'B'], 'C'), - (['H', 'C'], 'B'), - (['H', 'N'], 'C'), - (['N', 'N'], 'C'), - (['B', 'H'], 'H'), - (['N', 'C'], 'B'), - (['N', 'B'], 'B'), - (['B', 'N'], 'B'), - (['B', 'B'], 'N'), - (['B', 'C'], 'B'), - (['C', 'C'], 'N'), - (['C', 'N'], 'C') - ]); - let result = part2(&InputData { polymer_template, rules }); - assert_eq!(result, 2188189693529); - } + #[test] + fn part2_example() { + let polymer_template = String::from("NNCB"); + let rules = HashMap::from([ + (['C', 'H'], 'B'), + (['H', 'H'], 'N'), + (['C', 'B'], 'H'), + (['N', 'H'], 'C'), + (['H', 'B'], 'C'), + (['H', 'C'], 'B'), + (['H', 'N'], 'C'), + (['N', 'N'], 'C'), + (['B', 'H'], 'H'), + (['N', 'C'], 'B'), + (['N', 'B'], 'B'), + (['B', 'N'], 'B'), + (['B', 'B'], 'N'), + (['B', 'C'], 'B'), + (['C', 'C'], 'N'), + (['C', 'N'], 'C'), + ]); + let result = part2(&InputData { + polymer_template, + rules, + }); + assert_eq!(result, 2188189693529); + } } diff --git a/src/day15.rs b/src/day15.rs index ab55a5e..5549eea 100644 --- a/src/day15.rs +++ b/src/day15.rs @@ -1,114 +1,120 @@ -use std::collections::{HashMap, HashSet}; use priority_queue::PriorityQueue; - +use std::collections::{HashMap, HashSet}; #[derive(Debug)] pub struct Grid { - rows: u32, - cols: u32, - data: Vec, - scale: u32 + rows: u32, + cols: u32, + data: Vec, + scale: u32, } impl Grid { - fn new(rows: u32, cols: u32, data: Vec) -> Grid { - return Grid { - rows, cols, data, - scale: 1 - } - } + fn new(rows: u32, cols: u32, data: Vec) -> Grid { + return Grid { + rows, + cols, + data, + scale: 1, + }; + } - fn get(&self, point: &(u32, u32)) -> u32 { - let row = point.0 % self.rows; - let col = point.1 % self.cols; - let value = self.data[(row * self.cols + col) as usize]; - return (value + point.0 / self.rows + point.1 / self.cols - 1) % 9 + 1; - } + fn get(&self, point: &(u32, u32)) -> u32 { + let row = point.0 % self.rows; + let col = point.1 % self.cols; + let value = self.data[(row * self.cols + col) as usize]; + return (value + point.0 / self.rows + point.1 / self.cols - 1) % 9 + 1; + } - fn width(&self) -> u32 { - self.cols * self.scale - } + fn width(&self) -> u32 { + self.cols * self.scale + } - fn height(&self) -> u32 { - self.rows * self.scale - } + fn height(&self) -> u32 { + self.rows * self.scale + } - fn within_bounds(&self, point: &(i32, i32)) -> bool { - point.0 >= 0 && point.1 >= 0 && point.0 < self.height() as i32 && point.1 < self.width() as i32 - } + fn within_bounds(&self, point: &(i32, i32)) -> bool { + point.0 >= 0 && point.1 >= 0 && point.0 < self.height() as i32 && point.1 < self.width() as i32 + } } pub fn parse_input(input: &str) -> Grid { - let mut data = Vec::new(); - let mut rows = 0; - let mut cols = 0; - for line in input.lines() { - rows += 1; - for c in line.chars() { - if rows == 1 { cols += 1 } - data.push(c.to_digit(10).unwrap()); - } - } - return Grid::new(rows, cols, data); + let mut data = Vec::new(); + let mut rows = 0; + let mut cols = 0; + for line in input.lines() { + rows += 1; + for c in line.chars() { + if rows == 1 { + cols += 1 + } + data.push(c.to_digit(10).unwrap()); + } + } + return Grid::new(rows, cols, data); } fn find_neighbours(pos: &(u32, u32), grid: &Grid, offsets: &[(i32, i32)]) -> Vec<(u32, u32)> { - let mut neighbours = Vec::new(); - for offset in offsets { - let row = pos.0 as i32 + offset.0; - let col = pos.1 as i32 + offset.1; - if grid.within_bounds(&(row, col)) { - neighbours.push((row as u32, col as u32)); - } - } - return neighbours; + let mut neighbours = Vec::new(); + for offset in offsets { + let row = pos.0 as i32 + offset.0; + let col = pos.1 as i32 + offset.1; + if grid.within_bounds(&(row, col)) { + neighbours.push((row as u32, col as u32)); + } + } + return neighbours; } fn find_shortest_path_cost(grid: &Grid) -> u32 { - let mut total_costs: HashMap<(u32, u32), u32> = HashMap::new(); - let mut min_pq: PriorityQueue<(u32, u32), i32> = PriorityQueue::new(); - let mut visited: HashSet<(u32, u32)> = HashSet::new(); - let neighbour_offsets = [ (0, 1), (0, -1), (1, 0), (-1, 0) ]; - min_pq.push((0, 0), 0); - total_costs.insert((0, 0), 0); + let mut total_costs: HashMap<(u32, u32), u32> = HashMap::new(); + let mut min_pq: PriorityQueue<(u32, u32), i32> = PriorityQueue::new(); + let mut visited: HashSet<(u32, u32)> = HashSet::new(); + let neighbour_offsets = [(0, 1), (0, -1), (1, 0), (-1, 0)]; + min_pq.push((0, 0), 0); + total_costs.insert((0, 0), 0); - while !min_pq.is_empty() { - let new_smallest = min_pq.pop().unwrap().0; - visited.insert(new_smallest); + while !min_pq.is_empty() { + let new_smallest = min_pq.pop().unwrap().0; + visited.insert(new_smallest); - for neighbour in find_neighbours(&new_smallest, grid, &neighbour_offsets) { - if visited.contains(&neighbour) { - continue; - } + for neighbour in find_neighbours(&new_smallest, grid, &neighbour_offsets) { + if visited.contains(&neighbour) { + continue; + } - let alt_distance = grid.get(&neighbour); - let alt_path = total_costs.get(&new_smallest).unwrap_or(&u32::MAX) + alt_distance; - if alt_path < *total_costs.get(&neighbour).unwrap_or(&u32::MAX) { - total_costs.insert(neighbour, alt_path); - min_pq.push_decrease(neighbour, -(alt_path as i32)); - } - } - } - - return *total_costs.get(&(grid.height()-1, grid.width()-1)).unwrap(); + let alt_distance = grid.get(&neighbour); + let alt_path = total_costs.get(&new_smallest).unwrap_or(&u32::MAX) + alt_distance; + if alt_path < *total_costs.get(&neighbour).unwrap_or(&u32::MAX) { + total_costs.insert(neighbour, alt_path); + min_pq.push_decrease(neighbour, -(alt_path as i32)); + } + } + } + + return *total_costs + .get(&(grid.height() - 1, grid.width() - 1)) + .unwrap(); } pub fn part1(grid: &Grid) -> u32 { - find_shortest_path_cost(grid) + find_shortest_path_cost(grid) } pub fn part2(grid: &mut Grid) -> u32 { - grid.scale = 5; - find_shortest_path_cost(grid) + grid.scale = 5; + find_shortest_path_cost(grid) } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let grid = parse_input("1163751742 + #[test] + fn part1_example() { + let grid = parse_input( + "1163751742 1381373672 2136511328 3694931569 @@ -117,14 +123,16 @@ mod tests { 1359912421 3125421639 1293138521 -2311944581"); - let result = part1(&grid); - assert_eq!(result, 40); - } +2311944581", + ); + let result = part1(&grid); + assert_eq!(result, 40); + } - #[test] - fn part2_example() { - let mut grid = parse_input("1163751742 + #[test] + fn part2_example() { + let mut grid = parse_input( + "1163751742 1381373672 2136511328 3694931569 @@ -133,9 +141,9 @@ mod tests { 1359912421 3125421639 1293138521 -2311944581"); - let result = part2(&mut grid); - assert_eq!(result, 315); - } +2311944581", + ); + let result = part2(&mut grid); + assert_eq!(result, 315); + } } - diff --git a/src/day16.rs b/src/day16.rs index a984476..c815029 100644 --- a/src/day16.rs +++ b/src/day16.rs @@ -1,256 +1,267 @@ - pub enum PacketBody { - Literal(u64), - Operator(Vec) + Literal(u64), + Operator(Vec), } pub struct Packet { - version: u8, - r#type: u8, - body: PacketBody + version: u8, + r#type: u8, + body: PacketBody, } fn to_bits(hex: &str) -> String { - let mut bits = String::new(); - for c in hex.bytes() { - match c { - b'0'..=b'9' => bits.push_str(format!("{:0>4b}", c - b'0').as_str()), - b'A'..=b'F' => bits.push_str(format!("{:0>4b}", c - b'A' + 10).as_str()), - _ => () - } - } - return bits; + let mut bits = String::new(); + for c in hex.bytes() { + match c { + b'0'..=b'9' => bits.push_str(format!("{:0>4b}", c - b'0').as_str()), + b'A'..=b'F' => bits.push_str(format!("{:0>4b}", c - b'A' + 10).as_str()), + _ => (), + } + } + return bits; } fn parse_literal_body(bits_str: &str) -> (PacketBody, u32) { - let mut value_bits = String::new(); - let mut cursor = 0; - let bytes = bits_str.as_bytes(); - loop { - value_bits.push_str(&bits_str[cursor+1..cursor+5]); - if bytes[cursor] == b'0' { break; } - cursor += 5; - } - let value = u64::from_str_radix(&value_bits, 2).unwrap(); + let mut value_bits = String::new(); + let mut cursor = 0; + let bytes = bits_str.as_bytes(); + loop { + value_bits.push_str(&bits_str[cursor + 1..cursor + 5]); + if bytes[cursor] == b'0' { + break; + } + cursor += 5; + } + let value = u64::from_str_radix(&value_bits, 2).unwrap(); - return (PacketBody::Literal(value), (cursor+5) as u32); + return (PacketBody::Literal(value), (cursor + 5) as u32); } fn parse_operator_body(bits_str: &str) -> (PacketBody, u32) { - let mut size: usize = 0; - let mut packets = Vec::new(); - let bytes = bits_str.as_bytes(); - size += 1; - if bytes[0] == b'1' { - size += 11; - let count = u32::from_str_radix(&bits_str[1..12], 2).unwrap(); - for _ in 0..count { - let (packet, s) = parse_packet(&bits_str[size..]); - packets.push(packet); - size += s as usize; - } - } else { - let total_size = u32::from_str_radix(&bits_str[1..16], 2).unwrap(); - size += 15; - while ((size-16) as u32) < total_size { - let (packet, s) = parse_packet(&bits_str[size..]); - packets.push(packet); - size += s as usize; - } - } - return (PacketBody::Operator(packets), size as u32); + let mut size: usize = 0; + let mut packets = Vec::new(); + let bytes = bits_str.as_bytes(); + size += 1; + if bytes[0] == b'1' { + size += 11; + let count = u32::from_str_radix(&bits_str[1..12], 2).unwrap(); + for _ in 0..count { + let (packet, s) = parse_packet(&bits_str[size..]); + packets.push(packet); + size += s as usize; + } + } else { + let total_size = u32::from_str_radix(&bits_str[1..16], 2).unwrap(); + size += 15; + while ((size - 16) as u32) < total_size { + let (packet, s) = parse_packet(&bits_str[size..]); + packets.push(packet); + size += s as usize; + } + } + return (PacketBody::Operator(packets), size as u32); } fn parse_packet(bits: &str) -> (Packet, u32) { - let r#type = u8::from_str_radix(&bits[3..6], 2).unwrap(); - let (body, body_size) = match r#type { - 4 => parse_literal_body(&bits[6..]), - _ => parse_operator_body(&bits[6..]) - }; + let r#type = u8::from_str_radix(&bits[3..6], 2).unwrap(); + let (body, body_size) = match r#type { + 4 => parse_literal_body(&bits[6..]), + _ => parse_operator_body(&bits[6..]), + }; - return (Packet { - version: u8::from_str_radix(&bits[0..3], 2).unwrap(), - r#type, - body - }, - body_size + 6 - ); + return ( + Packet { + version: u8::from_str_radix(&bits[0..3], 2).unwrap(), + r#type, + body, + }, + body_size + 6, + ); } pub fn parse_input(input: &str) -> Packet { - let (packet, _) = parse_packet(&to_bits(input)); - return packet; + let (packet, _) = parse_packet(&to_bits(input)); + return packet; } fn sum_packet_versions(packet: &Packet) -> u32 { - let mut sum: u32 = packet.version.into(); - match &packet.body { - PacketBody::Operator(packets) => { - for sub_packet in packets { - sum += sum_packet_versions(sub_packet); - } - }, - _ => () - }; - return sum; + let mut sum: u32 = packet.version.into(); + match &packet.body { + PacketBody::Operator(packets) => { + for sub_packet in packets { + sum += sum_packet_versions(sub_packet); + } + } + _ => (), + }; + return sum; } pub fn part1(packet: &Packet) -> u32 { - sum_packet_versions(packet) + sum_packet_versions(packet) } fn eval_sum_packets(packets: &[Packet]) -> u64 { - let mut sum = 0; - for packet in packets { - sum += eval_packet(packet); - } - return sum; + let mut sum = 0; + for packet in packets { + sum += eval_packet(packet); + } + return sum; } fn eval_product_packets(packets: &[Packet]) -> u64 { - let mut product = 1; - for packet in packets { - product *= eval_packet(packet); - } - return product; + let mut product = 1; + for packet in packets { + product *= eval_packet(packet); + } + return product; } fn eval_minimum_packets(packets: &[Packet]) -> u64 { - let mut min = u64::MAX; - for packet in packets { - min = min.min(eval_packet(packet)); - } - return min; + let mut min = u64::MAX; + for packet in packets { + min = min.min(eval_packet(packet)); + } + return min; } fn eval_maximum_packets(packets: &[Packet]) -> u64 { - let mut max = 0; - for packet in packets { - max = max.max(eval_packet(packet)); - } - return max; + let mut max = 0; + for packet in packets { + max = max.max(eval_packet(packet)); + } + return max; } fn eval_greater_packets(packets: &[Packet]) -> u64 { - let first_packet = packets.get(0).unwrap(); - let second_packet = packets.get(1).unwrap(); - if eval_packet(first_packet) > eval_packet(second_packet) { 1 } else { 0 } + let first_packet = packets.get(0).unwrap(); + let second_packet = packets.get(1).unwrap(); + if eval_packet(first_packet) > eval_packet(second_packet) { + 1 + } else { + 0 + } } fn eval_less_packets(packets: &[Packet]) -> u64 { - let first_packet = packets.get(0).unwrap(); - let second_packet = packets.get(1).unwrap(); - if eval_packet(first_packet) < eval_packet(second_packet) { 1 } else { 0 } + let first_packet = packets.get(0).unwrap(); + let second_packet = packets.get(1).unwrap(); + if eval_packet(first_packet) < eval_packet(second_packet) { + 1 + } else { + 0 + } } fn eval_equal_packets(packets: &[Packet]) -> u64 { - let first_packet = packets.get(0).unwrap(); - let second_packet = packets.get(1).unwrap(); - if eval_packet(first_packet) == eval_packet(second_packet) { 1 } else { 0 } + let first_packet = packets.get(0).unwrap(); + let second_packet = packets.get(1).unwrap(); + if eval_packet(first_packet) == eval_packet(second_packet) { + 1 + } else { + 0 + } } fn eval_packet(packet: &Packet) -> u64 { - match &packet.body { - PacketBody::Literal(value) => *value, - PacketBody::Operator(packets) => { - match packet.r#type { - 0 => eval_sum_packets(packets), - 1 => eval_product_packets(packets), - 2 => eval_minimum_packets(packets), - 3 => eval_maximum_packets(packets), - 5 => eval_greater_packets(packets), - 6 => eval_less_packets(packets), - 7 => eval_equal_packets(packets), - _ => unreachable!() - } - } - } + match &packet.body { + PacketBody::Literal(value) => *value, + PacketBody::Operator(packets) => match packet.r#type { + 0 => eval_sum_packets(packets), + 1 => eval_product_packets(packets), + 2 => eval_minimum_packets(packets), + 3 => eval_maximum_packets(packets), + 5 => eval_greater_packets(packets), + 6 => eval_less_packets(packets), + 7 => eval_equal_packets(packets), + _ => unreachable!(), + }, + } } pub fn part2(packet: &Packet) -> u64 { - eval_packet(packet) + eval_packet(packet) } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example_1() { - let packet = parse_input("8A004A801A8002F478"); - let result = part1(&packet); - assert_eq!(result, 16); - } + #[test] + fn part1_example_1() { + let packet = parse_input("8A004A801A8002F478"); + let result = part1(&packet); + assert_eq!(result, 16); + } - #[test] - fn part1_example_2() { - let packet = parse_input("620080001611562C8802118E34"); - let result = part1(&packet); - assert_eq!(result, 12); - } + #[test] + fn part1_example_2() { + let packet = parse_input("620080001611562C8802118E34"); + let result = part1(&packet); + assert_eq!(result, 12); + } - #[test] - fn part1_example_3() { - let packet = parse_input("C0015000016115A2E0802F182340"); - let result = part1(&packet); - assert_eq!(result, 23); - } + #[test] + fn part1_example_3() { + let packet = parse_input("C0015000016115A2E0802F182340"); + let result = part1(&packet); + assert_eq!(result, 23); + } - #[test] - fn part1_example_4() { - let packet = parse_input("A0016C880162017C3686B18A3D4780"); - let result = part1(&packet); - assert_eq!(result, 31); - } + #[test] + fn part1_example_4() { + let packet = parse_input("A0016C880162017C3686B18A3D4780"); + let result = part1(&packet); + assert_eq!(result, 31); + } - #[test] - fn part2_example_1() { - let packet = parse_input("C200B40A82"); - let result = part2(&packet); - assert_eq!(result, 3); - } + #[test] + fn part2_example_1() { + let packet = parse_input("C200B40A82"); + let result = part2(&packet); + assert_eq!(result, 3); + } - #[test] - fn part2_example_2() { - let packet = parse_input("04005AC33890"); - let result = part2(&packet); - assert_eq!(result, 54); - } + #[test] + fn part2_example_2() { + let packet = parse_input("04005AC33890"); + let result = part2(&packet); + assert_eq!(result, 54); + } - #[test] - fn part2_example_3() { - let packet = parse_input("880086C3E88112"); - let result = part2(&packet); - assert_eq!(result, 7); - } + #[test] + fn part2_example_3() { + let packet = parse_input("880086C3E88112"); + let result = part2(&packet); + assert_eq!(result, 7); + } - #[test] - fn part2_example_4() { - let packet = parse_input("CE00C43D881120"); - let result = part2(&packet); - assert_eq!(result, 9); - } + #[test] + fn part2_example_4() { + let packet = parse_input("CE00C43D881120"); + let result = part2(&packet); + assert_eq!(result, 9); + } - #[test] - fn part2_example_5() { - let packet = parse_input("D8005AC2A8F0"); - let result = part2(&packet); - assert_eq!(result, 1); - } + #[test] + fn part2_example_5() { + let packet = parse_input("D8005AC2A8F0"); + let result = part2(&packet); + assert_eq!(result, 1); + } - #[test] - fn part2_example_6() { - let packet = parse_input("F600BC2D8F"); - let result = part2(&packet); - assert_eq!(result, 0); - } + #[test] + fn part2_example_6() { + let packet = parse_input("F600BC2D8F"); + let result = part2(&packet); + assert_eq!(result, 0); + } - #[test] - fn part2_example_7() { - let packet = parse_input("9C005AC2F8F0"); - let result = part2(&packet); - assert_eq!(result, 0); - } + #[test] + fn part2_example_7() { + let packet = parse_input("9C005AC2F8F0"); + let result = part2(&packet); + assert_eq!(result, 0); + } - #[test] - fn part2_example_8() { - let packet = parse_input("9C0141080250320F1802104A08"); - let result = part2(&packet); - assert_eq!(result, 1); - } + #[test] + fn part2_example_8() { + let packet = parse_input("9C0141080250320F1802104A08"); + let result = part2(&packet); + assert_eq!(result, 1); + } } - diff --git a/src/day17.rs b/src/day17.rs index 5d5d11d..0f6afd3 100644 --- a/src/day17.rs +++ b/src/day17.rs @@ -1,102 +1,108 @@ - pub struct Rect { - x0: i32, x1: i32, - y0: i32, y1: i32, + x0: i32, + x1: i32, + y0: i32, + y1: i32, } pub fn parse_input(input: &str) -> Rect { - let (x_part, y_part) = input.strip_suffix("\n") - .or(Some(input)) - .unwrap() - .strip_prefix("target area: ") - .unwrap() - .split_once(", ") - .unwrap(); - let (x0, x1) = x_part[2..].split_once("..").unwrap(); - let (y0, y1) = y_part[2..].split_once("..").unwrap(); - return Rect { - x0: x0.parse().unwrap(), - x1: x1.parse().unwrap(), - y0: y0.parse().unwrap(), - y1: y1.parse().unwrap() - } + let (x_part, y_part) = input + .strip_suffix("\n") + .or(Some(input)) + .unwrap() + .strip_prefix("target area: ") + .unwrap() + .split_once(", ") + .unwrap(); + let (x0, x1) = x_part[2..].split_once("..").unwrap(); + let (y0, y1) = y_part[2..].split_once("..").unwrap(); + return Rect { + x0: x0.parse().unwrap(), + x1: x1.parse().unwrap(), + y0: y0.parse().unwrap(), + y1: y1.parse().unwrap(), + }; } fn sign(x: i32) -> i32 { - if x > 0 { 1 } else if x < 0 { -1 } else { 0 } + if x > 0 { + 1 + } else if x < 0 { + -1 + } else { + 0 + } } fn is_overshot(px: i32, py: i32, target: &Rect) -> bool { - px > target.x1 || py < target.y0 + px > target.x1 || py < target.y0 } fn is_in_rect(px: i32, py: i32, target: &Rect) -> bool { - target.x0 <= px && px <= target.x1 && - target.y0 <= py && py <= target.y1 + target.x0 <= px && px <= target.x1 && target.y0 <= py && py <= target.y1 } fn simulate(target: &Rect, initial_vx: i32, initial_vy: i32) -> i32 { - let mut px = 0; - let mut py = 0; - let mut vx = initial_vx; - let mut vy = initial_vy; - let mut maxy = 0; + let mut px = 0; + let mut py = 0; + let mut vx = initial_vx; + let mut vy = initial_vy; + let mut maxy = 0; - while !is_overshot(px, py, target) { - px += vx; - py += vy; + while !is_overshot(px, py, target) { + px += vx; + py += vy; - if is_in_rect(px, py, target) { - return maxy; - } - - maxy = maxy.max(py); + if is_in_rect(px, py, target) { + return maxy; + } - vx -= sign(vx); - vy -= 1; - } + maxy = maxy.max(py); - return -1; + vx -= sign(vx); + vy -= 1; + } + + return -1; } pub fn part1(target: &Rect) -> i32 { - let mut maxy = 0; - for vx in 0..target.x1 { - for vy in target.y0..-target.y0 { - maxy = maxy.max(simulate(target, vx, vy)); - } - } - return maxy; + let mut maxy = 0; + for vx in 0..target.x1 { + for vy in target.y0..-target.y0 { + maxy = maxy.max(simulate(target, vx, vy)); + } + } + return maxy; } pub fn part2(target: &Rect) -> i32 { - let mut count = 0; - for vx in 0..=target.x1 { - for vy in target.y0..-target.y0 { - if simulate(target, vx, vy) >= 0 { - count += 1; - } - } - } - return count; + let mut count = 0; + for vx in 0..=target.x1 { + for vy in target.y0..-target.y0 { + if simulate(target, vx, vy) >= 0 { + count += 1; + } + } + } + return count; } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let target = parse_input("target area: x=20..30, y=-10..-5"); - let result = part1(&target); - assert_eq!(result, 45); - } + #[test] + fn part1_example() { + let target = parse_input("target area: x=20..30, y=-10..-5"); + let result = part1(&target); + assert_eq!(result, 45); + } - #[test] - fn part2_example() { - let target = parse_input("target area: x=20..30, y=-10..-5"); - let result = part2(&target); - assert_eq!(result, 112); - } + #[test] + fn part2_example() { + let target = parse_input("target area: x=20..30, y=-10..-5"); + let result = part2(&target); + assert_eq!(result, 112); + } } - diff --git a/src/day18.rs b/src/day18.rs index 100e46c..aefac3a 100644 --- a/src/day18.rs +++ b/src/day18.rs @@ -1,136 +1,143 @@ // Solution gotten from: https://github.com/AxlLind/AdventOfCode2021/blob/main/src/bin/18.rs fn parse_snailfish(line: &str) -> Vec<(i32, u8)> { - let mut depth = 0; - let mut nums = Vec::new(); - for c in line.chars() { - match c { - '[' => depth += 1, - ']' => depth -= 1, - ',' => {}, - _ => nums.push(((c as u8 - b'0') as i32, depth)) - } - } - return nums; + let mut depth = 0; + let mut nums = Vec::new(); + for c in line.chars() { + match c { + '[' => depth += 1, + ']' => depth -= 1, + ',' => {} + _ => nums.push(((c as u8 - b'0') as i32, depth)), + } + } + return nums; } fn find_deepest_index(num: &Vec<(i32, u8)>) -> usize { - let mut deepest_index = 0; - let mut deepest_depth = 0; - for i in 0..num.len() { - let depth = num[i].1; - if deepest_depth < depth { - deepest_depth = depth; - deepest_index = i; - } - } - return deepest_index; + let mut deepest_index = 0; + let mut deepest_depth = 0; + for i in 0..num.len() { + let depth = num[i].1; + if deepest_depth < depth { + deepest_depth = depth; + deepest_index = i; + } + } + return deepest_index; } pub fn parse_input(input: &str) -> Vec> { - let mut nums = Vec::new(); - for line in input.lines() { - nums.push(parse_snailfish(line)); - } - return nums; + let mut nums = Vec::new(); + for line in input.lines() { + nums.push(parse_snailfish(line)); + } + return nums; } fn add_snailfish(a: &Vec<(i32, u8)>, b: &Vec<(i32, u8)>) -> Vec<(i32, u8)> { - let mut added = Vec::new(); - for (num, depth) in a { - added.push((*num, depth+1)); - } - for (num, depth) in b { - added.push((*num, depth+1)); - } - return added; + let mut added = Vec::new(); + for (num, depth) in a { + added.push((*num, depth + 1)); + } + for (num, depth) in b { + added.push((*num, depth + 1)); + } + return added; } fn try_exploding(num: &mut Vec<(i32, u8)>) -> bool { - let i = find_deepest_index(num); - if num[i].1 < 5 { return false; } - let (left_num, depth) = num[i]; - let right_num = num.remove(i+1).0; - if i > 0 { - num[i-1].0 += left_num; - } - if i+1 < num.len() { - num[i+1].0 += right_num; - } - num[i] = (0, depth-1); - return true; + let i = find_deepest_index(num); + if num[i].1 < 5 { + return false; + } + let (left_num, depth) = num[i]; + let right_num = num.remove(i + 1).0; + if i > 0 { + num[i - 1].0 += left_num; + } + if i + 1 < num.len() { + num[i + 1].0 += right_num; + } + num[i] = (0, depth - 1); + return true; } fn try_splitting(num: &mut Vec<(i32, u8)>) -> bool { - let target = match num.iter().position(|&(n,_)| n > 9) { - Some(i) => i, - None => return false, - }; - let (x, depth) = num[target]; - num[target] = (x/2, depth+1); - num.insert(target+1, ((x+1)/2, depth+1)); - return true; + let target = match num.iter().position(|&(n, _)| n > 9) { + Some(i) => i, + None => return false, + }; + let (x, depth) = num[target]; + num[target] = (x / 2, depth + 1); + num.insert(target + 1, ((x + 1) / 2, depth + 1)); + return true; } fn reduce_snailfish(num: &mut Vec<(i32, u8)>) { - loop { - if try_exploding(num) { continue; } - if try_splitting(num) { continue; } - break; - } + loop { + if try_exploding(num) { + continue; + } + if try_splitting(num) { + continue; + } + break; + } } fn get_magnitude(mut num: Vec<(i32, u8)>) -> i32 { - while num.len() > 1 { - let i = find_deepest_index(&num); - let (left_num, depth) = num[i]; - let right_num = num[i+1].0; - num[i] = (3*left_num + 2*right_num, depth-1); - num.remove(i+1); - } - num[0].0 + while num.len() > 1 { + let i = find_deepest_index(&num); + let (left_num, depth) = num[i]; + let right_num = num[i + 1].0; + num[i] = (3 * left_num + 2 * right_num, depth - 1); + num.remove(i + 1); + } + num[0].0 } fn add_and_reduce(a: &Vec<(i32, u8)>, b: &Vec<(i32, u8)>) -> Vec<(i32, u8)> { - let mut result = add_snailfish(a, b); - reduce_snailfish(&mut result); - return result; + let mut result = add_snailfish(a, b); + reduce_snailfish(&mut result); + return result; } fn sum(nums: &Vec>) -> Vec<(i32, u8)> { - let mut result = nums[0].clone(); - for i in 1..nums.len() { - result = add_snailfish(&result, &nums[i]); - reduce_snailfish(&mut result); - } - return result; + let mut result = nums[0].clone(); + for i in 1..nums.len() { + result = add_snailfish(&result, &nums[i]); + reduce_snailfish(&mut result); + } + return result; } pub fn part1(nums: &Vec>) -> i32 { - return get_magnitude(sum(nums)); + return get_magnitude(sum(nums)); } pub fn part2(nums: &Vec>) -> i32 { - let mut max_magnitude = 0; - let n = nums.len(); - for i in 0..n { - for j in 0..n-1 { - let a = &nums[i]; - let b = &nums[j]; - max_magnitude = max_magnitude.max(get_magnitude(add_and_reduce(a, b))); - max_magnitude = max_magnitude.max(get_magnitude(add_and_reduce(b, a))); - } - } - return max_magnitude; + let mut max_magnitude = 0; + let n = nums.len(); + for i in 0..n { + for j in 0..n - 1 { + let a = &nums[i]; + let b = &nums[j]; + max_magnitude = max_magnitude.max(get_magnitude(add_and_reduce(a, b))); + max_magnitude = max_magnitude.max(get_magnitude(add_and_reduce(b, a))); + } + } + return max_magnitude; } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let nums = parse_input("[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]] + #[test] + fn part1_example() { + let nums = parse_input( + "[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]] [[[5,[2,8]],4],[5,[[9,9],0]]] [6,[[[6,2],[5,6]],[[7,6],[4,7]]]] [[[6,[0,7]],[0,9]],[4,[9,[9,0]]]] @@ -139,14 +146,16 @@ mod tests { [[[[5,4],[7,7]],8],[[8,3],8]] [[9,3],[[9,9],[6,[4,9]]]] [[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]] -[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]"); - let result = part1(&nums); - assert_eq!(result, 4140); - } +[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]", + ); + let result = part1(&nums); + assert_eq!(result, 4140); + } - #[test] - fn part2_example() { - let nums = parse_input("[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]] + #[test] + fn part2_example() { + let nums = parse_input( + "[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]] [[[5,[2,8]],4],[5,[[9,9],0]]] [6,[[[6,2],[5,6]],[[7,6],[4,7]]]] [[[6,[0,7]],[0,9]],[4,[9,[9,0]]]] @@ -155,124 +164,118 @@ mod tests { [[[[5,4],[7,7]],8],[[8,3],8]] [[9,3],[[9,9],[6,[4,9]]]] [[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]] -[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]"); - let result = part2(&nums); - assert_eq!(result, 3993); - } +[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]", + ); + let result = part2(&nums); + assert_eq!(result, 3993); + } - fn test_explosion(initial: &str, expected: &str) { - let mut num = parse_snailfish(initial); - try_exploding(&mut num); - assert_eq!(num, parse_snailfish(expected)); - } + fn test_explosion(initial: &str, expected: &str) { + let mut num = parse_snailfish(initial); + try_exploding(&mut num); + assert_eq!(num, parse_snailfish(expected)); + } - #[test] - fn exploding_1() { - test_explosion("[[[[[9,8],1],2],3],4]", "[[[[0,9],2],3],4]"); - } - #[test] - fn exploding_2() { - test_explosion("[7,[6,[5,[4,[3,2]]]]]", "[7,[6,[5,[7,0]]]]"); - } - #[test] - fn exploding_3() { - test_explosion("[[6,[5,[4,[3,2]]]],1]", "[[6,[5,[7,0]]],3]"); - } - #[test] - fn exploding_4() { - test_explosion("[[3,[2,[1,[7,3]]]],[6,[5,[4,[3,2]]]]]", "[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]]"); - } - #[test] - fn exploding_5() { - test_explosion("[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]]", "[[3,[2,[8,0]]],[9,[5,[7,0]]]]"); - } + #[test] + fn exploding_1() { + test_explosion("[[[[[9,8],1],2],3],4]", "[[[[0,9],2],3],4]"); + } + #[test] + fn exploding_2() { + test_explosion("[7,[6,[5,[4,[3,2]]]]]", "[7,[6,[5,[7,0]]]]"); + } + #[test] + fn exploding_3() { + test_explosion("[[6,[5,[4,[3,2]]]],1]", "[[6,[5,[7,0]]],3]"); + } + #[test] + fn exploding_4() { + test_explosion( + "[[3,[2,[1,[7,3]]]],[6,[5,[4,[3,2]]]]]", + "[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]]", + ); + } + #[test] + fn exploding_5() { + test_explosion( + "[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]]", + "[[3,[2,[8,0]]],[9,[5,[7,0]]]]", + ); + } - fn test_sum(nums: Vec<&str>, expected: &str) { - let mut parsed_nums = Vec::new(); - for num in nums { - parsed_nums.push(parse_snailfish(num)); - } - assert_eq!(sum(&parsed_nums), parse_snailfish(expected)); - } + fn test_sum(nums: Vec<&str>, expected: &str) { + let mut parsed_nums = Vec::new(); + for num in nums { + parsed_nums.push(parse_snailfish(num)); + } + assert_eq!(sum(&parsed_nums), parse_snailfish(expected)); + } - #[test] - fn sum_1() { - let nums = vec![ - "[1,1]", - "[2,2]", - "[3,3]", - "[4,4]" - ]; - test_sum(nums, "[[[[1,1],[2,2]],[3,3]],[4,4]]"); - } - #[test] - fn sum_2() { - let nums = vec![ - "[1,1]", - "[2,2]", - "[3,3]", - "[4,4]", - "[5,5]" - ]; - test_sum(nums, "[[[[3,0],[5,3]],[4,4]],[5,5]]"); - } - #[test] - fn sum_3() { - let nums = vec![ - "[1,1]", - "[2,2]", - "[3,3]", - "[4,4]", - "[5,5]", - "[6,6]", - ]; - test_sum(nums, "[[[[5,0],[7,4]],[5,5]],[6,6]]"); - } - #[test] - fn sum_4() { - let nums = vec![ - "[[[0,[4,5]],[0,0]],[[[4,5],[2,6]],[9,5]]]", - "[7,[[[3,7],[4,3]],[[6,3],[8,8]]]]", - "[[2,[[0,8],[3,4]]],[[[6,7],1],[7,[1,6]]]]", - "[[[[2,4],7],[6,[0,5]]],[[[6,8],[2,8]],[[2,1],[4,5]]]]", - "[7,[5,[[3,8],[1,4]]]]", - "[[2,[2,2]],[8,[8,1]]]", - "[2,9]", - "[1,[[[9,3],9],[[9,0],[0,7]]]]", - "[[[5,[7,4]],7],1]", - "[[[[4,2],2],6],[8,7]]" - ]; - test_sum(nums, "[[[[8,7],[7,7]],[[8,6],[7,7]]],[[[0,7],[6,6]],[8,7]]]"); - } + #[test] + fn sum_1() { + let nums = vec!["[1,1]", "[2,2]", "[3,3]", "[4,4]"]; + test_sum(nums, "[[[[1,1],[2,2]],[3,3]],[4,4]]"); + } + #[test] + fn sum_2() { + let nums = vec!["[1,1]", "[2,2]", "[3,3]", "[4,4]", "[5,5]"]; + test_sum(nums, "[[[[3,0],[5,3]],[4,4]],[5,5]]"); + } + #[test] + fn sum_3() { + let nums = vec!["[1,1]", "[2,2]", "[3,3]", "[4,4]", "[5,5]", "[6,6]"]; + test_sum(nums, "[[[[5,0],[7,4]],[5,5]],[6,6]]"); + } + #[test] + fn sum_4() { + let nums = vec![ + "[[[0,[4,5]],[0,0]],[[[4,5],[2,6]],[9,5]]]", + "[7,[[[3,7],[4,3]],[[6,3],[8,8]]]]", + "[[2,[[0,8],[3,4]]],[[[6,7],1],[7,[1,6]]]]", + "[[[[2,4],7],[6,[0,5]]],[[[6,8],[2,8]],[[2,1],[4,5]]]]", + "[7,[5,[[3,8],[1,4]]]]", + "[[2,[2,2]],[8,[8,1]]]", + "[2,9]", + "[1,[[[9,3],9],[[9,0],[0,7]]]]", + "[[[5,[7,4]],7],1]", + "[[[[4,2],2],6],[8,7]]", + ]; + test_sum( + nums, + "[[[[8,7],[7,7]],[[8,6],[7,7]]],[[[0,7],[6,6]],[8,7]]]", + ); + } - fn test_magnitude(initial: &str, expected: i32) { - let num = parse_snailfish(initial); - assert_eq!(get_magnitude(num), expected); - } + fn test_magnitude(initial: &str, expected: i32) { + let num = parse_snailfish(initial); + assert_eq!(get_magnitude(num), expected); + } - #[test] - fn magnitude_1() { - test_magnitude("[[1,2],[[3,4],5]]", 143); - } - #[test] - fn magnitude_2() { - test_magnitude("[[[[0,7],4],[[7,8],[6,0]]],[8,1]]", 1384); - } - #[test] - fn magnitude_3() { - test_magnitude("[[[[1,1],[2,2]],[3,3]],[4,4]]", 445); - } - #[test] - fn magnitude_4() { - test_magnitude("[[[[3,0],[5,3]],[4,4]],[5,5]]", 791); - } - #[test] - fn magnitude_5() { - test_magnitude("[[[[5,0],[7,4]],[5,5]],[6,6]]", 1137); - } - #[test] - fn magnitude_6() { - test_magnitude("[[[[8,7],[7,7]],[[8,6],[7,7]]],[[[0,7],[6,6]],[8,7]]]", 3488); - } + #[test] + fn magnitude_1() { + test_magnitude("[[1,2],[[3,4],5]]", 143); + } + #[test] + fn magnitude_2() { + test_magnitude("[[[[0,7],4],[[7,8],[6,0]]],[8,1]]", 1384); + } + #[test] + fn magnitude_3() { + test_magnitude("[[[[1,1],[2,2]],[3,3]],[4,4]]", 445); + } + #[test] + fn magnitude_4() { + test_magnitude("[[[[3,0],[5,3]],[4,4]],[5,5]]", 791); + } + #[test] + fn magnitude_5() { + test_magnitude("[[[[5,0],[7,4]],[5,5]],[6,6]]", 1137); + } + #[test] + fn magnitude_6() { + test_magnitude( + "[[[[8,7],[7,7]],[[8,6],[7,7]]],[[[0,7],[6,6]],[8,7]]]", + 3488, + ); + } } - diff --git a/src/day2.rs b/src/day2.rs index c1ab121..e55ff74 100644 --- a/src/day2.rs +++ b/src/day2.rs @@ -2,96 +2,93 @@ use std::num::ParseIntError; #[derive(Debug)] pub enum ParseCommandError { - ParseEnumError, - ParseIntError(ParseIntError), + ParseEnumError, + ParseIntError(ParseIntError), } pub enum CommandType { - Forward, - Down, - Up + Forward, + Down, + Up, } pub struct Command(CommandType, u32); fn parse_line(line: &str) -> Result { - let parts: Vec<&str> = line.split(' ').collect(); - let command = match parts[0] { - "up" => Ok(CommandType::Up), - "down" => Ok(CommandType::Down), - "forward" => Ok(CommandType::Forward), - _ => Err(ParseCommandError::ParseEnumError) - }?; - let amount = parts[1].parse().map_err(ParseCommandError::ParseIntError)?; - Ok(Command(command, amount)) + let parts: Vec<&str> = line.split(' ').collect(); + let command = match parts[0] { + "up" => Ok(CommandType::Up), + "down" => Ok(CommandType::Down), + "forward" => Ok(CommandType::Forward), + _ => Err(ParseCommandError::ParseEnumError), + }?; + let amount = parts[1].parse().map_err(ParseCommandError::ParseIntError)?; + Ok(Command(command, amount)) } pub fn parse_input(input: &str) -> Result, ParseCommandError> { - input.split_terminator('\n') - .map(parse_line) - .collect() + input.split_terminator('\n').map(parse_line).collect() } pub fn part1(commands: &[Command]) -> u32 { - let mut depth = 0; - let mut horizontal = 0; - for command in commands { - match command.0 { - CommandType::Up => depth -= command.1, - CommandType::Down => depth += command.1, - CommandType::Forward => horizontal += command.1, - } - } - return depth * horizontal; + let mut depth = 0; + let mut horizontal = 0; + for command in commands { + match command.0 { + CommandType::Up => depth -= command.1, + CommandType::Down => depth += command.1, + CommandType::Forward => horizontal += command.1, + } + } + return depth * horizontal; } pub fn part2(commands: &[Command]) -> u32 { - let mut depth = 0; - let mut horizontal = 0; - let mut aim = 0; - for command in commands { - match command.0 { - CommandType::Up => aim -= command.1, - CommandType::Down => aim += command.1, - CommandType::Forward => { - horizontal += command.1; - depth += aim * command.1; - } - } - } - return depth * horizontal; + let mut depth = 0; + let mut horizontal = 0; + let mut aim = 0; + for command in commands { + match command.0 { + CommandType::Up => aim -= command.1, + CommandType::Down => aim += command.1, + CommandType::Forward => { + horizontal += command.1; + depth += aim * command.1; + } + } + } + return depth * horizontal; } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let commands = [ - Command(CommandType::Forward, 5), - Command(CommandType::Down, 5), - Command(CommandType::Forward, 8), - Command(CommandType::Up, 3), - Command(CommandType::Down, 8), - Command(CommandType::Forward, 2) - ]; - let result = part1(&commands); - assert_eq!(result, 150); - } + #[test] + fn part1_example() { + let commands = [ + Command(CommandType::Forward, 5), + Command(CommandType::Down, 5), + Command(CommandType::Forward, 8), + Command(CommandType::Up, 3), + Command(CommandType::Down, 8), + Command(CommandType::Forward, 2), + ]; + let result = part1(&commands); + assert_eq!(result, 150); + } - #[test] - fn part2_example() { - let commands = [ - Command(CommandType::Forward, 5), - Command(CommandType::Down, 5), - Command(CommandType::Forward, 8), - Command(CommandType::Up, 3), - Command(CommandType::Down, 8), - Command(CommandType::Forward, 2) - ]; - let result = part2(&commands); - assert_eq!(result, 900) - } + #[test] + fn part2_example() { + let commands = [ + Command(CommandType::Forward, 5), + Command(CommandType::Down, 5), + Command(CommandType::Forward, 8), + Command(CommandType::Up, 3), + Command(CommandType::Down, 8), + Command(CommandType::Forward, 2), + ]; + let result = part2(&commands); + assert_eq!(result, 900) + } } - diff --git a/src/day20.rs b/src/day20.rs index dc28ad8..ae75b4a 100644 --- a/src/day20.rs +++ b/src/day20.rs @@ -1,235 +1,236 @@ -use std::{ops::Range, fmt::Display}; - +use std::{fmt::Display, ops::Range}; #[derive(Clone, Debug)] pub struct Image { - width: usize, - height: usize, - data: Vec, - default_value: bool, - offset_x: i32, - offset_y: i32 + width: usize, + height: usize, + data: Vec, + default_value: bool, + offset_x: i32, + offset_y: i32, } impl Image { - fn new(width: usize, height: usize) -> Image { - let data = vec![false; width*height]; - Image { - width, - height, - data, - default_value: false, - offset_x: 0, - offset_y: 0 - } - } + fn new(width: usize, height: usize) -> Image { + let data = vec![false; width * height]; + Image { + width, + height, + data, + default_value: false, + offset_x: 0, + offset_y: 0, + } + } - fn get(&self, x: i32, y: i32) -> bool { - if self.in_bounds(x, y) { - let index = (y + self.offset_y) * self.width as i32 + (x + self.offset_x); - *self.data.get(index as usize).unwrap_or(&self.default_value) - } else { - self.default_value - } - } + fn get(&self, x: i32, y: i32) -> bool { + if self.in_bounds(x, y) { + let index = (y + self.offset_y) * self.width as i32 + (x + self.offset_x); + *self.data.get(index as usize).unwrap_or(&self.default_value) + } else { + self.default_value + } + } - fn set(&mut self, x: i32, y: i32, value: bool) { - // Make image larger if it is too small - let (left, top, right, bottom) = self.bounds(); - if !(left <= x && x < right && top <= y && y < bottom) { - if x < left { - self.offset_x = -x; - self.width = self.width + (-x + left) as usize; - } else if x >= right { - self.width = self.width + 1 + (x - right) as usize; - } + fn set(&mut self, x: i32, y: i32, value: bool) { + // Make image larger if it is too small + let (left, top, right, bottom) = self.bounds(); + if !(left <= x && x < right && top <= y && y < bottom) { + if x < left { + self.offset_x = -x; + self.width = self.width + (-x + left) as usize; + } else if x >= right { + self.width = self.width + 1 + (x - right) as usize; + } - if y < top { - self.offset_y = -y; - self.height = self.height + (-y + top) as usize; - } else if y >= bottom { - self.height = self.height + 1 + (y - bottom) as usize; - } + if y < top { + self.offset_y = -y; + self.height = self.height + (-y + top) as usize; + } else if y >= bottom { + self.height = self.height + 1 + (y - bottom) as usize; + } - let mut new_data = Vec::new(); - for y in self.y_range(0) { - for x in self.x_range(0) { - new_data.push(self.get(x, y)); - } - } - self.data = new_data; - } + let mut new_data = Vec::new(); + for y in self.y_range(0) { + for x in self.x_range(0) { + new_data.push(self.get(x, y)); + } + } + self.data = new_data; + } - let index = ((y + self.offset_y) * self.width as i32 + (x + self.offset_x)) as usize; - self.data[index] = value; - } + let index = ((y + self.offset_y) * self.width as i32 + (x + self.offset_x)) as usize; + self.data[index] = value; + } - fn in_bounds(&self, x: i32, y: i32) -> bool { - let (left, top, right, bottom) = self.bounds(); - left <= x && x < right && top <= y && y < bottom - } + fn in_bounds(&self, x: i32, y: i32) -> bool { + let (left, top, right, bottom) = self.bounds(); + left <= x && x < right && top <= y && y < bottom + } - fn count(&self, value: bool) -> usize { - if self.default_value == value { - usize::MAX - } else { - self.data.iter().filter(|x| **x == value).count() - } - } + fn count(&self, value: bool) -> usize { + if self.default_value == value { + usize::MAX + } else { + self.data.iter().filter(|x| **x == value).count() + } + } - fn x_range(&self, padding: u32) -> Range { - let padding = padding as i32; - Range { - start: -self.offset_x - padding, - end: self.width as i32 - self.offset_x + padding - } - } + fn x_range(&self, padding: u32) -> Range { + let padding = padding as i32; + Range { + start: -self.offset_x - padding, + end: self.width as i32 - self.offset_x + padding, + } + } - fn y_range(&self, padding: u32) -> Range { - let padding = padding as i32; - Range { - start: -self.offset_y - padding, - end: self.height as i32 - self.offset_y + padding - } - } + fn y_range(&self, padding: u32) -> Range { + let padding = padding as i32; + Range { + start: -self.offset_y - padding, + end: self.height as i32 - self.offset_y + padding, + } + } - // (i32, i32, i32, i32) => (left, top, right, bottom) - fn bounds(&self) -> (i32, i32, i32, i32) { - return ( - -self.offset_x, - -self.offset_y, - self.width as i32 - self.offset_x, - self.height as i32 - self.offset_y - ); - } + // (i32, i32, i32, i32) => (left, top, right, bottom) + fn bounds(&self) -> (i32, i32, i32, i32) { + return ( + -self.offset_x, + -self.offset_y, + self.width as i32 - self.offset_x, + self.height as i32 - self.offset_y, + ); + } } impl Display for Image { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut grid = String::new(); - for y in self.y_range(1) { - for x in self.x_range(1) { - let symbol = if self.get(x, y) { '#' } else { '.' }; - grid.push(symbol); - } - grid.push('\n'); - } - write!(f, "{}", grid) - } + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut grid = String::new(); + for y in self.y_range(1) { + for x in self.x_range(1) { + let symbol = if self.get(x, y) { '#' } else { '.' }; + grid.push(symbol); + } + grid.push('\n'); + } + write!(f, "{}", grid) + } } fn parse_image(input: &str) -> Image { - let mut image = Image::new(3, 3); - let mut y = 0; - for line in input.lines() { - let mut x = 0; - for c in line.chars() { - image.set(x, y, c == '#'); - x += 1; - } - y += 1 - } - return image; + let mut image = Image::new(3, 3); + let mut y = 0; + for line in input.lines() { + let mut x = 0; + for c in line.chars() { + image.set(x, y, c == '#'); + x += 1; + } + y += 1 + } + return image; } fn parse_enchancer(input: &str) -> [bool; 512] { - let mut enhancer = [false; 512]; - let mut i = 0; - for c in input.chars() { - enhancer[i] = c == '#'; - i+=1; - } - return enhancer + let mut enhancer = [false; 512]; + let mut i = 0; + for c in input.chars() { + enhancer[i] = c == '#'; + i += 1; + } + return enhancer; } pub fn parse_input(input: &str) -> ([bool; 512], Image) { - let (section1, section2) = input.split_once("\n\n").unwrap(); - return ( - parse_enchancer(section1), - parse_image(section2) - ); + let (section1, section2) = input.split_once("\n\n").unwrap(); + return (parse_enchancer(section1), parse_image(section2)); } fn lookup_enhancer(x: i32, y: i32, image: &Image, enhancer: &[bool; 512]) -> bool { - let pixel_offsets = [ - (-1, -1), ( 0, -1), ( 1, -1), - (-1, 0), ( 0, 0), ( 1, 0), - (-1, 1), ( 0, 1), ( 1, 1) - ]; + let pixel_offsets = [ + (-1, -1), + (0, -1), + (1, -1), + (-1, 0), + (0, 0), + (1, 0), + (-1, 1), + (0, 1), + (1, 1), + ]; - let mut lookup_index = 0; - for i in 0..9 { - let (ox, oy) = pixel_offsets[i]; - let pixel = image.get(x + ox, y + oy); - if pixel { - lookup_index += 2usize.pow((8-i) as u32) - } - } + let mut lookup_index = 0; + for i in 0..9 { + let (ox, oy) = pixel_offsets[i]; + let pixel = image.get(x + ox, y + oy); + if pixel { + lookup_index += 2usize.pow((8 - i) as u32) + } + } - enhancer[lookup_index] + enhancer[lookup_index] } fn enhance(image: &Image, enhancer: &[bool; 512]) -> Image { - let mut enhanced = image.clone(); - for y in image.y_range(1) { - for x in image.x_range(1) { - enhanced.set(x, y, lookup_enhancer(x, y, image, enhancer)); - } - } + let mut enhanced = image.clone(); + for y in image.y_range(1) { + for x in image.x_range(1) { + enhanced.set(x, y, lookup_enhancer(x, y, image, enhancer)); + } + } - if image.default_value { - enhanced.default_value = enhancer[511]; - } else { - enhanced.default_value = enhancer[0]; - } + if image.default_value { + enhanced.default_value = enhancer[511]; + } else { + enhanced.default_value = enhancer[0]; + } - enhanced + enhanced } pub fn part1(data: &([bool; 512], Image)) -> usize { - let (enhancer, image) = data; - let mut enhanced_image = enhance(&image, enhancer); - enhanced_image = enhance(&enhanced_image, enhancer); - enhanced_image.count(true) + let (enhancer, image) = data; + let mut enhanced_image = enhance(&image, enhancer); + enhanced_image = enhance(&enhanced_image, enhancer); + enhanced_image.count(true) } pub fn part2(data: &([bool; 512], Image)) -> usize { - let (enhancer, image) = data; - let mut enhanced_image = enhance(&image, enhancer); - for _ in 0..49 { - enhanced_image = enhance(&enhanced_image, enhancer); - } - enhanced_image.count(true) + let (enhancer, image) = data; + let mut enhanced_image = enhance(&image, enhancer); + for _ in 0..49 { + enhanced_image = enhance(&enhanced_image, enhancer); + } + enhanced_image.count(true) } - #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let input = parse_input("..#.#..#####.#.#.#.###.##.....###.##.#..###.####..#####..#....#..#..##..###..######.###...####..#..#####..##..#.#####...##.#.#..#.##..#.#......#.###.######.###.####...#.##.##..#..#..#####.....#.#....###..#.##......#.....#..#..#..##..#...##.######.####.####.#.#...#.......#..#.#.#...####.##.#......#..#...##.#.##..#...##.#.##..###.#......#.#.......#.#.#.####.###.##...#.....####.#..#..#.##.#....##..#.####....##...##..#...#......#.#.......#.......##..####..#...#.#.#...##..#.#..###..#####........#..####......#..# + #[test] + fn part1_example() { + let input = parse_input("..#.#..#####.#.#.#.###.##.....###.##.#..###.####..#####..#....#..#..##..###..######.###...####..#..#####..##..#.#####...##.#.#..#.##..#.#......#.###.######.###.####...#.##.##..#..#..#####.....#.#....###..#.##......#.....#..#..#..##..#...##.######.####.####.#.#...#.......#..#.#.#...####.##.#......#..#...##.#.##..#...##.#.##..###.#......#.#.......#.#.#.####.###.##...#.....####.#..#..#.##.#....##..#.####....##...##..#...#......#.#.......#.......##..####..#...#.#.#...##..#.#..###..#####........#..####......#..# #..#. #.... ##..# ..#.. ..###"); - let result = part1(&input); - assert_eq!(result, 35); - } + let result = part1(&input); + assert_eq!(result, 35); + } - #[test] - fn part2_example() { - let input = parse_input("..#.#..#####.#.#.#.###.##.....###.##.#..###.####..#####..#....#..#..##..###..######.###...####..#..#####..##..#.#####...##.#.#..#.##..#.#......#.###.######.###.####...#.##.##..#..#..#####.....#.#....###..#.##......#.....#..#..#..##..#...##.######.####.####.#.#...#.......#..#.#.#...####.##.#......#..#...##.#.##..#...##.#.##..###.#......#.#.......#.#.#.####.###.##...#.....####.#..#..#.##.#....##..#.####....##...##..#...#......#.#.......#.......##..####..#...#.#.#...##..#.#..###..#####........#..####......#..# + #[test] + fn part2_example() { + let input = parse_input("..#.#..#####.#.#.#.###.##.....###.##.#..###.####..#####..#....#..#..##..###..######.###...####..#..#####..##..#.#####...##.#.#..#.##..#.#......#.###.######.###.####...#.##.##..#..#..#####.....#.#....###..#.##......#.....#..#..#..##..#...##.######.####.####.#.#...#.......#..#.#.#...####.##.#......#..#...##.#.##..#...##.#.##..###.#......#.#.......#.#.#.####.###.##...#.....####.#..#..#.##.#....##..#.####....##...##..#...#......#.#.......#.......##..####..#...#.#.#...##..#.#..###..#####........#..####......#..# #..#. #.... ##..# ..#.. ..###"); - let result = part2(&input); - assert_eq!(result, 3351); - } + let result = part2(&input); + assert_eq!(result, 3351); + } } diff --git a/src/day21.rs b/src/day21.rs index af96bcb..b225da5 100644 --- a/src/day21.rs +++ b/src/day21.rs @@ -1,97 +1,108 @@ use std::collections::HashMap; - pub fn parse_input(input: &str) -> (u8, u8) { - let players: Vec = input.lines() - .map(|l| l.split_once(": ").unwrap().1.parse().unwrap()) - .collect(); - return (players[0], players[1]); + let players: Vec = input + .lines() + .map(|l| l.split_once(": ").unwrap().1.parse().unwrap()) + .collect(); + return (players[0], players[1]); } pub fn part1(starting_positions: &(u8, u8)) -> u32 { - let mut player1_position = starting_positions.0 as u32; - let mut player2_position = starting_positions.1 as u32; - let mut player1_score: u32 = 0; - let mut player2_score: u32 = 0; - let mut rolled_count = 0; + let mut player1_position = starting_positions.0 as u32; + let mut player2_position = starting_positions.1 as u32; + let mut player1_score: u32 = 0; + let mut player2_score: u32 = 0; + let mut rolled_count = 0; - let mut is_player1_turn = true; + let mut is_player1_turn = true; - while player1_score < 1000 && player2_score < 1000 { - let position; - let score; - if is_player1_turn { - position = &mut player1_position; - score = &mut player1_score; - } else { - position = &mut player2_position; - score = &mut player2_score; - } + while player1_score < 1000 && player2_score < 1000 { + let position; + let score; + if is_player1_turn { + position = &mut player1_position; + score = &mut player1_score; + } else { + position = &mut player2_position; + score = &mut player2_score; + } - *position += (rolled_count + 1 - 1) % 100 + 1; - *position += (rolled_count + 2 - 1) % 100 + 1; - *position += (rolled_count + 3 - 1) % 100 + 1; + *position += (rolled_count + 1 - 1) % 100 + 1; + *position += (rolled_count + 2 - 1) % 100 + 1; + *position += (rolled_count + 3 - 1) % 100 + 1; - *position = (*position - 1) % 10 + 1; - *score += *position as u32; + *position = (*position - 1) % 10 + 1; + *score += *position as u32; - rolled_count += 3; - is_player1_turn = !is_player1_turn; - } + rolled_count += 3; + is_player1_turn = !is_player1_turn; + } - player1_score.min(player2_score) * rolled_count as u32 + player1_score.min(player2_score) * rolled_count as u32 } -fn get_wins_amount(starting_pos1: u32, starting_pos2: u32, starting_score1: u32, starting_score2: u32, memo: &mut HashMap<(u32, u32, u32, u32), (u64, u64)>) -> (u64, u64) { - let memo_key = (starting_pos1, starting_pos2, starting_score1, starting_score2); - if memo.contains_key(&memo_key) { - return *memo.get(&memo_key).unwrap() - } - let mut total_wins1 = 0; - let mut total_wins2 = 0; +fn get_wins_amount( + starting_pos1: u32, + starting_pos2: u32, + starting_score1: u32, + starting_score2: u32, + memo: &mut HashMap<(u32, u32, u32, u32), (u64, u64)>, +) -> (u64, u64) { + let memo_key = ( + starting_pos1, + starting_pos2, + starting_score1, + starting_score2, + ); + if memo.contains_key(&memo_key) { + return *memo.get(&memo_key).unwrap(); + } + let mut total_wins1 = 0; + let mut total_wins2 = 0; - for dice1 in 1..=3 { - for dice2 in 1..=3 { - for dice3 in 1..=3 { - let pos1 = (starting_pos1 + dice1 + dice2 + dice3 - 1) % 10 + 1; - let score1 = starting_score1 + pos1; - if score1 >= 21 { - total_wins1 += 1 - } else { - let (wins2, wins1) = get_wins_amount(starting_pos2, pos1, starting_score2, score1, memo); - total_wins1 += wins1; - total_wins2 += wins2; - } - } - } - } + for dice1 in 1..=3 { + for dice2 in 1..=3 { + for dice3 in 1..=3 { + let pos1 = (starting_pos1 + dice1 + dice2 + dice3 - 1) % 10 + 1; + let score1 = starting_score1 + pos1; + if score1 >= 21 { + total_wins1 += 1 + } else { + let (wins2, wins1) = get_wins_amount(starting_pos2, pos1, starting_score2, score1, memo); + total_wins1 += wins1; + total_wins2 += wins2; + } + } + } + } - memo.insert(memo_key, (total_wins1, total_wins2)); + memo.insert(memo_key, (total_wins1, total_wins2)); - (total_wins1, total_wins2) + (total_wins1, total_wins2) } pub fn part2(positions: &(u8, u8)) -> u64 { - let mut memo = HashMap::new(); - let (wins1, wins2) = get_wins_amount(positions.0 as u32, positions.1 as u32, 0, 0, &mut memo); - wins1.max(wins2) + let mut memo = HashMap::new(); + let (wins1, wins2) = get_wins_amount(positions.0 as u32, positions.1 as u32, 0, 0, &mut memo); + wins1.max(wins2) } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let input = (4, 8); - let result = part1(&input); - assert_eq!(result, 739785); - } + #[test] + fn part1_example() { + let input = (4, 8); + let result = part1(&input); + assert_eq!(result, 739785); + } - #[test] - fn part2_example() { - let input = (4, 8); - let result = part2(&input); - assert_eq!(result, 444356092776315); - } + #[test] + fn part2_example() { + let input = (4, 8); + let result = part2(&input); + assert_eq!(result, 444356092776315); + } } diff --git a/src/day22.rs b/src/day22.rs index 0c8b250..469b042 100644 --- a/src/day22.rs +++ b/src/day22.rs @@ -1,17 +1,20 @@ -use std::{convert::{TryFrom, TryInto}, num::ParseIntError, collections::HashSet}; - +use std::{ + collections::HashSet, + convert::{TryFrom, TryInto}, + num::ParseIntError, +}; #[derive(Debug, Clone)] pub struct Cuboid { - x: (i32, i32), - y: (i32, i32), - z: (i32, i32) + x: (i32, i32), + y: (i32, i32), + z: (i32, i32), } #[derive(Debug)] pub enum StepAction { - On, - Off + On, + Off, } #[derive(Debug)] @@ -19,210 +22,216 @@ pub struct RebootStep(StepAction, Cuboid); #[derive(Debug)] pub enum ParseRangeError { - Empty, - BadLen, - ParseInt(ParseIntError) + Empty, + BadLen, + ParseInt(ParseIntError), } #[derive(Debug)] pub enum ParseCuboidError { - Empty, - BadLen, - ParseRange(ParseRangeError) + Empty, + BadLen, + ParseRange(ParseRangeError), } #[derive(Debug)] pub enum ParseRebootStepError { - Empty, - BadLen, - BadAction, - ParseCuboid(ParseCuboidError) + Empty, + BadLen, + BadAction, + ParseCuboid(ParseCuboidError), } impl Cuboid { - fn contains(&self, point: &(i32, i32, i32)) -> bool { - self.x.0 <= point.0 && point.0 <= self.x.1 && - self.y.0 <= point.1 && point.1 <= self.y.1 && - self.z.0 <= point.2 && point.2 <= self.z.1 - } + fn contains(&self, point: &(i32, i32, i32)) -> bool { + self.x.0 <= point.0 + && point.0 <= self.x.1 + && self.y.0 <= point.1 + && point.1 <= self.y.1 + && self.z.0 <= point.2 + && point.2 <= self.z.1 + } - fn clamp(&self, other: &Cuboid) -> Cuboid { - Cuboid { - x: (self.x.0.max(other.x.0), self.x.1.min(other.x.1)), - y: (self.y.0.max(other.y.0), self.y.1.min(other.y.1)), - z: (self.z.0.max(other.z.0), self.z.1.min(other.z.1)), - } - } + fn clamp(&self, other: &Cuboid) -> Cuboid { + Cuboid { + x: (self.x.0.max(other.x.0), self.x.1.min(other.x.1)), + y: (self.y.0.max(other.y.0), self.y.1.min(other.y.1)), + z: (self.z.0.max(other.z.0), self.z.1.min(other.z.1)), + } + } - fn intersection(&self, other: &Cuboid) -> Option { - if self.z.0 > other.z.1 || other.z.0 > self.z.1 { return None; } - if self.y.0 > other.y.1 || other.y.0 > self.y.1 { return None; } - if self.x.0 > other.x.1 || other.x.0 > self.x.1 { return None; } - Some(self.clamp(other)) - } + fn intersection(&self, other: &Cuboid) -> Option { + if self.z.0 > other.z.1 || other.z.0 > self.z.1 { + return None; + } + if self.y.0 > other.y.1 || other.y.0 > self.y.1 { + return None; + } + if self.x.0 > other.x.1 || other.x.0 > self.x.1 { + return None; + } + Some(self.clamp(other)) + } - fn volume(&self) -> u64 { - (self.x.1 - self.x.0 + 1) as u64 * - (self.y.1 - self.y.0 + 1) as u64 * - (self.z.1 - self.z.0 + 1) as u64 - } + fn volume(&self) -> u64 { + (self.x.1 - self.x.0 + 1) as u64 + * (self.y.1 - self.y.0 + 1) as u64 + * (self.z.1 - self.z.0 + 1) as u64 + } } impl From for ParseRangeError { - fn from(e: ParseIntError) -> Self { - ParseRangeError::ParseInt(e) - } + fn from(e: ParseIntError) -> Self { + ParseRangeError::ParseInt(e) + } } impl From for ParseCuboidError { - fn from(e: ParseRangeError) -> Self { - ParseCuboidError::ParseRange(e) - } + fn from(e: ParseRangeError) -> Self { + ParseCuboidError::ParseRange(e) + } } fn parse_range(value: &str) -> Result<(i32, i32), ParseRangeError> { - if value.is_empty() { - return Err(ParseRangeError::Empty); - } - let (start, end) = value[2..] - .split_once("..") - .ok_or(ParseRangeError::BadLen)?; - Ok((start.parse()?, end.parse()?)) + if value.is_empty() { + return Err(ParseRangeError::Empty); + } + let (start, end) = value[2..].split_once("..").ok_or(ParseRangeError::BadLen)?; + Ok((start.parse()?, end.parse()?)) } impl TryFrom<&str> for Cuboid { - type Error = ParseCuboidError; + type Error = ParseCuboidError; - fn try_from(value: &str) -> Result { - if value.is_empty() { - return Err(Self::Error::Empty); - } - let ranges: Vec<_> = value.split(',') - .map(parse_range) - .collect::>()?; - if ranges.len() != 3 { - return Err(Self::Error::BadLen); - } - Ok(Cuboid { - x: ranges[0], - y: ranges[1], - z: ranges[2] - }) - } + fn try_from(value: &str) -> Result { + if value.is_empty() { + return Err(Self::Error::Empty); + } + let ranges: Vec<_> = value + .split(',') + .map(parse_range) + .collect::>()?; + if ranges.len() != 3 { + return Err(Self::Error::BadLen); + } + Ok(Cuboid { + x: ranges[0], + y: ranges[1], + z: ranges[2], + }) + } } impl From for ParseRebootStepError { - fn from(e: ParseCuboidError) -> Self { - ParseRebootStepError::ParseCuboid(e) - } + fn from(e: ParseCuboidError) -> Self { + ParseRebootStepError::ParseCuboid(e) + } } impl TryFrom<&str> for RebootStep { - type Error = ParseRebootStepError; + type Error = ParseRebootStepError; - fn try_from(value: &str) -> Result { - if value.is_empty() { - return Err(Self::Error::Empty); - } - let (action_str, cuboid) = value.split_once(" ").ok_or(Self::Error::BadLen)?; + fn try_from(value: &str) -> Result { + if value.is_empty() { + return Err(Self::Error::Empty); + } + let (action_str, cuboid) = value.split_once(" ").ok_or(Self::Error::BadLen)?; - let action = match action_str { - "on" => StepAction::On, - "off" => StepAction::Off, - _ => return Err(Self::Error::BadAction) - }; + let action = match action_str { + "on" => StepAction::On, + "off" => StepAction::Off, + _ => return Err(Self::Error::BadAction), + }; - Ok(RebootStep(action, cuboid.try_into()?)) - } + Ok(RebootStep(action, cuboid.try_into()?)) + } } pub fn parse_input(input: &str) -> Vec { - input.lines() - .map(|l| l.try_into().unwrap()) - .collect() + input.lines().map(|l| l.try_into().unwrap()).collect() } fn count_cubes_in_cuboid(steps: &[RebootStep], region: &Cuboid) -> u32 { - let mut cubes = HashSet::new(); + let mut cubes = HashSet::new(); - for step in steps { - let clamped = step.1.clamp(region); - for x in clamped.x.0..=clamped.x.1 { - for y in clamped.y.0..=clamped.y.1 { - for z in clamped.z.0..=clamped.z.1 { - let cube = (x, y, z); - match step.0 { - StepAction::On => cubes.insert(cube), - StepAction::Off => cubes.remove(&cube) - }; - } - } - } - } + for step in steps { + let clamped = step.1.clamp(region); + for x in clamped.x.0..=clamped.x.1 { + for y in clamped.y.0..=clamped.y.1 { + for z in clamped.z.0..=clamped.z.1 { + let cube = (x, y, z); + match step.0 { + StepAction::On => cubes.insert(cube), + StepAction::Off => cubes.remove(&cube), + }; + } + } + } + } - cubes.len() as u32 + cubes.len() as u32 } // From: http://twocentstudios.com/2016/08/16/calculating-the-area-of-multiple-intersecting-rectangles-with-swift /* fn total_volume(cuboids: &Vec) -> u64 { - let mut unique_x = HashSet::new(); - let mut unique_y = HashSet::new(); - let mut unique_z = HashSet::new(); - for cuboid in cuboids { - unique_x.insert(cuboid.x.0); - unique_x.insert(cuboid.x.1); - unique_y.insert(cuboid.y.0); - unique_y.insert(cuboid.y.1); - unique_z.insert(cuboid.z.0); - unique_z.insert(cuboid.z.1); - } + let mut unique_x = HashSet::new(); + let mut unique_y = HashSet::new(); + let mut unique_z = HashSet::new(); + for cuboid in cuboids { + unique_x.insert(cuboid.x.0); + unique_x.insert(cuboid.x.1); + unique_y.insert(cuboid.y.0); + unique_y.insert(cuboid.y.1); + unique_z.insert(cuboid.z.0); + unique_z.insert(cuboid.z.1); + } - let mut unique_x: Vec<_> = unique_x.iter().collect(); - let mut unique_y: Vec<_> = unique_y.iter().collect(); - let mut unique_z: Vec<_> = unique_z.iter().collect(); + let mut unique_x: Vec<_> = unique_x.iter().collect(); + let mut unique_y: Vec<_> = unique_y.iter().collect(); + let mut unique_z: Vec<_> = unique_z.iter().collect(); - unique_x.sort(); - unique_y.sort(); - unique_z.sort(); + unique_x.sort(); + unique_y.sort(); + unique_z.sort(); - let mut volume = 0; - for (i, x) in unique_x.iter().enumerate().skip(1) { - for (j, y) in unique_y.iter().enumerate().skip(1) { - for (k, z) in unique_z.iter().enumerate().skip(1) { - let cuboid = Cuboid { - x: (*unique_x[i-1], **x), - y: (*unique_y[j-1], **y), - z: (*unique_z[k-1], **z) - }; - for c in cuboids { - if c.has_overlap(&cuboid) { - volume += cuboid.volume(); - break; - } - } + let mut volume = 0; + for (i, x) in unique_x.iter().enumerate().skip(1) { + for (j, y) in unique_y.iter().enumerate().skip(1) { + for (k, z) in unique_z.iter().enumerate().skip(1) { + let cuboid = Cuboid { + x: (*unique_x[i-1], **x), + y: (*unique_y[j-1], **y), + z: (*unique_z[k-1], **z) + }; + for c in cuboids { + if c.has_overlap(&cuboid) { + volume += cuboid.volume(); + break; + } + } - // let point = ( - // (*unique_x[i-1] + **x)/2, - // (*unique_y[j-1] + **y)/2, - // (*unique_z[k-1] + **z)/2 - // ); - // for c in cuboids { - // if c.contains(&point) { - // let cuboid = Cuboid { - // x: (*unique_x[i-1], **x), - // y: (*unique_y[j-1], **y), - // z: (*unique_z[k-1], **z) - // }; - // volume += cuboid.volume(); - // break; - // } - // } - } - } - } + // let point = ( + // (*unique_x[i-1] + **x)/2, + // (*unique_y[j-1] + **y)/2, + // (*unique_z[k-1] + **z)/2 + // ); + // for c in cuboids { + // if c.contains(&point) { + // let cuboid = Cuboid { + // x: (*unique_x[i-1], **x), + // y: (*unique_y[j-1], **y), + // z: (*unique_z[k-1], **z) + // }; + // volume += cuboid.volume(); + // break; + // } + // } + } + } + } - volume + volume } */ @@ -231,50 +240,51 @@ fn total_volume(cuboids: &Vec) -> u64 { * Based on inclusion-exclusion principle. https://en.wikipedia.org/wiki/Inclusion%E2%80%93exclusion_principle */ fn count_cubes(steps: Vec) -> u64 { - let mut cuboids: Vec<(Cuboid, bool)> = Vec::new(); + let mut cuboids: Vec<(Cuboid, bool)> = Vec::new(); - for step in steps { - let mut extra_cuboids = Vec::new(); - for c in cuboids.iter() { - if let Some(intersect) = step.1.intersection(&c.0) { - extra_cuboids.push((intersect, !c.1)); - } - } + for step in steps { + let mut extra_cuboids = Vec::new(); + for c in cuboids.iter() { + if let Some(intersect) = step.1.intersection(&c.0) { + extra_cuboids.push((intersect, !c.1)); + } + } - if let StepAction::On = step.0 { - cuboids.push((step.1, true)); - } - cuboids.append(&mut extra_cuboids); - } + if let StepAction::On = step.0 { + cuboids.push((step.1, true)); + } + cuboids.append(&mut extra_cuboids); + } - let mut total_volume = 0; - for (cuboid, additive) in cuboids { - let sign: i64 = if additive { 1 } else { -1 }; - total_volume += sign * cuboid.volume() as i64; - } - total_volume as u64 + let mut total_volume = 0; + for (cuboid, additive) in cuboids { + let sign: i64 = if additive { 1 } else { -1 }; + total_volume += sign * cuboid.volume() as i64; + } + total_volume as u64 } pub fn part1(steps: &[RebootStep]) -> u32 { - let region = Cuboid{ - x: (-50, 50), - y: (-50, 50), - z: (-50, 50) - }; - count_cubes_in_cuboid(steps, ®ion) + let region = Cuboid { + x: (-50, 50), + y: (-50, 50), + z: (-50, 50), + }; + count_cubes_in_cuboid(steps, ®ion) } pub fn part2(steps: Vec) -> u64 { - count_cubes(steps) + count_cubes(steps) } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let steps = parse_input("on x=-20..26,y=-36..17,z=-47..7 + #[test] + fn part1_example() { + let steps = parse_input( + "on x=-20..26,y=-36..17,z=-47..7 on x=-20..33,y=-21..23,z=-26..28 on x=-22..28,y=-29..23,z=-38..16 on x=-46..7,y=-6..46,z=-50..-1 @@ -295,14 +305,16 @@ on x=-49..-5,y=-3..45,z=-29..18 off x=18..30,y=-20..-8,z=-3..13 on x=-41..9,y=-7..43,z=-33..15 on x=-54112..-39298,y=-85059..-49293,z=-27449..7877 -on x=967..23432,y=45373..81175,z=27513..53682"); - let result = part1(&steps); - assert_eq!(result, 590784); - } +on x=967..23432,y=45373..81175,z=27513..53682", + ); + let result = part1(&steps); + assert_eq!(result, 590784); + } - #[test] - fn part2_example() { - let steps = parse_input("on x=-5..47,y=-31..22,z=-19..33 + #[test] + fn part2_example() { + let steps = parse_input( + "on x=-5..47,y=-31..22,z=-19..33 on x=-44..5,y=-27..21,z=-14..35 on x=-49..-1,y=-11..42,z=-10..38 on x=-20..34,y=-40..6,z=-44..1 @@ -361,8 +373,9 @@ off x=-37810..49457,y=-71013..-7894,z=-105357..-13188 off x=-27365..46395,y=31009..98017,z=15428..76570 off x=-70369..-16548,y=22648..78696,z=-1892..86821 on x=-53470..21291,y=-120233..-33476,z=-44150..38147 -off x=-93533..-4276,y=-16170..68771,z=-104985..-24507"); - let result = part2(steps); - assert_eq!(result, 2758514936282235); - } +off x=-93533..-4276,y=-16170..68771,z=-104985..-24507", + ); + let result = part2(steps); + assert_eq!(result, 2758514936282235); + } } diff --git a/src/day3.rs b/src/day3.rs index 35900b4..631adb6 100644 --- a/src/day3.rs +++ b/src/day3.rs @@ -1,103 +1,123 @@ use std::{num::ParseIntError, slice::Iter}; pub fn parse_input(input: &str) -> Result, ParseIntError> { - input.split_whitespace() - .map(|s| i32::from_str_radix(s, 2)) - .collect() + input + .split_whitespace() + .map(|s| i32::from_str_radix(s, 2)) + .collect() } fn calculate_max_bits(nums: &[i32]) -> u32 { - let mut max_bits = 0; - for num in nums { - max_bits = max_bits.max((*num as f32).log2().ceil() as u32); - } - return max_bits; + let mut max_bits = 0; + for num in nums { + max_bits = max_bits.max((*num as f32).log2().ceil() as u32); + } + return max_bits; } fn count_bits(nums: Iter, power: &i32) -> u32 { - let mut bits = 0; - for num in nums { - if num & power > 0 { - bits += 1; - } - } - return bits; + let mut bits = 0; + for num in nums { + if num & power > 0 { + bits += 1; + } + } + return bits; } pub fn part1(diagnostics: &[i32]) -> i32 { - let n = diagnostics.len() as u32; - let mut gamma = 0; - let mut epsilon = 0; + let n = diagnostics.len() as u32; + let mut gamma = 0; + let mut epsilon = 0; - let max_bits = calculate_max_bits(&diagnostics); - let mut power = 1; - for _ in 1..=max_bits { - let bits = count_bits(diagnostics.iter(), &power); - if 2*bits >= n { - gamma += power; - } else { - epsilon += power; - } - power *= 2; - } + let max_bits = calculate_max_bits(&diagnostics); + let mut power = 1; + for _ in 1..=max_bits { + let bits = count_bits(diagnostics.iter(), &power); + if 2 * bits >= n { + gamma += power; + } else { + epsilon += power; + } + power *= 2; + } - return gamma * epsilon; + return gamma * epsilon; } pub fn part2(diagnostics: &[i32]) -> i32 { - let mut carbon_diagnostics = Vec::new(); - let mut oxygen_diagnostics = Vec::new(); + let mut carbon_diagnostics = Vec::new(); + let mut oxygen_diagnostics = Vec::new(); - carbon_diagnostics.extend_from_slice(diagnostics); - oxygen_diagnostics.extend_from_slice(diagnostics); + carbon_diagnostics.extend_from_slice(diagnostics); + oxygen_diagnostics.extend_from_slice(diagnostics); - let max_bits = calculate_max_bits(&diagnostics); - let mut power = 2i32.pow(max_bits-1); - for _ in 1..=max_bits { - let oxygen_len = oxygen_diagnostics.len() as u32; - if oxygen_len > 1 { - let bit_count = count_bits(oxygen_diagnostics.iter(), &power); - if 2*bit_count >= oxygen_len { - oxygen_diagnostics = oxygen_diagnostics.into_iter().filter(|n| n & power > 0).collect(); - } else { - oxygen_diagnostics = oxygen_diagnostics.into_iter().filter(|n| n & power == 0).collect(); - } - } + let max_bits = calculate_max_bits(&diagnostics); + let mut power = 2i32.pow(max_bits - 1); + for _ in 1..=max_bits { + let oxygen_len = oxygen_diagnostics.len() as u32; + if oxygen_len > 1 { + let bit_count = count_bits(oxygen_diagnostics.iter(), &power); + if 2 * bit_count >= oxygen_len { + oxygen_diagnostics = oxygen_diagnostics + .into_iter() + .filter(|n| n & power > 0) + .collect(); + } else { + oxygen_diagnostics = oxygen_diagnostics + .into_iter() + .filter(|n| n & power == 0) + .collect(); + } + } - let carbon_len = carbon_diagnostics.len() as u32; - if carbon_len > 1 { - let bit_count = count_bits(carbon_diagnostics.iter(), &power); - if 2*bit_count < carbon_len { - carbon_diagnostics = carbon_diagnostics.into_iter().filter(|n| n & power > 0).collect(); - } else { - carbon_diagnostics = carbon_diagnostics.into_iter().filter(|n| n & power == 0).collect(); - } - } + let carbon_len = carbon_diagnostics.len() as u32; + if carbon_len > 1 { + let bit_count = count_bits(carbon_diagnostics.iter(), &power); + if 2 * bit_count < carbon_len { + carbon_diagnostics = carbon_diagnostics + .into_iter() + .filter(|n| n & power > 0) + .collect(); + } else { + carbon_diagnostics = carbon_diagnostics + .into_iter() + .filter(|n| n & power == 0) + .collect(); + } + } - if oxygen_len == 1 && carbon_len == 1 { break; } + if oxygen_len == 1 && carbon_len == 1 { + break; + } - power /= 2; - } + power /= 2; + } - return carbon_diagnostics[0] * oxygen_diagnostics[0]; + return carbon_diagnostics[0] * oxygen_diagnostics[0]; } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let diagnostics = [0b00100, 0b11110, 0b10110, 0b10111, 0b10101, 0b01111, 0b00111, 0b11100, 0b10000, 0b11001, 0b00010, 0b01010]; - let result = part1(&diagnostics); - assert_eq!(result, 198); - } + #[test] + fn part1_example() { + let diagnostics = [ + 0b00100, 0b11110, 0b10110, 0b10111, 0b10101, 0b01111, 0b00111, 0b11100, 0b10000, 0b11001, + 0b00010, 0b01010, + ]; + let result = part1(&diagnostics); + assert_eq!(result, 198); + } - #[test] - fn part2_example() { - let diagnostics = [0b00100, 0b11110, 0b10110, 0b10111, 0b10101, 0b01111, 0b00111, 0b11100, 0b10000, 0b11001, 0b00010, 0b01010]; - let result = part2(&diagnostics); - assert_eq!(result, 230); - } + #[test] + fn part2_example() { + let diagnostics = [ + 0b00100, 0b11110, 0b10110, 0b10111, 0b10101, 0b01111, 0b00111, 0b11100, 0b10000, 0b11001, + 0b00010, 0b01010, + ]; + let result = part2(&diagnostics); + assert_eq!(result, 230); + } } - diff --git a/src/day4.rs b/src/day4.rs index 7db293c..b1dc1a8 100644 --- a/src/day4.rs +++ b/src/day4.rs @@ -1,229 +1,217 @@ use std::num::ParseIntError; - #[derive(Debug)] pub struct BingoGame { - numbers: Vec, - boards: Vec<[i32; 25]> + numbers: Vec, + boards: Vec<[i32; 25]>, } #[derive(Debug)] pub enum ParseBingoGameError { - NoNumbersError, - ParseNumberError(ParseIntError), + NoNumbersError, + ParseNumberError(ParseIntError), } pub fn parse_input(input: &str) -> Result { - let mut sections = input.split_terminator("\n\n"); + let mut sections = input.split_terminator("\n\n"); - let numbers_section = sections - .next() - .ok_or(ParseBingoGameError::NoNumbersError)?; + let numbers_section = sections.next().ok_or(ParseBingoGameError::NoNumbersError)?; - let numbers = numbers_section - .split_terminator(",") - .map(|s| s.parse::()) - .collect::, ParseIntError>>() - .map_err(ParseBingoGameError::ParseNumberError)?; - - let mut boards = Vec::new(); - for section in sections { - let mut board: [i32; 25] = [0; 25]; - let mut y = 0; - for row in section.split_terminator("\n") { - let mut x = 0; - for s in row.split_whitespace() { - let n = s.trim().parse::().map_err(ParseBingoGameError::ParseNumberError)?; - board[5*y + x] = n; - x += 1; - } - y += 1; - } - boards.push(board); - } - - Ok(BingoGame { numbers, boards }) + let numbers = numbers_section + .split_terminator(",") + .map(|s| s.parse::()) + .collect::, ParseIntError>>() + .map_err(ParseBingoGameError::ParseNumberError)?; + + let mut boards = Vec::new(); + for section in sections { + let mut board: [i32; 25] = [0; 25]; + let mut y = 0; + for row in section.split_terminator("\n") { + let mut x = 0; + for s in row.split_whitespace() { + let n = s + .trim() + .parse::() + .map_err(ParseBingoGameError::ParseNumberError)?; + board[5 * y + x] = n; + x += 1; + } + y += 1; + } + boards.push(board); + } + + Ok(BingoGame { numbers, boards }) } fn find_number(board: &[i32], value: i32) -> Option { - for i in 0..board.len() { - if board[i] == value { - return Some(i); - } - } - return None; + for i in 0..board.len() { + if board[i] == value { + return Some(i); + } + } + return None; } fn mark_number(board: &[i32], markings: &mut i32, value: i32) -> bool { - let pos: usize; - match find_number(board, value) { - None => return false, - Some(n) => pos = n - }; - *markings |= 1 << pos; - return true; + let pos: usize; + match find_number(board, value) { + None => return false, + Some(n) => pos = n, + }; + *markings |= 1 << pos; + return true; } fn contains_win(markings: i32) -> bool { - const WINNING_COMBINATIONS: [i32; 10] = [ - 0b11111 << 0, // First row - 0b11111 << 5, // Second row - 0b11111 << 10, // Third row - 0b11111 << 15, // Fourth row - 0b11111 << 20, // Fifth row - 0b0000100001000010000100001, // First column - 0b0001000010000100001000010, // Second column - 0b0010000100001000010000100, // Third column - 0b0100001000010000100001000, // Fourth column - 0b1000010000100001000010000, // Fifth column - ]; + const WINNING_COMBINATIONS: [i32; 10] = [ + 0b11111 << 0, // First row + 0b11111 << 5, // Second row + 0b11111 << 10, // Third row + 0b11111 << 15, // Fourth row + 0b11111 << 20, // Fifth row + 0b0000100001000010000100001, // First column + 0b0001000010000100001000010, // Second column + 0b0010000100001000010000100, // Third column + 0b0100001000010000100001000, // Fourth column + 0b1000010000100001000010000, // Fifth column + ]; - for comb in WINNING_COMBINATIONS.iter() { - if markings & comb == *comb { - return true; - } - } - false + for comb in WINNING_COMBINATIONS.iter() { + if markings & comb == *comb { + return true; + } + } + false } fn sum_unmarked_numbers(board: &[i32], markings: i32) -> i32 { - let mut sum = 0; - for i in 0..25 { - if markings & (1 << i) == 0 { - sum += board[i]; - } - } - return sum; + let mut sum = 0; + for i in 0..25 { + if markings & (1 << i) == 0 { + sum += board[i]; + } + } + return sum; } pub fn part1(game: &BingoGame) -> i32 { - let mut markings = vec![0; game.boards.len()]; + let mut markings = vec![0; game.boards.len()]; - for num in game.numbers.iter() { - for i in 0..game.boards.len() { - if mark_number(&game.boards[i], &mut markings[i], *num) && contains_win(markings[i]) { - return num * sum_unmarked_numbers(&game.boards[i], markings[i]); - } - } - } - -1 + for num in game.numbers.iter() { + for i in 0..game.boards.len() { + if mark_number(&game.boards[i], &mut markings[i], *num) && contains_win(markings[i]) { + return num * sum_unmarked_numbers(&game.boards[i], markings[i]); + } + } + } + -1 } pub fn part2(game: &BingoGame) -> i32 { - let mut markings = vec![0; game.boards.len()]; - let mut winning_numbers: Vec = vec![0; game.boards.len()]; - let mut last_winning_board = usize::MAX; + let mut markings = vec![0; game.boards.len()]; + let mut winning_numbers: Vec = vec![0; game.boards.len()]; + let mut last_winning_board = usize::MAX; - for num in game.numbers.iter() { - for i in 0..game.boards.len() { - if winning_numbers[i] == 0 && mark_number(&game.boards[i], &mut markings[i], *num) && contains_win(markings[i]) { - winning_numbers[i] = *num; - last_winning_board = i; - } - } - } + for num in game.numbers.iter() { + for i in 0..game.boards.len() { + if winning_numbers[i] == 0 + && mark_number(&game.boards[i], &mut markings[i], *num) + && contains_win(markings[i]) + { + winning_numbers[i] = *num; + last_winning_board = i; + } + } + } - return winning_numbers[last_winning_board] * sum_unmarked_numbers(&game.boards[last_winning_board], markings[last_winning_board]); + return winning_numbers[last_winning_board] + * sum_unmarked_numbers( + &game.boards[last_winning_board], + markings[last_winning_board], + ); } #[cfg(test)] mod tests { - use super::*; + use super::*; - fn new_test_board() -> [i32; 25] { - let mut board: [i32; 25] = [0; 25]; - for i in 0..25 { - board[i] = i as i32; - } - return board; - } + fn new_test_board() -> [i32; 25] { + let mut board: [i32; 25] = [0; 25]; + for i in 0..25 { + board[i] = i as i32; + } + return board; + } - #[test] - fn part1_example() { - let input = BingoGame { - numbers: vec![7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1], - boards: vec![ - [ - 22, 13, 17, 11, 0, - 8, 2, 23, 4, 24, - 21, 9, 14, 16, 7, - 6, 10, 3, 18, 5, - 1, 12, 20, 15, 19 - ], - [ - 3, 15, 0, 2, 22, - 9, 18, 13, 17, 5, - 19, 8, 7, 25, 23, - 20, 11, 10, 24, 4, - 14, 21, 16, 12, 6 - ], - [ - 14, 21, 17, 24, 4, - 10, 16, 15, 9, 19, - 18, 8, 23, 26, 20, - 22, 11, 13, 6, 5, - 2, 0, 12, 3, 7 - ] - ] - }; - let result = part1(&input); - assert_eq!(result, 4512); - } + #[test] + fn part1_example() { + let input = BingoGame { + numbers: vec![ + 7, 4, 9, 5, 11, 17, 23, 2, 0, 14, 21, 24, 10, 16, 13, 6, 15, 25, 12, 22, 18, 20, 8, 19, 3, + 26, 1, + ], + boards: vec![ + [ + 22, 13, 17, 11, 0, 8, 2, 23, 4, 24, 21, 9, 14, 16, 7, 6, 10, 3, 18, 5, 1, 12, 20, 15, 19, + ], + [ + 3, 15, 0, 2, 22, 9, 18, 13, 17, 5, 19, 8, 7, 25, 23, 20, 11, 10, 24, 4, 14, 21, 16, 12, 6, + ], + [ + 14, 21, 17, 24, 4, 10, 16, 15, 9, 19, 18, 8, 23, 26, 20, 22, 11, 13, 6, 5, 2, 0, 12, 3, 7, + ], + ], + }; + let result = part1(&input); + assert_eq!(result, 4512); + } - #[test] - fn part2_example() { - let input = BingoGame { - numbers: vec![7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1], - boards: vec![ - [ - 22, 13, 17, 11, 0, - 8, 2, 23, 4, 24, - 21, 9, 14, 16, 7, - 6, 10, 3, 18, 5, - 1, 12, 20, 15, 19 - ], - [ - 3, 15, 0, 2, 22, - 9, 18, 13, 17, 5, - 19, 8, 7, 25, 23, - 20, 11, 10, 24, 4, - 14, 21, 16, 12, 6 - ], - [ - 14, 21, 17, 24, 4, - 10, 16, 15, 9, 19, - 18, 8, 23, 26, 20, - 22, 11, 13, 6, 5, - 2, 0, 12, 3, 7 - ] - ] - }; - let result = part2(&input); - assert_eq!(result, 1924); - } + #[test] + fn part2_example() { + let input = BingoGame { + numbers: vec![ + 7, 4, 9, 5, 11, 17, 23, 2, 0, 14, 21, 24, 10, 16, 13, 6, 15, 25, 12, 22, 18, 20, 8, 19, 3, + 26, 1, + ], + boards: vec![ + [ + 22, 13, 17, 11, 0, 8, 2, 23, 4, 24, 21, 9, 14, 16, 7, 6, 10, 3, 18, 5, 1, 12, 20, 15, 19, + ], + [ + 3, 15, 0, 2, 22, 9, 18, 13, 17, 5, 19, 8, 7, 25, 23, 20, 11, 10, 24, 4, 14, 21, 16, 12, 6, + ], + [ + 14, 21, 17, 24, 4, 10, 16, 15, 9, 19, 18, 8, 23, 26, 20, 22, 11, 13, 6, 5, 2, 0, 12, 3, 7, + ], + ], + }; + let result = part2(&input); + assert_eq!(result, 1924); + } - #[test] - fn check_mark_number() { - let board = new_test_board(); - let mut markings = 0b0; - mark_number(&board, &mut markings, 0); - assert_eq!(markings, 1); + #[test] + fn check_mark_number() { + let board = new_test_board(); + let mut markings = 0b0; + mark_number(&board, &mut markings, 0); + assert_eq!(markings, 1); - mark_number(&board, &mut markings, 1); - assert_eq!(markings, 3); - } + mark_number(&board, &mut markings, 1); + assert_eq!(markings, 3); + } - #[test] - fn check_contains_win() { - let board = new_test_board(); - let mut markings = 0b0; - mark_number(&board, &mut markings, 0); - mark_number(&board, &mut markings, 1); - mark_number(&board, &mut markings, 2); - mark_number(&board, &mut markings, 3); - mark_number(&board, &mut markings, 4); - mark_number(&board, &mut markings, 5); - assert!(contains_win(markings)); - } + #[test] + fn check_contains_win() { + let board = new_test_board(); + let mut markings = 0b0; + mark_number(&board, &mut markings, 0); + mark_number(&board, &mut markings, 1); + mark_number(&board, &mut markings, 2); + mark_number(&board, &mut markings, 3); + mark_number(&board, &mut markings, 4); + mark_number(&board, &mut markings, 5); + assert!(contains_win(markings)); + } } - diff --git a/src/day5.rs b/src/day5.rs index e65adc4..3a1d9d9 100644 --- a/src/day5.rs +++ b/src/day5.rs @@ -1,177 +1,282 @@ -use std::{num::ParseIntError, cmp::{min, max}}; +use std::{ + cmp::{max, min}, + num::ParseIntError, +}; type Grid = Vec>; #[derive(Debug)] pub struct Line { - x1: i32, - y1: i32, - x2: i32, - y2: i32 + x1: i32, + y1: i32, + x2: i32, + y2: i32, } #[derive(Debug)] pub enum ParseLineError { - ParseNumberError(ParseIntError), - ParsePointsError, - ParsePointError + ParseNumberError(ParseIntError), + ParsePointsError, + ParsePointError, } pub fn parse_point(input: &str) -> Result<(i32, i32), ParseLineError> { - let mut parts = input.split(','); - let x = parts.next() - .ok_or(ParseLineError::ParsePointError)? - .parse() - .map_err(ParseLineError::ParseNumberError)?; - let y = parts.next() - .ok_or(ParseLineError::ParsePointError)? - .parse() - .map_err(ParseLineError::ParseNumberError)?; - return Ok((x, y)); + let mut parts = input.split(','); + let x = parts + .next() + .ok_or(ParseLineError::ParsePointError)? + .parse() + .map_err(ParseLineError::ParseNumberError)?; + let y = parts + .next() + .ok_or(ParseLineError::ParsePointError)? + .parse() + .map_err(ParseLineError::ParseNumberError)?; + return Ok((x, y)); } pub fn parse_input(input: &str) -> Result, ParseLineError> { - let mut lines = Vec::new(); - for input_line in input.lines() { - let mut parts = input_line.split(" -> "); + let mut lines = Vec::new(); + for input_line in input.lines() { + let mut parts = input_line.split(" -> "); - let point1 = parts.next().ok_or(ParseLineError::ParsePointsError)?; - let (x1, y1) = parse_point(point1)?; + let point1 = parts.next().ok_or(ParseLineError::ParsePointsError)?; + let (x1, y1) = parse_point(point1)?; - let point2 = parts.next().ok_or(ParseLineError::ParsePointsError)?; - let (x2, y2) = parse_point(point2)?; + let point2 = parts.next().ok_or(ParseLineError::ParsePointsError)?; + let (x2, y2) = parse_point(point2)?; - lines.push(Line { x1, y1, x2, y2 }) - } - return Ok(lines); + lines.push(Line { x1, y1, x2, y2 }) + } + return Ok(lines); } fn determine_bounds(lines: &[Line]) -> (i32, i32, i32, i32) { - let mut x1 = i32::MAX; - let mut y1 = i32::MAX; - let mut x2 = i32::MIN; - let mut y2 = i32::MIN; - for line in lines { - x1 = min(x1, min(line.x1, line.x2)); - y1 = min(y1, min(line.y1, line.y2)); - x2 = max(x2, max(line.x1, line.x2)); - y2 = max(y2, max(line.y1, line.y2)); - } - return (x1, y1, x2, y2); + let mut x1 = i32::MAX; + let mut y1 = i32::MAX; + let mut x2 = i32::MIN; + let mut y2 = i32::MIN; + for line in lines { + x1 = min(x1, min(line.x1, line.x2)); + y1 = min(y1, min(line.y1, line.y2)); + x2 = max(x2, max(line.x1, line.x2)); + y2 = max(y2, max(line.y1, line.y2)); + } + return (x1, y1, x2, y2); } fn new_grid(width: usize, height: usize) -> Grid { - let mut grid = Vec::new(); - for _ in 0..height { - grid.push(vec![0; width]); - } - grid + let mut grid = Vec::new(); + for _ in 0..height { + grid.push(vec![0; width]); + } + grid } fn sign(x: i32) -> i32 { - if x > 0 { - 1 - } else if x < 0 { - -1 - } else { - 0 - } + if x > 0 { + 1 + } else if x < 0 { + -1 + } else { + 0 + } } fn mark_line(grid: &mut Grid, line: &Line, ox: i32, oy: i32) { - let dx = sign(line.x2 - line.x1); - let dy = sign(line.y2 - line.y1); - let mut x = line.x1; - let mut y = line.y1; - while x != line.x2 || y != line.y2 { - grid[(y - oy) as usize][(x - ox) as usize] += 1; - if x != line.x2 { - x += dx; - } - if y != line.y2 { - y += dy; - } - } - grid[(y - oy) as usize][(x - ox) as usize] += 1; + let dx = sign(line.x2 - line.x1); + let dy = sign(line.y2 - line.y1); + let mut x = line.x1; + let mut y = line.y1; + while x != line.x2 || y != line.y2 { + grid[(y - oy) as usize][(x - ox) as usize] += 1; + if x != line.x2 { + x += dx; + } + if y != line.y2 { + y += dy; + } + } + grid[(y - oy) as usize][(x - ox) as usize] += 1; } fn count_dangerous_areas(grid: &Grid) -> u32 { - let mut count = 0; - for row in grid { - for point in row { - if *point > 1 { - count += 1; - } - } - } - count + let mut count = 0; + for row in grid { + for point in row { + if *point > 1 { + count += 1; + } + } + } + count } pub fn part1(lines: &[Line]) -> u32 { - let bounds = determine_bounds(lines); - let width = (bounds.2 - bounds.0 + 1) as usize; - let height = (bounds.3 - bounds.1 + 1) as usize; - let mut grid = new_grid(width, height); + let bounds = determine_bounds(lines); + let width = (bounds.2 - bounds.0 + 1) as usize; + let height = (bounds.3 - bounds.1 + 1) as usize; + let mut grid = new_grid(width, height); - for line in lines { - if (line.x1 == line.x2) || (line.y1 == line.y2) { - mark_line(&mut grid, line, bounds.0, bounds.1); - } - } + for line in lines { + if (line.x1 == line.x2) || (line.y1 == line.y2) { + mark_line(&mut grid, line, bounds.0, bounds.1); + } + } - count_dangerous_areas(&grid) + count_dangerous_areas(&grid) } pub fn part2(lines: &[Line]) -> u32 { - let bounds = determine_bounds(lines); - let width = (bounds.2 - bounds.0 + 1) as usize; - let height = (bounds.3 - bounds.1 + 1) as usize; - let mut grid = new_grid(width, height); + let bounds = determine_bounds(lines); + let width = (bounds.2 - bounds.0 + 1) as usize; + let height = (bounds.3 - bounds.1 + 1) as usize; + let mut grid = new_grid(width, height); - for line in lines { - mark_line(&mut grid, line, bounds.0, bounds.1); - } + for line in lines { + mark_line(&mut grid, line, bounds.0, bounds.1); + } - count_dangerous_areas(&grid) + count_dangerous_areas(&grid) } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let input = [ - Line { x1: 0, y1: 9, x2: 5, y2: 9 }, - Line { x1: 8, y1: 0, x2: 0, y2: 8 }, - Line { x1: 9, y1: 4, x2: 3, y2: 4 }, - Line { x1: 2, y1: 2, x2: 2, y2: 1 }, - Line { x1: 7, y1: 0, x2: 7, y2: 4 }, - Line { x1: 6, y1: 4, x2: 2, y2: 0 }, - Line { x1: 0, y1: 9, x2: 2, y2: 9 }, - Line { x1: 3, y1: 4, x2: 1, y2: 4 }, - Line { x1: 0, y1: 0, x2: 8, y2: 8 }, - Line { x1: 5, y1: 5, x2: 8, y2: 2 } - ]; - let result = part1(&input); - assert_eq!(result, 5); - } + #[test] + fn part1_example() { + let input = [ + Line { + x1: 0, + y1: 9, + x2: 5, + y2: 9, + }, + Line { + x1: 8, + y1: 0, + x2: 0, + y2: 8, + }, + Line { + x1: 9, + y1: 4, + x2: 3, + y2: 4, + }, + Line { + x1: 2, + y1: 2, + x2: 2, + y2: 1, + }, + Line { + x1: 7, + y1: 0, + x2: 7, + y2: 4, + }, + Line { + x1: 6, + y1: 4, + x2: 2, + y2: 0, + }, + Line { + x1: 0, + y1: 9, + x2: 2, + y2: 9, + }, + Line { + x1: 3, + y1: 4, + x2: 1, + y2: 4, + }, + Line { + x1: 0, + y1: 0, + x2: 8, + y2: 8, + }, + Line { + x1: 5, + y1: 5, + x2: 8, + y2: 2, + }, + ]; + let result = part1(&input); + assert_eq!(result, 5); + } - #[test] - fn part2_example() { - let input = [ - Line { x1: 0, y1: 9, x2: 5, y2: 9 }, - Line { x1: 8, y1: 0, x2: 0, y2: 8 }, - Line { x1: 9, y1: 4, x2: 3, y2: 4 }, - Line { x1: 2, y1: 2, x2: 2, y2: 1 }, - Line { x1: 7, y1: 0, x2: 7, y2: 4 }, - Line { x1: 6, y1: 4, x2: 2, y2: 0 }, - Line { x1: 0, y1: 9, x2: 2, y2: 9 }, - Line { x1: 3, y1: 4, x2: 1, y2: 4 }, - Line { x1: 0, y1: 0, x2: 8, y2: 8 }, - Line { x1: 5, y1: 5, x2: 8, y2: 2 } - ]; - let result = part2(&input); - assert_eq!(result, 12); - } + #[test] + fn part2_example() { + let input = [ + Line { + x1: 0, + y1: 9, + x2: 5, + y2: 9, + }, + Line { + x1: 8, + y1: 0, + x2: 0, + y2: 8, + }, + Line { + x1: 9, + y1: 4, + x2: 3, + y2: 4, + }, + Line { + x1: 2, + y1: 2, + x2: 2, + y2: 1, + }, + Line { + x1: 7, + y1: 0, + x2: 7, + y2: 4, + }, + Line { + x1: 6, + y1: 4, + x2: 2, + y2: 0, + }, + Line { + x1: 0, + y1: 9, + x2: 2, + y2: 9, + }, + Line { + x1: 3, + y1: 4, + x2: 1, + y2: 4, + }, + Line { + x1: 0, + y1: 0, + x2: 8, + y2: 8, + }, + Line { + x1: 5, + y1: 5, + x2: 8, + y2: 2, + }, + ]; + let result = part2(&input); + assert_eq!(result, 12); + } } diff --git a/src/day6.rs b/src/day6.rs index efb13ce..c4049ae 100644 --- a/src/day6.rs +++ b/src/day6.rs @@ -1,81 +1,82 @@ use std::num::ParseIntError; pub fn parse_input(input: &str) -> Result, ParseIntError> { - input.trim_end().split_terminator(',') - .map(|s| s.parse()) - .collect() + input + .trim_end() + .split_terminator(',') + .map(|s| s.parse()) + .collect() } fn simulate_step(fishes: &mut Vec) { - for i in 0..fishes.len() { - if fishes[i] == 0 { - fishes[i] = 7; - fishes.push(9); - } - } + for i in 0..fishes.len() { + if fishes[i] == 0 { + fishes[i] = 7; + fishes.push(9); + } + } - for i in 0..fishes.len() { - if fishes[i] > 0 { - fishes[i] -= 1; - } - } + for i in 0..fishes.len() { + if fishes[i] > 0 { + fishes[i] -= 1; + } + } } pub fn part1(input: &[i32]) -> u32 { - let mut fishes = input.to_vec(); + let mut fishes = input.to_vec(); - for _ in 0..80 { - simulate_step(&mut fishes) - } + for _ in 0..80 { + simulate_step(&mut fishes) + } - fishes.len() as u32 + fishes.len() as u32 } // Instead of storing each fishes cycle as individual values group them up // by there cycles. Because it dosen't matter where the fish is in the list. // So just make an array of size 9 for the 9 possible fish cycle timers. -// And one extra group, for accounting for the delay that when the timer is 0, +// And one extra group, for accounting for the delay that when the timer is 0, // they produce a new fish only on the next turn. pub fn part2(input: &[i32]) -> u64 { - let mut groups: [u64; 10] = [0; 10]; + let mut groups: [u64; 10] = [0; 10]; - for fish in input.iter() { - groups[*fish as usize + 1] += 1; - } + for fish in input.iter() { + groups[*fish as usize + 1] += 1; + } - for _ in 0..256 { - for i in 1..10 { - groups[i-1] += groups[i]; - groups[i] = 0; - } - groups[7] += groups[0]; - groups[9] += groups[0]; - groups[0] = 0; - } + for _ in 0..256 { + for i in 1..10 { + groups[i - 1] += groups[i]; + groups[i] = 0; + } + groups[7] += groups[0]; + groups[9] += groups[0]; + groups[0] = 0; + } - let mut count: u64 = 0; - for amount in groups.iter() { - count += amount; - } - count + let mut count: u64 = 0; + for amount in groups.iter() { + count += amount; + } + count } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let input = [3,4,3,1,2]; - let result = part1(&input); - assert_eq!(result, 5934); - } + #[test] + fn part1_example() { + let input = [3, 4, 3, 1, 2]; + let result = part1(&input); + assert_eq!(result, 5934); + } - #[test] - fn part2_example() { - let input = [3,4,3,1,2]; - let result = part2(&input); - assert_eq!(result, 26984457539 as u64); - } + #[test] + fn part2_example() { + let input = [3, 4, 3, 1, 2]; + let result = part2(&input); + assert_eq!(result, 26984457539 as u64); + } } - diff --git a/src/day7.rs b/src/day7.rs index 52ce4ad..28c127f 100644 --- a/src/day7.rs +++ b/src/day7.rs @@ -1,85 +1,90 @@ use std::num::ParseIntError; pub fn parse_input(input: &str) -> Result, ParseIntError> { - input.trim_end().split_terminator(',') - .map(|s| s.parse()) - .collect() + input + .trim_end() + .split_terminator(',') + .map(|s| s.parse()) + .collect() } fn abs(x: i32) -> u32 { - if x < 0 { -x as u32 } else { x as u32 } + if x < 0 { + -x as u32 + } else { + x as u32 + } } fn calculate_total_cost_to1(crabs: &[i32], target: i32) -> u32 { - let mut sum = 0; - for crab in crabs { - sum += abs(crab-target); - } - return sum; + let mut sum = 0; + for crab in crabs { + sum += abs(crab - target); + } + return sum; } pub fn part1(crabs: &[i32]) -> u32 { - let mut best_cost = calculate_total_cost_to1(crabs, crabs[0]); + let mut best_cost = calculate_total_cost_to1(crabs, crabs[0]); - for position in crabs.iter().skip(1) { - let cost = calculate_total_cost_to1(crabs, *position); - if cost < best_cost { - best_cost = cost; - } - } + for position in crabs.iter().skip(1) { + let cost = calculate_total_cost_to1(crabs, *position); + if cost < best_cost { + best_cost = cost; + } + } - best_cost + best_cost } fn calculate_total_cost_to2(crabs: &[i32], target: i32) -> u32 { - let mut sum = 0; - for crab in crabs { - let distance = abs(crab - target); - for i in 1..=distance { - sum += i; - } - } - return sum; + let mut sum = 0; + for crab in crabs { + let distance = abs(crab - target); + for i in 1..=distance { + sum += i; + } + } + return sum; } fn calculate_average(arr: &[i32]) -> f32 { - let mut sum = 0.0; - for a in arr { - sum += *a as f32; - } - return sum / arr.len() as f32; + let mut sum = 0.0; + for a in arr { + sum += *a as f32; + } + return sum / arr.len() as f32; } pub fn part2(crabs: &[i32]) -> u32 { - let average_position = calculate_average(crabs).round() as i32; - let mut best_cost = calculate_total_cost_to2(crabs, average_position); + let average_position = calculate_average(crabs).round() as i32; + let mut best_cost = calculate_total_cost_to2(crabs, average_position); - for position in average_position-5..=average_position+5 { - let cost = calculate_total_cost_to2(crabs, position); - if cost < best_cost { - best_cost = cost; - } - } + for position in average_position - 5..=average_position + 5 { + let cost = calculate_total_cost_to2(crabs, position); + if cost < best_cost { + best_cost = cost; + } + } - best_cost + best_cost } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let input = [16,1,2,0,4,2,7,1,2,14]; - let result = part1(&input); - assert_eq!(result, 37); - } + #[test] + fn part1_example() { + let input = [16, 1, 2, 0, 4, 2, 7, 1, 2, 14]; + let result = part1(&input); + assert_eq!(result, 37); + } - #[test] - fn part2_example() { - let input = [16,1,2,0,4,2,7,1,2,14]; - let result = part2(&input); - assert_eq!(result, 168); - } + #[test] + fn part2_example() { + let input = [16, 1, 2, 0, 4, 2, 7, 1, 2, 14]; + let result = part2(&input); + assert_eq!(result, 168); + } } - diff --git a/src/day8.rs b/src/day8.rs index ce7e5a1..8cc70ba 100644 --- a/src/day8.rs +++ b/src/day8.rs @@ -1,179 +1,507 @@ -use std::{convert::TryInto, collections::HashMap}; +use std::{collections::HashMap, convert::TryInto}; pub struct Entry([String; 10], [String; 4]); fn parse_line(line: &str) -> Entry { - let parts: Vec<&str> = line.split(" | ").collect(); - let unique_patterns = parts[0] - .split_whitespace() - .map(|s| String::from(s)) - .collect::>() - .try_into() - .unwrap(); - let output_digits = parts[1] - .split_whitespace() - .map(|s| String::from(s)) - .collect::>() - .try_into() - .unwrap(); - return Entry(unique_patterns, output_digits); + let parts: Vec<&str> = line.split(" | ").collect(); + let unique_patterns = parts[0] + .split_whitespace() + .map(|s| String::from(s)) + .collect::>() + .try_into() + .unwrap(); + let output_digits = parts[1] + .split_whitespace() + .map(|s| String::from(s)) + .collect::>() + .try_into() + .unwrap(); + return Entry(unique_patterns, output_digits); } pub fn parse_input(input: &str) -> Vec { - input.lines() - .map(parse_line) - .collect() + input.lines().map(parse_line).collect() } pub fn part1(entries: &[Entry]) -> u32 { - let mut count = 0; - for entry in entries { - for digit in entry.1.iter() { - let len = digit.len(); - if len == 2 || len == 3 || len == 4 || len == 7 { - count += 1; - } - } - } - count + let mut count = 0; + for entry in entries { + for digit in entry.1.iter() { + let len = digit.len(); + if len == 2 || len == 3 || len == 4 || len == 7 { + count += 1; + } + } + } + count } // Helper function which converts a string into a binary representation // I did this is so that the order of the letters won't matter fn signal_to_bitmask(signal: &str) -> u32 { - let mut bitmask = 0; - for c in signal.chars() { - match c { - 'a' => bitmask += 0b0000001, - 'b' => bitmask += 0b0000010, - 'c' => bitmask += 0b0000100, - 'd' => bitmask += 0b0001000, - 'e' => bitmask += 0b0010000, - 'f' => bitmask += 0b0100000, - 'g' => bitmask += 0b1000000, - _ => bitmask += 0 - } - } - return bitmask; + let mut bitmask = 0; + for c in signal.chars() { + match c { + 'a' => bitmask += 0b0000001, + 'b' => bitmask += 0b0000010, + 'c' => bitmask += 0b0000100, + 'd' => bitmask += 0b0001000, + 'e' => bitmask += 0b0010000, + 'f' => bitmask += 0b0100000, + 'g' => bitmask += 0b1000000, + _ => bitmask += 0, + } + } + return bitmask; } fn decode_signal(signal: &str, wire_loopup: &HashMap) -> Option { - wire_loopup.get(&signal_to_bitmask(signal)).map(|n| *n) + wire_loopup.get(&signal_to_bitmask(signal)).map(|n| *n) } fn decode_signals(signals: &[String], wire_loopup: &HashMap) -> u32 { - let mut number = 0; - let n = signals.len(); - for i in 0..n { - let value = decode_signal(&signals[i], wire_loopup).unwrap(); - number += value * u32::pow(10, (n-i-1) as u32); - } - return number; + let mut number = 0; + let n = signals.len(); + for i in 0..n { + let value = decode_signal(&signals[i], wire_loopup).unwrap(); + number += value * u32::pow(10, (n - i - 1) as u32); + } + return number; } fn decode_wire_lookup(signals: &[String; 10]) -> HashMap { - let mut wire_lookup = HashMap::new(); - let mut bitmasks: [u32; 10] = [0; 10]; - for i in 0..10 { - bitmasks[i] = signal_to_bitmask(&signals[i]); - } + let mut wire_lookup = HashMap::new(); + let mut bitmasks: [u32; 10] = [0; 10]; + for i in 0..10 { + bitmasks[i] = signal_to_bitmask(&signals[i]); + } - let mut one_bitmask = 0; - let mut four_bitmask = 0; + let mut one_bitmask = 0; + let mut four_bitmask = 0; - // Decode all signals which have unique number of wires - for i in 0..10 { - let len = signals[i].len(); - if len == 2 { - one_bitmask = bitmasks[i]; - wire_lookup.insert(one_bitmask, 1); - } else if len == 3 { - wire_lookup.insert(bitmasks[i], 7); - } else if len == 4 { - four_bitmask = bitmasks[i]; - wire_lookup.insert(four_bitmask, 4); - } else if len == 7 { - wire_lookup.insert(bitmasks[i], 8); - } - } + // Decode all signals which have unique number of wires + for i in 0..10 { + let len = signals[i].len(); + if len == 2 { + one_bitmask = bitmasks[i]; + wire_lookup.insert(one_bitmask, 1); + } else if len == 3 { + wire_lookup.insert(bitmasks[i], 7); + } else if len == 4 { + four_bitmask = bitmasks[i]; + wire_lookup.insert(four_bitmask, 4); + } else if len == 7 { + wire_lookup.insert(bitmasks[i], 8); + } + } - let fourdiff = four_bitmask ^ one_bitmask; + let fourdiff = four_bitmask ^ one_bitmask; - for i in 0..10 { - let len = signals[i].len(); - if len == 5 { - if bitmasks[i] & one_bitmask == one_bitmask { - wire_lookup.insert(bitmasks[i], 3); - } else if bitmasks[i] & fourdiff == fourdiff { - wire_lookup.insert(bitmasks[i], 5); - } else { - wire_lookup.insert(bitmasks[i], 2); - } - } else if len == 6 { - if bitmasks[i] & four_bitmask == four_bitmask { - wire_lookup.insert(bitmasks[i], 9); - } else if bitmasks[i] & fourdiff == fourdiff { - wire_lookup.insert(bitmasks[i], 6); - } else { - wire_lookup.insert(bitmasks[i], 0); - } - } - } + for i in 0..10 { + let len = signals[i].len(); + if len == 5 { + if bitmasks[i] & one_bitmask == one_bitmask { + wire_lookup.insert(bitmasks[i], 3); + } else if bitmasks[i] & fourdiff == fourdiff { + wire_lookup.insert(bitmasks[i], 5); + } else { + wire_lookup.insert(bitmasks[i], 2); + } + } else if len == 6 { + if bitmasks[i] & four_bitmask == four_bitmask { + wire_lookup.insert(bitmasks[i], 9); + } else if bitmasks[i] & fourdiff == fourdiff { + wire_lookup.insert(bitmasks[i], 6); + } else { + wire_lookup.insert(bitmasks[i], 0); + } + } + } - return wire_lookup; + return wire_lookup; } fn decode_entry(entry: &Entry) -> u32 { - let wire_lookup = decode_wire_lookup(&entry.0); - return decode_signals(&entry.1, &wire_lookup); + let wire_lookup = decode_wire_lookup(&entry.0); + return decode_signals(&entry.1, &wire_lookup); } pub fn part2(entries: &[Entry]) -> u32 { - let mut sum = 0; - for entry in entries { - sum += decode_entry(entry); - } - sum + let mut sum = 0; + for entry in entries { + sum += decode_entry(entry); + } + sum } #[cfg(test)] mod tests { - use super::*; + use super::*; - // I know it's ugly - #[test] - fn part1_example() { - let input = vec![ - Entry(["be" .into(), "cfbegad" .into(), "cbdgef" .into(), "fgaecd" .into(), "cgeb" .into(), "fdcge" .into(), "agebfd" .into(), "fecdb" .into(), "fabcd" .into(), "edb".into()], ["fdgacbe" .into(), "cefdb" .into(), "cefbgd" .into(), "gcbe".into()]), - Entry(["edbfga" .into(), "begcd" .into(), "cbg" .into(), "gc" .into(), "gcadebf" .into(), "fbgde" .into(), "acbgfd" .into(), "abcde" .into(), "gfcbed" .into(), "gfec".into()], ["fcgedb" .into(), "cgb" .into(), "dgebacf" .into(), "gc".into()]), - Entry(["fgaebd" .into(), "cg" .into(), "bdaec" .into(), "gdafb" .into(), "agbcfd" .into(), "gdcbef" .into(), "bgcad" .into(), "gfac" .into(), "gcb" .into(), "cdgabef".into()], ["cg" .into(), "cg" .into(), "fdcagb" .into(), "cbg".into()]), - Entry(["fbegcd" .into(), "cbd" .into(), "adcefb" .into(), "dageb" .into(), "afcb" .into(), "bc" .into(), "aefdc" .into(), "ecdab" .into(), "fgdeca" .into(), "fcdbega".into()], ["efabcd" .into(), "cedba" .into(), "gadfec" .into(), "cb".into()]), - Entry(["aecbfdg" .into(), "fbg" .into(), "gf" .into(), "bafeg" .into(), "dbefa" .into(), "fcge" .into(), "gcbea" .into(), "fcaegb" .into(), "dgceab" .into(), "fcbdga".into()], ["gecf" .into(), "egdcabf" .into(), "bgf" .into(), "bfgea".into()]), - Entry(["fgeab" .into(), "ca" .into(), "afcebg" .into(), "bdacfeg" .into(), "cfaedg" .into(), "gcfdb" .into(), "baec" .into(), "bfadeg" .into(), "bafgc" .into(), "acf".into()], ["gebdcfa" .into(), "ecba" .into(), "ca" .into(), "fadegcb".into()]), - Entry(["dbcfg" .into(), "fgd" .into(), "bdegcaf" .into(), "fgec" .into(), "aegbdf" .into(), "ecdfab" .into(), "fbedc" .into(), "dacgb" .into(), "gdcebf" .into(), "gf".into()], ["cefg" .into(), "dcbef" .into(), "fcge" .into(), "gbcadfe".into()]), - Entry(["bdfegc" .into(), "cbegaf" .into(), "gecbf" .into(), "dfcage" .into(), "bdacg" .into(), "ed" .into(), "bedf" .into(), "ced" .into(), "adcbefg" .into(), "gebcd".into()], ["ed" .into(), "bcgafe" .into(), "cdgba" .into(), "cbgef".into()]), - Entry(["egadfb" .into(), "cdbfeg" .into(), "cegd" .into(), "fecab" .into(), "cgb" .into(), "gbdefca" .into(), "cg" .into(), "fgcdab" .into(), "egfdb" .into(), "bfceg".into()], ["gbdfcae" .into(), "bgc" .into(), "cg" .into(), "cgb".into()]), - Entry(["gcafb" .into(), "gcf" .into(), "dcaebfg" .into(), "ecagb" .into(), "gf" .into(), "abcdeg" .into(), "gaef" .into(), "cafbge" .into(), "fdbac" .into(), "fegbdc".into()], ["fgae" .into(), "cfgab" .into(), "fg" .into(), "bagce".into()]), - ]; - let result = part1(&input); - assert_eq!(result, 26); - } + // I know it's ugly + #[test] + fn part1_example() { + let input = vec![ + Entry( + [ + "be".into(), + "cfbegad".into(), + "cbdgef".into(), + "fgaecd".into(), + "cgeb".into(), + "fdcge".into(), + "agebfd".into(), + "fecdb".into(), + "fabcd".into(), + "edb".into(), + ], + [ + "fdgacbe".into(), + "cefdb".into(), + "cefbgd".into(), + "gcbe".into(), + ], + ), + Entry( + [ + "edbfga".into(), + "begcd".into(), + "cbg".into(), + "gc".into(), + "gcadebf".into(), + "fbgde".into(), + "acbgfd".into(), + "abcde".into(), + "gfcbed".into(), + "gfec".into(), + ], + ["fcgedb".into(), "cgb".into(), "dgebacf".into(), "gc".into()], + ), + Entry( + [ + "fgaebd".into(), + "cg".into(), + "bdaec".into(), + "gdafb".into(), + "agbcfd".into(), + "gdcbef".into(), + "bgcad".into(), + "gfac".into(), + "gcb".into(), + "cdgabef".into(), + ], + ["cg".into(), "cg".into(), "fdcagb".into(), "cbg".into()], + ), + Entry( + [ + "fbegcd".into(), + "cbd".into(), + "adcefb".into(), + "dageb".into(), + "afcb".into(), + "bc".into(), + "aefdc".into(), + "ecdab".into(), + "fgdeca".into(), + "fcdbega".into(), + ], + [ + "efabcd".into(), + "cedba".into(), + "gadfec".into(), + "cb".into(), + ], + ), + Entry( + [ + "aecbfdg".into(), + "fbg".into(), + "gf".into(), + "bafeg".into(), + "dbefa".into(), + "fcge".into(), + "gcbea".into(), + "fcaegb".into(), + "dgceab".into(), + "fcbdga".into(), + ], + [ + "gecf".into(), + "egdcabf".into(), + "bgf".into(), + "bfgea".into(), + ], + ), + Entry( + [ + "fgeab".into(), + "ca".into(), + "afcebg".into(), + "bdacfeg".into(), + "cfaedg".into(), + "gcfdb".into(), + "baec".into(), + "bfadeg".into(), + "bafgc".into(), + "acf".into(), + ], + [ + "gebdcfa".into(), + "ecba".into(), + "ca".into(), + "fadegcb".into(), + ], + ), + Entry( + [ + "dbcfg".into(), + "fgd".into(), + "bdegcaf".into(), + "fgec".into(), + "aegbdf".into(), + "ecdfab".into(), + "fbedc".into(), + "dacgb".into(), + "gdcebf".into(), + "gf".into(), + ], + [ + "cefg".into(), + "dcbef".into(), + "fcge".into(), + "gbcadfe".into(), + ], + ), + Entry( + [ + "bdfegc".into(), + "cbegaf".into(), + "gecbf".into(), + "dfcage".into(), + "bdacg".into(), + "ed".into(), + "bedf".into(), + "ced".into(), + "adcbefg".into(), + "gebcd".into(), + ], + ["ed".into(), "bcgafe".into(), "cdgba".into(), "cbgef".into()], + ), + Entry( + [ + "egadfb".into(), + "cdbfeg".into(), + "cegd".into(), + "fecab".into(), + "cgb".into(), + "gbdefca".into(), + "cg".into(), + "fgcdab".into(), + "egfdb".into(), + "bfceg".into(), + ], + ["gbdfcae".into(), "bgc".into(), "cg".into(), "cgb".into()], + ), + Entry( + [ + "gcafb".into(), + "gcf".into(), + "dcaebfg".into(), + "ecagb".into(), + "gf".into(), + "abcdeg".into(), + "gaef".into(), + "cafbge".into(), + "fdbac".into(), + "fegbdc".into(), + ], + ["fgae".into(), "cfgab".into(), "fg".into(), "bagce".into()], + ), + ]; + let result = part1(&input); + assert_eq!(result, 26); + } - #[test] - fn part2_example() { - let input = vec![ - Entry(["be" .into(), "cfbegad" .into(), "cbdgef" .into(), "fgaecd" .into(), "cgeb" .into(), "fdcge" .into(), "agebfd" .into(), "fecdb" .into(), "fabcd" .into(), "edb".into()], ["fdgacbe" .into(), "cefdb" .into(), "cefbgd" .into(), "gcbe".into()]), - Entry(["edbfga" .into(), "begcd" .into(), "cbg" .into(), "gc" .into(), "gcadebf" .into(), "fbgde" .into(), "acbgfd" .into(), "abcde" .into(), "gfcbed" .into(), "gfec".into()], ["fcgedb" .into(), "cgb" .into(), "dgebacf" .into(), "gc".into()]), - Entry(["fgaebd" .into(), "cg" .into(), "bdaec" .into(), "gdafb" .into(), "agbcfd" .into(), "gdcbef" .into(), "bgcad" .into(), "gfac" .into(), "gcb" .into(), "cdgabef".into()], ["cg" .into(), "cg" .into(), "fdcagb" .into(), "cbg".into()]), - Entry(["fbegcd" .into(), "cbd" .into(), "adcefb" .into(), "dageb" .into(), "afcb" .into(), "bc" .into(), "aefdc" .into(), "ecdab" .into(), "fgdeca" .into(), "fcdbega".into()], ["efabcd" .into(), "cedba" .into(), "gadfec" .into(), "cb".into()]), - Entry(["aecbfdg" .into(), "fbg" .into(), "gf" .into(), "bafeg" .into(), "dbefa" .into(), "fcge" .into(), "gcbea" .into(), "fcaegb" .into(), "dgceab" .into(), "fcbdga".into()], ["gecf" .into(), "egdcabf" .into(), "bgf" .into(), "bfgea".into()]), - Entry(["fgeab" .into(), "ca" .into(), "afcebg" .into(), "bdacfeg" .into(), "cfaedg" .into(), "gcfdb" .into(), "baec" .into(), "bfadeg" .into(), "bafgc" .into(), "acf".into()], ["gebdcfa" .into(), "ecba" .into(), "ca" .into(), "fadegcb".into()]), - Entry(["dbcfg" .into(), "fgd" .into(), "bdegcaf" .into(), "fgec" .into(), "aegbdf" .into(), "ecdfab" .into(), "fbedc" .into(), "dacgb" .into(), "gdcebf" .into(), "gf".into()], ["cefg" .into(), "dcbef" .into(), "fcge" .into(), "gbcadfe".into()]), - Entry(["bdfegc" .into(), "cbegaf" .into(), "gecbf" .into(), "dfcage" .into(), "bdacg" .into(), "ed" .into(), "bedf" .into(), "ced" .into(), "adcbefg" .into(), "gebcd".into()], ["ed" .into(), "bcgafe" .into(), "cdgba" .into(), "cbgef".into()]), - Entry(["egadfb" .into(), "cdbfeg" .into(), "cegd" .into(), "fecab" .into(), "cgb" .into(), "gbdefca" .into(), "cg" .into(), "fgcdab" .into(), "egfdb" .into(), "bfceg".into()], ["gbdfcae" .into(), "bgc" .into(), "cg" .into(), "cgb".into()]), - Entry(["gcafb" .into(), "gcf" .into(), "dcaebfg" .into(), "ecagb" .into(), "gf" .into(), "abcdeg" .into(), "gaef" .into(), "cafbge" .into(), "fdbac" .into(), "fegbdc".into()], ["fgae" .into(), "cfgab" .into(), "fg" .into(), "bagce".into()]), - ]; - let result = part2(&input); - assert_eq!(result, 61229); - } + #[test] + fn part2_example() { + let input = vec![ + Entry( + [ + "be".into(), + "cfbegad".into(), + "cbdgef".into(), + "fgaecd".into(), + "cgeb".into(), + "fdcge".into(), + "agebfd".into(), + "fecdb".into(), + "fabcd".into(), + "edb".into(), + ], + [ + "fdgacbe".into(), + "cefdb".into(), + "cefbgd".into(), + "gcbe".into(), + ], + ), + Entry( + [ + "edbfga".into(), + "begcd".into(), + "cbg".into(), + "gc".into(), + "gcadebf".into(), + "fbgde".into(), + "acbgfd".into(), + "abcde".into(), + "gfcbed".into(), + "gfec".into(), + ], + ["fcgedb".into(), "cgb".into(), "dgebacf".into(), "gc".into()], + ), + Entry( + [ + "fgaebd".into(), + "cg".into(), + "bdaec".into(), + "gdafb".into(), + "agbcfd".into(), + "gdcbef".into(), + "bgcad".into(), + "gfac".into(), + "gcb".into(), + "cdgabef".into(), + ], + ["cg".into(), "cg".into(), "fdcagb".into(), "cbg".into()], + ), + Entry( + [ + "fbegcd".into(), + "cbd".into(), + "adcefb".into(), + "dageb".into(), + "afcb".into(), + "bc".into(), + "aefdc".into(), + "ecdab".into(), + "fgdeca".into(), + "fcdbega".into(), + ], + [ + "efabcd".into(), + "cedba".into(), + "gadfec".into(), + "cb".into(), + ], + ), + Entry( + [ + "aecbfdg".into(), + "fbg".into(), + "gf".into(), + "bafeg".into(), + "dbefa".into(), + "fcge".into(), + "gcbea".into(), + "fcaegb".into(), + "dgceab".into(), + "fcbdga".into(), + ], + [ + "gecf".into(), + "egdcabf".into(), + "bgf".into(), + "bfgea".into(), + ], + ), + Entry( + [ + "fgeab".into(), + "ca".into(), + "afcebg".into(), + "bdacfeg".into(), + "cfaedg".into(), + "gcfdb".into(), + "baec".into(), + "bfadeg".into(), + "bafgc".into(), + "acf".into(), + ], + [ + "gebdcfa".into(), + "ecba".into(), + "ca".into(), + "fadegcb".into(), + ], + ), + Entry( + [ + "dbcfg".into(), + "fgd".into(), + "bdegcaf".into(), + "fgec".into(), + "aegbdf".into(), + "ecdfab".into(), + "fbedc".into(), + "dacgb".into(), + "gdcebf".into(), + "gf".into(), + ], + [ + "cefg".into(), + "dcbef".into(), + "fcge".into(), + "gbcadfe".into(), + ], + ), + Entry( + [ + "bdfegc".into(), + "cbegaf".into(), + "gecbf".into(), + "dfcage".into(), + "bdacg".into(), + "ed".into(), + "bedf".into(), + "ced".into(), + "adcbefg".into(), + "gebcd".into(), + ], + ["ed".into(), "bcgafe".into(), "cdgba".into(), "cbgef".into()], + ), + Entry( + [ + "egadfb".into(), + "cdbfeg".into(), + "cegd".into(), + "fecab".into(), + "cgb".into(), + "gbdefca".into(), + "cg".into(), + "fgcdab".into(), + "egfdb".into(), + "bfceg".into(), + ], + ["gbdfcae".into(), "bgc".into(), "cg".into(), "cgb".into()], + ), + Entry( + [ + "gcafb".into(), + "gcf".into(), + "dcaebfg".into(), + "ecagb".into(), + "gf".into(), + "abcdeg".into(), + "gaef".into(), + "cafbge".into(), + "fdbac".into(), + "fegbdc".into(), + ], + ["fgae".into(), "cfgab".into(), "fg".into(), "bagce".into()], + ), + ]; + let result = part2(&input); + assert_eq!(result, 61229); + } } diff --git a/src/day9.rs b/src/day9.rs index 72caa05..7ec4860 100644 --- a/src/day9.rs +++ b/src/day9.rs @@ -1,100 +1,108 @@ use std::collections::HashSet; - pub fn parse_input(input: &str) -> Vec> { - input.lines() - .map(|s| s.chars().map(|c| c.to_digit(10).unwrap()).collect()) - .collect() + input + .lines() + .map(|s| s.chars().map(|c| c.to_digit(10).unwrap()).collect()) + .collect() } fn find_low_points(grid: &Vec>) -> Vec<(usize, usize)> { - let mut low_points = Vec::new(); - let height = grid.len(); - for i in 0..height { - let width = grid[i].len(); - for j in 0..width { - if (i == 0 || grid[i-1][j] > grid[i][j]) - && (i == height-1 || grid[i+1][j] > grid[i][j]) - && (j == 0 || grid[i][j-1] > grid[i][j]) - && (j == width-1 || grid[i][j+1] > grid[i][j]) { - low_points.push((i, j)); - } - } - } - return low_points; + let mut low_points = Vec::new(); + let height = grid.len(); + for i in 0..height { + let width = grid[i].len(); + for j in 0..width { + if (i == 0 || grid[i - 1][j] > grid[i][j]) + && (i == height - 1 || grid[i + 1][j] > grid[i][j]) + && (j == 0 || grid[i][j - 1] > grid[i][j]) + && (j == width - 1 || grid[i][j + 1] > grid[i][j]) + { + low_points.push((i, j)); + } + } + } + return low_points; } pub fn part1(grid: Vec>) -> u32 { - let mut sum = 0; - for low_point in find_low_points(&grid) { - let depth = grid[low_point.0][low_point.1]; - sum += depth + 1; - } - return sum; + let mut sum = 0; + for low_point in find_low_points(&grid) { + let depth = grid[low_point.0][low_point.1]; + sum += depth + 1; + } + return sum; } fn find_basin_size(grid: &Vec>, location: (usize, usize)) -> u32 { - let mut explored_spots = HashSet::new(); - let mut leaf_nodes = vec![location]; - let height = grid.len(); - let width = grid[0].len(); + let mut explored_spots = HashSet::new(); + let mut leaf_nodes = vec![location]; + let height = grid.len(); + let width = grid[0].len(); - while leaf_nodes.len() > 0 { - let leaf_node = leaf_nodes.pop().unwrap(); - explored_spots.insert(leaf_node); + while leaf_nodes.len() > 0 { + let leaf_node = leaf_nodes.pop().unwrap(); + explored_spots.insert(leaf_node); - let (i, j) = leaf_node; - if i > 0 && !explored_spots.contains(&(i-1, j)) && grid[i-1][j] != 9 { leaf_nodes.push((i-1, j)); } - if i < height-1 && !explored_spots.contains(&(i+1, j)) && grid[i+1][j] != 9 { leaf_nodes.push((i+1, j)); } - if j > 0 && !explored_spots.contains(&(i, j-1)) && grid[i][j-1] != 9 { leaf_nodes.push((i, j-1)); } - if j < width-1 && !explored_spots.contains(&(i, j+1)) && grid[i][j+1] != 9 { leaf_nodes.push((i, j+1)); } - } + let (i, j) = leaf_node; + if i > 0 && !explored_spots.contains(&(i - 1, j)) && grid[i - 1][j] != 9 { + leaf_nodes.push((i - 1, j)); + } + if i < height - 1 && !explored_spots.contains(&(i + 1, j)) && grid[i + 1][j] != 9 { + leaf_nodes.push((i + 1, j)); + } + if j > 0 && !explored_spots.contains(&(i, j - 1)) && grid[i][j - 1] != 9 { + leaf_nodes.push((i, j - 1)); + } + if j < width - 1 && !explored_spots.contains(&(i, j + 1)) && grid[i][j + 1] != 9 { + leaf_nodes.push((i, j + 1)); + } + } - return explored_spots.len() as u32; + return explored_spots.len() as u32; } fn find_basin_sizes(grid: &Vec>) -> Vec { - let mut sizes = Vec::new(); - for low_point in find_low_points(&grid) { - sizes.push(find_basin_size(grid, low_point)) - } - return sizes; + let mut sizes = Vec::new(); + for low_point in find_low_points(&grid) { + sizes.push(find_basin_size(grid, low_point)) + } + return sizes; } pub fn part2(grid: Vec>) -> u32 { - let mut basin_sizes = find_basin_sizes(&grid); - basin_sizes.sort_by(|a, b| b.cmp(a)); - return basin_sizes[0] * basin_sizes[1] * basin_sizes[2]; + let mut basin_sizes = find_basin_sizes(&grid); + basin_sizes.sort_by(|a, b| b.cmp(a)); + return basin_sizes[0] * basin_sizes[1] * basin_sizes[2]; } - #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] - fn part1_example() { - let input = vec![ - vec![2, 1, 9, 9, 9, 4, 3, 2, 1, 0], - vec![3, 9, 8, 7, 8, 9, 4, 9, 2, 1], - vec![9, 8, 5, 6, 7, 8, 9, 8, 9, 2], - vec![8, 7, 6, 7, 8, 9, 6, 7, 8, 9], - vec![9, 8, 9, 9, 9, 6, 5, 6, 7, 8] - ]; - let result = part1(input); - assert_eq!(result, 15); - } + #[test] + fn part1_example() { + let input = vec![ + vec![2, 1, 9, 9, 9, 4, 3, 2, 1, 0], + vec![3, 9, 8, 7, 8, 9, 4, 9, 2, 1], + vec![9, 8, 5, 6, 7, 8, 9, 8, 9, 2], + vec![8, 7, 6, 7, 8, 9, 6, 7, 8, 9], + vec![9, 8, 9, 9, 9, 6, 5, 6, 7, 8], + ]; + let result = part1(input); + assert_eq!(result, 15); + } - #[test] - fn part2_example() { - let input = vec![ - vec![2, 1, 9, 9, 9, 4, 3, 2, 1, 0], - vec![3, 9, 8, 7, 8, 9, 4, 9, 2, 1], - vec![9, 8, 5, 6, 7, 8, 9, 8, 9, 2], - vec![8, 7, 6, 7, 8, 9, 6, 7, 8, 9], - vec![9, 8, 9, 9, 9, 6, 5, 6, 7, 8] - ]; - let result = part2(input); - assert_eq!(result, 1134); - } + #[test] + fn part2_example() { + let input = vec![ + vec![2, 1, 9, 9, 9, 4, 3, 2, 1, 0], + vec![3, 9, 8, 7, 8, 9, 4, 9, 2, 1], + vec![9, 8, 5, 6, 7, 8, 9, 8, 9, 2], + vec![8, 7, 6, 7, 8, 9, 6, 7, 8, 9], + vec![9, 8, 9, 9, 9, 6, 5, 6, 7, 8], + ]; + let result = part2(input); + assert_eq!(result, 1134); + } } diff --git a/src/main.rs b/src/main.rs index 1fdae7a..f618c10 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,7 @@ mod day19; mod day20; mod day21; mod day22; +mod day23; use std::{env, process}; use std::fs::File; @@ -80,6 +81,8 @@ fn run(day: i32, part: i32, input_filename: &str) { "21.2" => println!("{}", day21::part2(&day21::parse_input(&contents))), "22.1" => println!("{}", day22::part1(&day22::parse_input(&contents))), "22.2" => println!("{}", day22::part2(day22::parse_input(&contents))), + "23.1" => println!("{}", day23::part1(&day23::parse_input(&contents))), + "23.2" => println!("{}", day23::part2(&day23::parse_input(&contents))), _ => println!("Day {} part {} not found", day, part) } }