generated from janezicmatej/aoc-template
	solution: day 18
This commit is contained in:
		
							
								
								
									
										14
									
								
								data/examples/18.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								data/examples/18.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | R 6 (#70c710) | ||||||
|  | D 5 (#0dc571) | ||||||
|  | L 2 (#5713f0) | ||||||
|  | D 2 (#d2c081) | ||||||
|  | R 2 (#59c680) | ||||||
|  | D 2 (#411b91) | ||||||
|  | L 5 (#8ceee2) | ||||||
|  | U 2 (#caa173) | ||||||
|  | L 1 (#1b58a2) | ||||||
|  | U 2 (#caa171) | ||||||
|  | R 2 (#7807d2) | ||||||
|  | U 3 (#a77fa3) | ||||||
|  | L 2 (#015232) | ||||||
|  | U 2 (#7a21e3) | ||||||
							
								
								
									
										126
									
								
								src/bin/18.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								src/bin/18.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | |||||||
|  | use std::str::FromStr; | ||||||
|  |  | ||||||
|  | #[derive(Debug, Clone, Copy)] | ||||||
|  | enum Direction { | ||||||
|  |     Up, | ||||||
|  |     Down, | ||||||
|  |     Left, | ||||||
|  |     Right, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
|  | struct ParseDirectionError; | ||||||
|  |  | ||||||
|  | impl FromStr for Direction { | ||||||
|  |     type Err = ParseDirectionError; | ||||||
|  |     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||||
|  |         use Direction::*; | ||||||
|  |  | ||||||
|  |         Ok(match s { | ||||||
|  |             "U" | "3" => Up, | ||||||
|  |             "D" | "1" => Down, | ||||||
|  |             "L" | "2" => Left, | ||||||
|  |             "R" | "0" => Right, | ||||||
|  |             _ => return Err(ParseDirectionError), | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl From<Direction> for (isize, isize) { | ||||||
|  |     fn from(value: Direction) -> Self { | ||||||
|  |         use Direction::*; | ||||||
|  |         match value { | ||||||
|  |             Up => (-1, 0), | ||||||
|  |             Down => (1, 0), | ||||||
|  |             Left => (0, -1), | ||||||
|  |             Right => (0, 1), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn get_area(border: &[(isize, isize)], border_length: isize) -> isize { | ||||||
|  |     // get area with shoelace formula (trapezoid variant) | ||||||
|  |     // https://en.wikipedia.org/wiki/Shoelace_formula | ||||||
|  |     let mut shoelace: isize = 0; | ||||||
|  |     for n in 0..border.len() { | ||||||
|  |         let (y1, x1) = border[n]; | ||||||
|  |         let (y2, x2) = border[(n + 1) % border.len()]; | ||||||
|  |         shoelace += (y1 + y2) * (x1 - x2); | ||||||
|  |     } | ||||||
|  |     let area = shoelace / 2; | ||||||
|  |  | ||||||
|  |     // get interior by inverting pick's theorem formula | ||||||
|  |     // https://en.wikipedia.org/wiki/Pick%27s_theorem | ||||||
|  |     let interior = area + 1 - border_length / 2; | ||||||
|  |     interior + border_length | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn get_border(instructions: &[(Direction, isize)]) -> (Vec<(isize, isize)>, isize) { | ||||||
|  |     let mut border = Vec::new(); | ||||||
|  |     let mut border_length = 0; | ||||||
|  |     let (mut sy, mut sx) = (0, 0); | ||||||
|  |     border.push((sy, sx)); | ||||||
|  |  | ||||||
|  |     for (d, l) in instructions.iter().copied() { | ||||||
|  |         let (dy, dx) = d.into(); | ||||||
|  |         (sy, sx) = (sy + l * dy, sx + l * dx); | ||||||
|  |         border.push((sy, sx)); | ||||||
|  |         border_length += l; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     border.pop(); | ||||||
|  |  | ||||||
|  |     (border, border_length) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn part_one(input: &str) -> Option<isize> { | ||||||
|  |     let instructions: Vec<(Direction, isize)> = input | ||||||
|  |         .lines() | ||||||
|  |         .map(|line| { | ||||||
|  |             let [d, l, _] = line.splitn(3, ' ').collect::<Vec<_>>().try_into().unwrap(); | ||||||
|  |             (d.parse().unwrap(), l.parse::<isize>().unwrap()) | ||||||
|  |         }) | ||||||
|  |         .collect(); | ||||||
|  |  | ||||||
|  |     let (border, border_length) = get_border(&instructions); | ||||||
|  |     Some(get_area(&border, border_length)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn join_option_tuple<T, U>((a, b): (Option<T>, Option<U>)) -> Option<(T, U)> { | ||||||
|  |     Some((a?, b?)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn part_two(input: &str) -> Option<isize> { | ||||||
|  |     let instructions: Vec<(Direction, isize)> = input | ||||||
|  |         .lines() | ||||||
|  |         .filter_map(|line| line.split_once(" (#")) | ||||||
|  |         .filter_map(|(_, h)| h.strip_suffix(')')) | ||||||
|  |         .map(|h| h.split_at(h.len() - 1)) | ||||||
|  |         .map(|(hex, dir)| (dir.parse().ok(), isize::from_str_radix(hex, 16).ok())) | ||||||
|  |         .filter_map(join_option_tuple) | ||||||
|  |         .collect(); | ||||||
|  |  | ||||||
|  |     let (border, border_length) = get_border(&instructions); | ||||||
|  |     Some(get_area(&border, border_length)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | aoc::solution!(18); | ||||||
|  |  | ||||||
|  | #[cfg(test)] | ||||||
|  | mod tests { | ||||||
|  |     use super::*; | ||||||
|  |     #[test] | ||||||
|  |     fn test_part_one() { | ||||||
|  |         assert_eq!( | ||||||
|  |             part_one(&aoc::template::read_file("examples", 18)), | ||||||
|  |             Some(62) | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     #[test] | ||||||
|  |     fn test_part_two() { | ||||||
|  |         assert_eq!( | ||||||
|  |             part_two(&aoc::template::read_file("examples", 18)), | ||||||
|  |             Some(952408144115) | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user