From dd3ec114623bc4cd84ef34f76094109fbff979b7 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 10 Dec 2022 02:06:38 +0800 Subject: [PATCH] day 9 i learnt more about how memory safety in rust works and why we need to split a vector when mutating it in two locations to ensure they don't conflict. makes a lot of sense to me now. also learnt that tuples can be used in `match`, makes stuff really clean. --- day_9/src/main.rs | 122 +++++++++++++++++++++++++++++++++++++++++- day_9/src/main_pt1.rs | 121 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 day_9/src/main_pt1.rs diff --git a/day_9/src/main.rs b/day_9/src/main.rs index e7a11a9..23ad9aa 100644 --- a/day_9/src/main.rs +++ b/day_9/src/main.rs @@ -1,3 +1,123 @@ +use std::{collections::HashSet, fs::read_to_string}; + +const PATH: &str = "src/input"; fn main() { - println!("Hello, world!"); + println!("PART 1 {}", rope_sim(2)); + println!("PART 2 {}", rope_sim(10)); +} + +fn rope_sim(rope_size: usize) -> usize { + // FOR PART 1, THERE IS A SMARTER SOLUTION BUT WITH THE SIZE OF THE INPUT WE CAN DO IT WITH THE NAIVE SOLUTION. + let binding = read_to_string(PATH).expect("Error reading file"); + assert!(binding.is_ascii()); + let data = binding.trim().split('\n').into_iter(); + + // WTF IS THIS??? + let mut rope = Vec::<(i32, i32)>::new(); + for _ in 0..rope_size { + rope.push((0, 0)); + } + + let mut tail_points = HashSet::<(i32, i32)>::new(); + tail_points.insert(*rope.last().unwrap()); + + for instruction in data { + let mut tokens = instruction.split_ascii_whitespace().into_iter(); + let dir = tokens.next().unwrap(); + let mag = tokens.next().unwrap().parse::().unwrap(); + + for _ in 0..mag { + // println!("({},{}), ({},{})", v_t.0, v_t.1, v_h.0, v_h.1); + move_head(rope.get_mut(0).unwrap(), dir); + for rope_part_i in 1..rope_size { + // SEGMENT HEAD AND TAIL. + let (part_1, part_2) = rope.split_at_mut(rope_part_i); + let v_dh = part_1.get_mut(rope_part_i - 1).unwrap(); //rope.get_mut(rope_part_i - 1).unwrap() + let v_dt = part_2.get_mut(0).unwrap(); //rope.get_mut(rope_part_i).unwrap() + rule_1(&v_dh, v_dt); + rule_2(&v_dh, v_dt); + } + tail_points.insert(*rope.last().unwrap()); + } + // print_grid(12, &mut tail_points); + } + return tail_points.len(); +} + +fn move_head(v_h: &mut (i32, i32), dir: &str) { + let dir_p = dir.chars().nth(0).unwrap(); + match dir_p { + 'U' => v_h.1 -= 1, + 'D' => v_h.1 += 1, + 'L' => v_h.0 -= 1, + 'R' => v_h.0 += 1, + _ => { + panic!() + } + }; +} + +fn rule_1(v_h: &(i32, i32), v_t: &mut (i32, i32)) { + let di = v_h.0 - v_t.0; + let dj = v_h.1 - v_t.1; + + let change = match (di, dj) { + (2, 0) => (1, 0), + (0, 2) => (0, 1), + (-2, 0) => (-1, 0), + (0, -2) => (0, -1), + _ => (0, 0), + }; + v_t.0 += change.0; + v_t.1 += change.1; +} + +fn rule_2(v_h: &(i32, i32), v_t: &mut (i32, i32)) { + let di = v_h.0 - v_t.0; + let dj = v_h.1 - v_t.1; + + let change: (i32, i32) = match (di, dj) { + (1, 2) => (1, 1), + (2, 1) => (1, 1), + (2, 2) => (1, 1), + + (-2, -1) => (-1, -1), + (-1, -2) => (-1, -1), + (-2, -2) => (-1, -1), + + (1, -2) => (1, -1), + (2, -1) => (1, -1), + (2, -2) => (1, -1), + + (-1, 2) => (-1, 1), + (-2, 1) => (-1, 1), + (-2, 2) => (-1, 1), + _ => (0, 0), + }; + v_t.0 += change.0; + v_t.1 += change.1; +} + +fn print_grid( + r: i32, + tail_points: &mut HashSet<(i32, i32)>, + // v_h: &(i32, i32), + // v_t: &mut (i32, i32), +) { + for j in -r..r { + for i in -r..r { + if i == 0 && j == 0 { + print!("S"); + // } else if i == v_h.0 && j == v_h.1 { + // print!("H") + // } else if i == v_t.0 && j == v_t.1 { + // print!("T") + } else if tail_points.contains(&(i, j)) { + print!("X"); + } else { + print!("-"); + } + } + println!(); + } } diff --git a/day_9/src/main_pt1.rs b/day_9/src/main_pt1.rs new file mode 100644 index 0000000..7ed147d --- /dev/null +++ b/day_9/src/main_pt1.rs @@ -0,0 +1,121 @@ +use std::{collections::HashSet, fs::read_to_string}; + +fn parse_direction(dir: &str, mag: &str) -> (i32, i32) { + let dir_p = dir.chars().nth(0).unwrap(); + let mag_p = mag.parse::().unwrap(); + let v = match dir_p { + 'U' => (0, -mag_p), + 'D' => (0, mag_p), + 'L' => (-mag_p, 0), + 'R' => (mag_p, 0), + _ => { + panic!() + } + }; + return v; +} + +fn move_head(v_h: &mut (i32, i32), dir: &str) { + let dir_p = dir.chars().nth(0).unwrap(); + match dir_p { + 'U' => v_h.1 -= 1, + 'D' => v_h.1 += 1, + 'L' => v_h.0 -= 1, + 'R' => v_h.0 += 1, + _ => { + panic!() + } + }; +} + +fn rule_1(v_h: &(i32, i32), v_t: &mut (i32, i32)) { + let di = v_h.0 - v_t.0; + let dj = v_h.1 - v_t.1; + + let change = match (di, dj) { + (2, 0) => (1, 0), + (0, 2) => (0, 1), + (-2, 0) => (-1, 0), + (0, -2) => (0, -1), + _ => (0, 0), + }; + v_t.0 += change.0; + v_t.1 += change.1; +} + +fn rule_2(v_h: &(i32, i32), v_t: &mut (i32, i32)) { + let di = v_h.0 - v_t.0; + let dj = v_h.1 - v_t.1; + + let change: (i32, i32) = match (di, dj) { + (1, 2) => (1, 1), + (2, 1) => (1, 1), + + (-2, -1) => (-1, -1), + (-1, -2) => (-1, -1), + + (1, -2) => (1, -1), + (2, -1) => (1, -1), + + (-1, 2) => (-1, 1), + (-2, 1) => (-1, 1), + _ => (0, 0), + }; + v_t.0 += change.0; + v_t.1 += change.1; +} + +fn print_grid( + r: i32, + tail_points: &mut HashSet<(i32, i32)>, + v_h: &(i32, i32), + v_t: &mut (i32, i32), +) { + for j in -r..r { + for i in -r..r { + if i == 0 && j == 0 { + print!("S"); + // } else if i == v_h.0 && j == v_h.1 { + // print!("H") + // } else if i == v_t.0 && j == v_t.1 { + // print!("T") + } else if tail_points.contains(&(i, j)) { + print!("X"); + } else { + print!("-"); + } + } + println!(); + } +} + +const PATH: &str = "src/input"; +fn main() { + // FOR PART 1, THERE IS A SMARTER SOLUTION BUT WITH THE SIZE OF THE INPUT WE CAN DO IT WITH THE NAIVE SOLUTION. + let mut tail_points = HashSet::<(i32, i32)>::new(); + let binding = read_to_string(PATH).expect("Error reading file"); + assert!(binding.is_ascii()); + let data = binding.trim().split('\n').into_iter(); + + let v_h = &mut (0, 0); + let v_t = &mut (0, 0); + for instruction in data { + let mut tokens = instruction.split_ascii_whitespace().into_iter(); + let dir = tokens.next().unwrap(); + let mag = tokens.next().unwrap().parse::().unwrap(); + + // println!("{} {}", dir, mag); + + tail_points.insert(*v_t); + + for i in 0..mag { + // println!("({},{}), ({},{})", v_t.0, v_t.1, v_h.0, v_h.1); + move_head(v_h, dir); + rule_1(v_h, v_t); + rule_2(v_h, v_t); + tail_points.insert(*v_t); + } + } + print_grid(5, &mut tail_points, v_h, v_t); + println!("PART 1 {}", tail_points.len()); +}