diff --git a/src/day10.rs b/src/day10.rs index 90754f2..9a5eb39 100644 --- a/src/day10.rs +++ b/src/day10.rs @@ -15,17 +15,22 @@ fn is_opening(c: char) -> bool { 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") + } +} + fn find_corrupted_chunk_symbol(line: &str) -> Option { let mut active_chunks: Vec = Vec::new(); for c in line.chars() { - let variant = match c { - '('|')' => ChunkVariant::Parenthesis, - '['|']' => ChunkVariant::Bracket, - '{'|'}' => ChunkVariant::Curly, - '<'|'>' => ChunkVariant::Pointy, - _ => panic!("Invalid character found while finding corrupted chunks") - }; - + let variant = get_chunk_variant(c); if is_opening(c) { active_chunks.push(variant); } else { @@ -53,6 +58,42 @@ pub fn part1(lines: &Vec) -> u32 { 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 +} + +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]; +} + #[cfg(test)] mod tests { use super::*; @@ -74,5 +115,23 @@ mod tests { 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); + } } diff --git a/src/main.rs b/src/main.rs index e4853b4..ecc7065 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,6 +43,7 @@ fn run(day: i32, part: i32, input_filename: &str) { "9.1" => println!("{}", day9::part1(day9::parse_input(&contents))), "9.2" => println!("{}", day9::part2(day9::parse_input(&contents))), "10.1" => println!("{}", day10::part1(&day10::parse_input(&contents))), + "10.2" => println!("{}", day10::part2(&day10::parse_input(&contents))), _ => println!("Day {} part {} not found", day, part) } }