use std::collections::HashMap; fn main() { let contents = std::fs::read_to_string("data.txt").expect("Failed to read file"); let lines = contents.lines().collect::>(); let mut hash: HashMap<(i32, i32), bool> = HashMap::new(); run(&lines, &mut hash, 1); let part_1 = hash.keys().len(); println!("Num visited, part 1: {:?}", part_1); let mut hash2: HashMap<(i32, i32), bool> = HashMap::new(); run(&lines, &mut hash2, 9); let part_2 = hash2.keys().len(); println!("Num visited, part 2: {:?}", part_2); } fn run(lines: &Vec<&str>, hash: &mut HashMap<(i32, i32), bool>, num_tails: usize) { let mut head = (0i32, 0i32); let mut tails: Vec<(i32, i32)> = vec![(0, 0); num_tails]; for line in lines { let (dir, steps) = line.split_once(" ").unwrap(); for _ in 0..steps.parse().unwrap() { match dir { "L" => head = (head.0, head.1 - 1), "R" => head = (head.0, head.1 + 1), "U" => head = (head.0 - 1, head.1), "D" => head = (head.0 + 1, head.1), _ => (), } // println!("\nnew head location {:?}", head); let mut parent = head; for tail_i in 0..num_tails { let mut tail = tails[tail_i]; // find the distance from parent to tail let v_dist = parent.0 - tail.0; let h_dist = parent.1 - tail.1; let mut already_moved_diagonally = false; // move vertically if v_dist.abs() > 1 { let v_diff = v_dist / v_dist.abs(); tail = (tail.0 + v_diff, tail.1); // do we need to move horizontally? if parent.1 != tail.1 { let h_diff = h_dist / h_dist.abs(); tail = (tail.0, tail.1 + h_diff); already_moved_diagonally = true; } } // move horizontally if h_dist.abs() > 1 && !already_moved_diagonally { let h_diff = h_dist / h_dist.abs(); tail = (tail.0, tail.1 + h_diff); // do we need to move horizontally? if parent.0 != tail.0 { let v_diff = v_dist / v_dist.abs(); tail = (tail.0 + v_diff, tail.1); } } // println!("new tail ({:?}) location {:?}", tail_i + 1, tail); if tail_i == num_tails - 1 { // for the last tail, record where it has been hash.insert(tail, true); } tails[tail_i] = tail; parent = tail; } } let mut temp = tails.to_owned(); temp.insert(0, head); display(temp); } } fn display(rope: Vec<(i32, i32)>) -> () { let v_min = rope.iter().map(|x| x.0).min().unwrap(); let v_max = rope.iter().map(|x| x.0).max().unwrap(); let h_min = rope.iter().map(|x| x.1).min().unwrap(); let h_max = rope.iter().map(|x| x.1).max().unwrap(); for v in v_min..=v_max { for h in h_min..=h_max { match rope.iter().position(|&x| x == (v, h)) { Some(i) => print!("{i}"), None => print!("."), } } println!(""); } println!(""); }