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 }