Skip to content

Instantly share code, notes, and snippets.

@neofight78
Created December 22, 2021 11:13
Show Gist options
  • Save neofight78/8d8c086220c558a41b80bccaf3beb479 to your computer and use it in GitHub Desktop.
Save neofight78/8d8c086220c558a41b80bccaf3beb479 to your computer and use it in GitHub Desktop.
Advent of Code 2021 - Day 22: Reactor Reboot
fn main() {
let steps = parse_steps(INPUT);
let regions = execute_steps(&steps);
let total = regions.iter().map(|c| c.count_cubes()).sum::<i64>();
let inner_region = Cuboid::new(Vector::new(-50, -50, -50), Vector::new(50, 50, 50));
let steps = once((true, inner_region))
.chain(regions.iter().map(|&r| (false, r)))
.collect::<Vec<_>>();
let regions = execute_steps(&steps);
let inner_total =
inner_region.count_cubes() - regions.iter().map(|c| c.count_cubes()).sum::<i64>();
println!("Within the inner region {} cubes are on.", inner_total);
println!("In total {} cubes are on.", total);
}
fn parse_steps(steps: &str) -> Vec<(bool, Cuboid)> {
steps
.lines()
.map(|l| {
let (instruction, cuboid) = l.split_once(' ').unwrap();
let mut ranges = cuboid.split(',').map(|r| {
let (_, range) = r.split_once('=').unwrap();
let bounds = range.split_once("..").unwrap();
(
bounds.0.parse::<i64>().unwrap(),
bounds.1.parse::<i64>().unwrap(),
)
});
let (from_x, to_x) = ranges.next().unwrap();
let (from_y, to_y) = ranges.next().unwrap();
let (from_z, to_z) = ranges.next().unwrap();
let cuboid = Cuboid::new(
Vector::new(from_x, from_y, from_z),
Vector::new(to_x, to_y, to_z),
);
(instruction == "on", cuboid)
})
.collect()
}
fn execute_steps(steps: &[(bool, Cuboid)]) -> Vec<Cuboid> {
let mut existing_regions = Vec::new();
for &(switch_on, cuboid) in steps {
if switch_on {
let mut new_regions = Vec::from([cuboid]);
for region in &existing_regions {
let mut updated_new_regions = Vec::new();
for new in new_regions {
updated_new_regions.append(&mut (new - *region));
}
new_regions = updated_new_regions;
}
existing_regions.append(&mut new_regions);
} else {
let mut new_regions = Vec::new();
for &region in &existing_regions {
new_regions.append(&mut (region - cuboid));
}
existing_regions = new_regions;
}
}
existing_regions
}
#[derive(Clone, Copy, Debug, PartialEq)]
struct Vector {
x: i64,
y: i64,
z: i64,
}
impl Vector {
fn new(x: i64, y: i64, z: i64) -> Self {
Self { x, y, z }
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
struct Cuboid {
from: Vector,
to: Vector,
}
impl Cuboid {
fn new(from: Vector, to: Vector) -> Self {
Self { from, to }
}
fn count_cubes(&self) -> i64 {
((self.from.x - self.to.x).abs() + 1)
* ((self.from.y - self.to.y).abs() + 1)
* ((self.from.z - self.to.z).abs() + 1)
}
}
impl Sub for Cuboid {
type Output = Vec<Self>;
fn sub(self, rhs: Self) -> Self::Output {
let mut new_regions = Vec::new();
let find_overlap_along_axis = |axis: fn(Vector) -> i64| {
let lower_point = i64::max(axis(self.from), axis(rhs.from));
let upper_point = i64::min(axis(self.to), axis(rhs.to));
if lower_point > upper_point {
None
} else {
Some((lower_point, upper_point))
}
};
if let Some((x_lower_point, x_upper_point)) = find_overlap_along_axis(|v| v.x) {
if let Some((y_lower_point, y_upper_point)) = find_overlap_along_axis(|v| v.y) {
if let Some((z_lower_point, z_higher_point)) = find_overlap_along_axis(|v| v.z) {
let mut remainder = self;
// Split X
if x_lower_point > remainder.from.x {
let mut to = remainder.to;
to.x = x_lower_point - 1;
let left = Cuboid::new(remainder.from, to);
new_regions.push(left);
let mut from = remainder.from;
from.x = x_lower_point;
remainder = Cuboid::new(from, remainder.to);
}
if x_upper_point < remainder.to.x {
let mut from = remainder.from;
from.x = x_upper_point + 1;
let right = Cuboid::new(from, remainder.to);
new_regions.push(right);
let mut to = remainder.to;
to.x = x_upper_point;
remainder = Cuboid::new(remainder.from, to);
}
// Split Y
if y_lower_point > remainder.from.y {
let mut to = remainder.to;
to.y = y_lower_point - 1;
let left = Cuboid::new(remainder.from, to);
new_regions.push(left);
let mut from = remainder.from;
from.y = y_lower_point;
remainder = Cuboid::new(from, remainder.to);
}
if y_upper_point < remainder.to.y {
let mut from = remainder.from;
from.y = y_upper_point + 1;
let right = Cuboid::new(from, remainder.to);
new_regions.push(right);
let mut to = remainder.to;
to.y = y_upper_point;
remainder = Cuboid::new(remainder.from, to);
}
// Split Z
if z_lower_point > remainder.from.z {
let mut to = remainder.to;
to.z = z_lower_point - 1;
let left = Cuboid::new(remainder.from, to);
new_regions.push(left);
}
if z_higher_point < remainder.to.z {
let mut from = remainder.from;
from.z = z_higher_point + 1;
let right = Cuboid::new(from, remainder.to);
new_regions.push(right);
}
return new_regions;
}
}
}
new_regions.push(self);
new_regions
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment