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.
This commit is contained in:
Peter 2022-12-10 02:06:38 +08:00
parent bb88b5b7ec
commit dd3ec11462
2 changed files with 242 additions and 1 deletions

View File

@ -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::<usize>().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!();
}
}

121
day_9/src/main_pt1.rs Normal file
View File

@ -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::<i32>().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::<usize>().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());
}