use std::collections::HashSet; fn main() { let input = lib::read_input(9); part1(&input); part2(&input); } type P = [i32; 2]; fn part1(input: &str) { let mut visited = HashSet::new(); let mut head = [0, 0]; let mut tail = [0, 0]; visited.insert(tail); for line in input.lines() { let (dir, dist) = line.split_at(1); let dist = dist[1..].parse::().unwrap(); let d = match dir { "L" => [-1, 0], "U" => [0, -1], "D" => [0, 1], "R" => [1, 0], _ => panic!("invalid direction"), }; for _ in 0..dist { head[0] += d[0]; head[1] += d[1]; if distance(tail, head) <= 1 { continue; } let m = len1(tail, head); tail[0] += m[0]; tail[1] += m[1]; visited.insert(tail); } } println!("{}", visited.len()); } fn part2(input: &str) { let mut visited = HashSet::new(); let mut rope = [[0, 0]; 10]; visited.insert(rope[9]); for line in input.lines() { let (dir, dist) = line.split_at(1); let dist = dist[1..].parse::().unwrap(); let d = match dir { "L" => [-1, 0], "U" => [0, -1], "D" => [0, 1], "R" => [1, 0], _ => panic!("invalid direction"), }; for _ in 0..dist { rope[0][0] += d[0]; rope[0][1] += d[1]; for i in 1..rope.len() { if distance(rope[i], rope[i - 1]) <= 1 { break; } let m = len1(rope[i], rope[i - 1]); rope[i][0] += m[0]; rope[i][1] += m[1]; if i == rope.len() - 1 { visited.insert(rope[i]); } } } // print(&visited, &rope); } println!("{}", visited.len()); } fn distance(a: P, b: P) -> i32 { (a[0] - b[0]).abs().max((a[1] - b[1]).abs()) } fn len1(from: P, to: P) -> P { [ (to[0] - from[0]).clamp(-1, 1), (to[1] - from[1]).clamp(-1, 1), ] } fn print(visited: &HashSet

, rope: &[P]) { let x_min = *visited .iter() .map(|[x, _]| x) .min() .unwrap() .min(rope.iter().map(|[x, _]| x).min().unwrap()); let x_max = *visited .iter() .map(|[x, _]| x) .max() .unwrap() .max(rope.iter().map(|[x, _]| x).max().unwrap()); let y_min = *visited .iter() .map(|[_, y]| y) .min() .unwrap() .min(rope.iter().map(|[_, y]| y).min().unwrap()); let y_max = *visited .iter() .map(|[_, y]| y) .max() .unwrap() .max(rope.iter().map(|[_, y]| y).max().unwrap()); for y in y_min..=y_max { for x in x_min..=x_max { if x == 0 && y == 0 { eprint!("\x1b[31m"); } if [x, y] == rope[0] { eprint!("H"); } else if let Some((i, _)) = rope.iter().enumerate().find(|(i, &b)| b == [x, y]) { eprint!("{}", i); } else if visited.contains(&[x, y]) { eprint!("#"); } else { eprint!("."); } eprint!("\x1b[0m"); } eprintln!(); } eprintln!(); }