Day 9
This commit is contained in:
		
							
								
								
									
										7
									
								
								day9/Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								day9/Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| # This file is automatically @generated by Cargo. | ||||
| # It is not intended for manual editing. | ||||
| version = 3 | ||||
|  | ||||
| [[package]] | ||||
| name = "day9" | ||||
| version = "0.1.0" | ||||
							
								
								
									
										2000
									
								
								day9/input.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2000
									
								
								day9/input.txt
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										171
									
								
								day9/src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										171
									
								
								day9/src/main.rs
									
									
									
									
									
								
							| @@ -1,3 +1,170 @@ | ||||
| fn main() { | ||||
|     println!("Hello, world!"); | ||||
| use std::{ | ||||
|     collections::HashSet, | ||||
|     fs::read_to_string, | ||||
|     mem::MaybeUninit, | ||||
|     ops::{Add, AddAssign, Sub, SubAssign}, | ||||
| }; | ||||
|  | ||||
| #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||||
| enum Direction { | ||||
|     Up, | ||||
|     Down, | ||||
|     Left, | ||||
|     Right, | ||||
| } | ||||
|  | ||||
| impl TryFrom<&str> for Direction { | ||||
|     type Error = &'static str; | ||||
|  | ||||
|     fn try_from(value: &str) -> Result<Self, Self::Error> { | ||||
|         match value { | ||||
|             "U" => Ok(Self::Up), | ||||
|             "D" => Ok(Self::Down), | ||||
|             "L" => Ok(Self::Left), | ||||
|             "R" => Ok(Self::Right), | ||||
|             _ => Err("invalid Direction"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||||
| struct Movement { | ||||
|     direction: Direction, | ||||
|     steps: usize, | ||||
| } | ||||
|  | ||||
| impl TryFrom<&str> for Movement { | ||||
|     type Error = &'static str; | ||||
|  | ||||
|     fn try_from(value: &str) -> Result<Self, Self::Error> { | ||||
|         let words = value.split_whitespace().collect::<Vec<_>>(); | ||||
|         match &words[..] { | ||||
|             [direction, steps] => Ok(Movement { | ||||
|                 direction: Direction::try_from(*direction)?, | ||||
|                 steps: match steps.parse::<usize>() { | ||||
|                     Ok(it) => it, | ||||
|                     Err(_) => return Err("unable to parse steps"), | ||||
|                 }, | ||||
|             }), | ||||
|             _ => Err("Need 2 words in format [Direction] [Steps]"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Eq, PartialEq, Clone, Copy, Default, Hash)] | ||||
| struct Position { | ||||
|     x: i32, | ||||
|     y: i32, | ||||
| } | ||||
|  | ||||
| impl Add for Position { | ||||
|     type Output = Position; | ||||
|  | ||||
|     fn add(self, rhs: Self) -> Self::Output { | ||||
|         Self { | ||||
|             x: self.x + rhs.x, | ||||
|             y: self.y + rhs.y, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl AddAssign for Position { | ||||
|     fn add_assign(&mut self, rhs: Self) { | ||||
|         self.x += rhs.x; | ||||
|         self.y += rhs.y; | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Sub for Position { | ||||
|     type Output = Position; | ||||
|  | ||||
|     fn sub(self, rhs: Self) -> Self::Output { | ||||
|         Self { | ||||
|             x: self.x - rhs.x, | ||||
|             y: self.y - rhs.y, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl SubAssign for Position { | ||||
|     fn sub_assign(&mut self, rhs: Self) { | ||||
|         self.x += rhs.x; | ||||
|         self.y += rhs.y; | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Eq, PartialEq, Clone, Default)] | ||||
| struct Link { | ||||
|     head: Position, | ||||
|     tail: Position, | ||||
|     tail_positions: HashSet<Position>, | ||||
| } | ||||
|  | ||||
| impl Link { | ||||
|     fn simulate_position(&mut self, head_position: &Position) { | ||||
|         self.head = *head_position; | ||||
|         let distance = self.head - self.tail; | ||||
|         if distance.x.abs() > 1 || distance.y.abs() > 1 { | ||||
|             self.tail.x += distance.x.signum(); | ||||
|             self.tail.y += distance.y.signum(); | ||||
|         } | ||||
|         self.tail_positions.insert(self.tail); | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Eq, PartialEq, Clone)] | ||||
| struct Rope<const N: usize> { | ||||
|     links: [Link; N], | ||||
| } | ||||
|  | ||||
| impl<const N: usize> Rope<N> { | ||||
|     fn simulate(mut self, movement: &Movement) -> Self { | ||||
|         for _ in 0..movement.steps { | ||||
|             let head_position = self.links[0].head | ||||
|                 + match movement.direction { | ||||
|                     Direction::Up => Position { x: 0, y: -1 }, | ||||
|                     Direction::Down => Position { x: 0, y: 1 }, | ||||
|                     Direction::Left => Position { x: -1, y: 0 }, | ||||
|                     Direction::Right => Position { x: 1, y: 0 }, | ||||
|                 }; | ||||
|             self.links[0].simulate_position(&head_position); | ||||
|             for i in 1..self.links.len() { | ||||
|                 let previous = self.links[i - 1].tail; | ||||
|                 self.links[i].simulate_position(&previous); | ||||
|             } | ||||
|         } | ||||
|         self | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<const N: usize> Default for Rope<N> { | ||||
|     fn default() -> Self { | ||||
|         let mut links: [Link; N] = unsafe { MaybeUninit::zeroed().assume_init() }; | ||||
|         links.fill(Default::default()); | ||||
|         Self { links } | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn main() { | ||||
|     let input = "R 5 | ||||
| U 8 | ||||
| L 8 | ||||
| D 3 | ||||
| R 17 | ||||
| D 10 | ||||
| L 25 | ||||
| U 20"; | ||||
|     let input = read_to_string("input.txt").unwrap_or_else(|_| input.to_owned()); | ||||
|  | ||||
|     let rope = input | ||||
|         .lines() | ||||
|         .flat_map(Movement::try_from) | ||||
|         .fold(Rope::<9>::default(), |rope, movement| { | ||||
|             rope.simulate(&movement) | ||||
|         }); | ||||
|     println!( | ||||
|         "The second knot visited {} positions, the tail visited {} positions", | ||||
|         rope.links[0].tail_positions.len(), | ||||
|         rope.links[8].tail_positions.len() | ||||
|     ); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user