Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epidemian
GitHub Repository: epidemian/advent-of-code-2021
Path: blob/main/src/day22.rs
97 views
1
pub fn run() {
2
let all_instructions: Vec<Instruction> = include_str!("inputs/day22")
3
.lines()
4
.map(parse_instruction)
5
.collect();
6
7
let init_cuboid = Cuboid {
8
xs: Range::new(-50, 50),
9
ys: Range::new(-50, 50),
10
zs: Range::new(-50, 50),
11
};
12
let init_instructions: Vec<Instruction> = all_instructions
13
.iter()
14
.filter_map(|(v, c)| c.intersect(&init_cuboid).map(|i| (*v, i)))
15
.collect();
16
17
println!("{}", run_instructions(init_instructions));
18
println!("{}", run_instructions(all_instructions));
19
}
20
21
fn run_instructions(instructions: Vec<Instruction>) -> i64 {
22
let mut processed: Vec<Instruction> = vec![];
23
24
for (value, cuboid) in instructions {
25
let negated_intersections: Vec<Instruction> = processed
26
.iter()
27
.filter_map(|(v, c)| c.intersect(&cuboid).map(|i| (-v, i)))
28
.collect();
29
// Avoid counting intersections multiple times by adding their negative values.
30
processed.extend(negated_intersections);
31
if value == ON {
32
processed.push((value, cuboid))
33
}
34
}
35
36
processed.iter().map(|(val, c)| *val * c.size()).sum()
37
}
38
39
const ON: i64 = 1;
40
const OFF: i64 = -1;
41
42
type Instruction = (i64, Cuboid);
43
44
struct Cuboid {
45
xs: Range,
46
ys: Range,
47
zs: Range,
48
}
49
50
struct Range {
51
start: i32,
52
end: i32,
53
}
54
55
fn parse_instruction(s: &str) -> Instruction {
56
let (value, coords) = s.split_once(" ").unwrap();
57
let value = if value == "on" { ON } else { OFF };
58
(value, Cuboid::parse(coords))
59
}
60
61
impl Cuboid {
62
fn parse(s: &str) -> Cuboid {
63
let mut ranges = s
64
.split(",")
65
.map(|s| Range::parse(s.split_once("=").unwrap().1));
66
Cuboid {
67
xs: ranges.next().unwrap(),
68
ys: ranges.next().unwrap(),
69
zs: ranges.next().unwrap(),
70
}
71
}
72
73
fn intersect(&self, other: &Cuboid) -> Option<Cuboid> {
74
match (
75
self.xs.intersect(&other.xs),
76
self.ys.intersect(&other.ys),
77
self.zs.intersect(&other.zs),
78
) {
79
(Some(xs), Some(ys), Some(zs)) => Some(Cuboid { xs, ys, zs }),
80
_ => None,
81
}
82
}
83
84
fn size(&self) -> i64 {
85
self.xs.size() as i64 * self.ys.size() as i64 * self.zs.size() as i64
86
}
87
}
88
89
impl Range {
90
fn parse(s: &str) -> Range {
91
let (start, end) = s.split_once("..").unwrap();
92
Range::new(start.parse().unwrap(), end.parse().unwrap())
93
}
94
95
fn new(start: i32, end: i32) -> Range {
96
Range { start, end }
97
}
98
99
fn intersect(&self, other: &Range) -> Option<Range> {
100
let start = self.start.max(other.start);
101
let end = self.end.min(other.end);
102
if start <= end {
103
Some(Range { start, end })
104
} else {
105
None
106
}
107
}
108
109
fn size(&self) -> i32 {
110
self.end - self.start + 1
111
}
112
}
113
114