main.rs (4135B)
1 use std::collections::{HashMap, HashSet}; 2 3 #[derive(Debug, Clone, Copy, Eq, PartialEq)] 4 enum Command { 5 On, 6 Off, 7 } 8 9 #[derive(Debug, Clone, Copy)] 10 struct Cuboid { 11 x: (i32, i32), 12 y: (i32, i32), 13 z: (i32, i32), 14 } 15 16 impl Cuboid { 17 fn new(s: &str) -> Self { 18 let ranges = s 19 .split(',') 20 .map(|x| x.split('=').skip(1).next().unwrap().to_string()) 21 .map(|x| { 22 let mut it = x.split(".."); 23 ( 24 it.next().unwrap().parse::<i32>().unwrap(), 25 it.next().unwrap().parse::<i32>().unwrap(), 26 ) 27 }) 28 .collect::<Vec<_>>(); 29 Cuboid { 30 x: ranges[0], 31 y: ranges[1], 32 z: ranges[2], 33 } 34 } 35 36 fn within(&self, other: &Cuboid) -> bool { 37 (self.x.0 >= other.x.0 && self.x.1 <= other.x.1) 38 && (self.y.0 >= other.y.0 && self.y.1 <= other.y.1) 39 && (self.z.0 >= other.z.0 && self.z.1 <= other.z.1) 40 } 41 } 42 43 fn main() { 44 let input = std::fs::read_to_string("input.txt") 45 .unwrap() 46 .trim() 47 .split('\n') 48 .map(|s| { 49 let mut it = s.split(' '); 50 let cmd = match it.next().unwrap() { 51 "on" => Command::On, 52 "off" => Command::Off, 53 _ => unreachable!(), 54 }; 55 let cuboid = Cuboid::new(it.next().unwrap()); 56 (cmd, cuboid) 57 }) 58 .collect::<Vec<_>>(); 59 // 547648 60 println!("Part 1: {}", part_1(&input)); 61 // 1206644425246111 62 println!("Part 2: {}", part_2(&input)); 63 } 64 65 fn run_command(input: &[(Command, Cuboid)]) -> usize { 66 // decompose input space 67 let mut xs = HashSet::new(); 68 let mut ys = HashSet::new(); 69 let mut zs = HashSet::new(); 70 for &(_, cubmoid) in input.iter() { 71 // convert into traditional index format 72 xs.insert(cubmoid.x.0); 73 xs.insert(cubmoid.x.1 + 1); 74 ys.insert(cubmoid.y.0); 75 ys.insert(cubmoid.y.1 + 1); 76 zs.insert(cubmoid.z.0); 77 zs.insert(cubmoid.z.1 + 1); 78 } 79 let mut xs = xs.into_iter().collect::<Vec<_>>(); 80 xs.sort(); 81 let mut ys = ys.into_iter().collect::<Vec<_>>(); 82 ys.sort(); 83 let mut zs = zs.into_iter().collect::<Vec<_>>(); 84 zs.sort(); 85 let xs_idx = xs 86 .iter() 87 .enumerate() 88 .map(|(i, x)| (*x, i)) 89 .collect::<HashMap<i32, usize>>(); 90 let ys_idx = ys 91 .iter() 92 .enumerate() 93 .map(|(i, y)| (*y, i)) 94 .collect::<HashMap<i32, usize>>(); 95 let zs_idx = zs 96 .iter() 97 .enumerate() 98 .map(|(i, z)| (*z, i)) 99 .collect::<HashMap<i32, usize>>(); 100 101 let mut cuboid_state = HashMap::new(); 102 for &(cmd, cuboid) in input.iter() { 103 let x_idx_min = xs_idx[&cuboid.x.0]; 104 let x_idx_max = xs_idx[&(cuboid.x.1 + 1)]; 105 let y_idx_min = ys_idx[&cuboid.y.0]; 106 let y_idx_max = ys_idx[&(cuboid.y.1 + 1)]; 107 let z_idx_min = zs_idx[&cuboid.z.0]; 108 let z_idx_max = zs_idx[&(cuboid.z.1 + 1)]; 109 110 for x_idx in x_idx_min..x_idx_max { 111 for y_idx in y_idx_min..y_idx_max { 112 for z_idx in z_idx_min..z_idx_max { 113 cuboid_state.insert((x_idx, y_idx, z_idx), cmd); 114 } 115 } 116 } 117 } 118 cuboid_state 119 .iter() 120 .map(|(&(x_idx, y_idx, z_idx), cmd)| match cmd { 121 Command::On => { 122 (xs[x_idx + 1] - xs[x_idx]) as usize 123 * (ys[y_idx + 1] - ys[y_idx]) as usize 124 * (zs[z_idx + 1] - zs[z_idx]) as usize 125 } 126 Command::Off => 0, 127 }) 128 .sum() 129 } 130 131 fn part_1(input: &[(Command, Cuboid)]) -> usize { 132 let init_region = Cuboid { 133 x: (-50, 50), 134 y: (-50, 50), 135 z: (-50, 50), 136 }; 137 let init_end = input 138 .iter() 139 .enumerate() 140 .find(|(_, &(_, cuboid))| !cuboid.within(&init_region)) 141 .unwrap() 142 .0; 143 run_command(&input[..init_end]) 144 } 145 146 fn part_2(input: &[(Command, Cuboid)]) -> usize { 147 run_command(input) 148 }