Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use std::env;
- use std::io::{prelude::*, BufReader};
- use std::fs::File;
- use std::ops::RangeInclusive;
- use std::collections::HashMap;
- use std::cmp::{min,max};
- extern crate regex;
- use regex::Regex;
- #[derive(Clone,Debug)]
- struct Cuboid {
- status: bool,
- x: RangeInclusive<i64>,
- y: RangeInclusive<i64>,
- z: RangeInclusive<i64>,
- }
- impl From<&String> for Cuboid {
- fn from(s: &String) -> Self {
- let re = Regex::new(r"(on|off) x=(\-*\d+)\.\.(\-*\d+),y=(\-*\d+)\.\.(\-*\d+),z=(\-*\d+)\.\.(\-*\d+)").unwrap();
- let matches = re.captures(s).unwrap();
- let status = match &matches[1] {
- "on" => true,
- "off" => false,
- _ => unreachable!()
- };
- Self {
- status: status,
- x: (matches[2].parse().unwrap()..=matches[3].parse().unwrap()),
- y: (matches[4].parse().unwrap()..=matches[5].parse().unwrap()),
- z: (matches[6].parse().unwrap()..=matches[7].parse().unwrap()),
- }
- }
- }
- impl Cuboid {
- pub fn new(x: RangeInclusive<i64>, y: RangeInclusive<i64>, z: RangeInclusive<i64>, status: bool) -> Self {
- Self { status: status, x: x, y: y, z: z }
- }
- pub fn raw_volume(&self) -> i64 {
- range_size(&self.x) * range_size(&self.y) * range_size(&self.z)
- }
- pub fn signed_volume(&self) -> i64 {
- self.raw_volume() * if self.status { 1 } else { -1 }
- }
- pub fn intersection(&self, other: &Cuboid, status: bool) -> Cuboid {
- let xsect = RangeInclusive::new(*max(self.x.start(), other.x.start()), *min(self.x.end(), other.x.end()));
- let ysect = RangeInclusive::new(*max(self.y.start(), other.y.start()), *min(self.y.end(), other.y.end()));
- let zsect = RangeInclusive::new(*max(self.z.start(), other.z.start()), *min(self.z.end(), other.z.end()));
- Cuboid::new(xsect, ysect, zsect, status)
- }
- pub fn intersects(&self, other: &Cuboid) -> bool {
- // intersection: (max(a.begin, b.begin), min(a.end, b.end))
- let xsect = RangeInclusive::new(*max(self.x.start(), other.x.start()), *min(self.x.end(), other.x.end()));
- let ysect = RangeInclusive::new(*max(self.y.start(), other.y.start()), *min(self.y.end(), other.y.end()));
- let zsect = RangeInclusive::new(*max(self.z.start(), other.z.start()), *min(self.z.end(), other.z.end()));
- !xsect.is_empty() && !ysect.is_empty() && !zsect.is_empty()
- }
- }
- fn range_size(range: &RangeInclusive<i64>) -> i64 {
- if !range.is_empty() { range.end() - range.start() + 1 } else { 0 }
- }
- fn solve2(input: &str) {
- let file = File::open(input).expect("Input file not found.");
- let reader = BufReader::new(file);
- // Input
- let input: Vec<String> = match reader.lines().collect() {
- Err(err) => panic!("Unknown error reading input: {}", err),
- Ok(result) => result,
- };
- let cuboids: Vec<_> = input.iter().map(Cuboid::from).collect();
- // Process instructions
- let mut final_cuboids: Vec<Cuboid> = Vec::new();
- for cuboid in &cuboids {
- let mut new_cuboids: Vec<Cuboid> = Vec::new();
- for final_cuboid in &final_cuboids {
- if cuboid.intersects(final_cuboid) {
- let new_status = if cuboid.status && final_cuboid.status { false }
- else if !cuboid.status && !final_cuboid.status { true }
- else { cuboid.status };
- new_cuboids.push(cuboid.intersection(&final_cuboid,new_status));
- }
- }
- if cuboid.status { final_cuboids.push(cuboid.clone()); }
- final_cuboids.append(&mut new_cuboids);
- }
- // Count volumes
- let part2: i64 = final_cuboids
- .iter()
- .map(|s| s.signed_volume())
- .sum();
- println!("Part 2: {}", part2); // 1334238660555542
- }
- fn solve1(input: &str) {
- let file = File::open(input).expect("Input file not found.");
- let reader = BufReader::new(file);
- // Input
- let input: Vec<String> = match reader.lines().collect() {
- Err(err) => panic!("Unknown error reading input: {}", err),
- Ok(result) => result,
- };
- let steps: Vec<_> = input.iter().map(Cuboid::from).collect();
- // Reboot
- let mut reactor: HashMap<(i64,i64,i64),bool> = HashMap::new();
- steps.iter().for_each(|s| {
- let xmin = std::cmp::max(s.x.start(),&-50i64);
- let xmax = std::cmp::min(s.x.end(),&50i64);
- let ymin = std::cmp::max(s.y.start(),&-50i64);
- let ymax = std::cmp::min(s.y.end(),&50i64);
- let zmin = std::cmp::max(s.z.start(),&-50i64);
- let zmax = std::cmp::min(s.z.end(),&50i64);
- for z in *zmin..=*zmax {
- for y in *ymin..=*ymax {
- for x in *xmin..=*xmax {
- if s.status {
- reactor.insert((x,y,z),true);
- } else {
- reactor.remove(&(x,y,z));
- }
- }
- }
- }
- });
- let part1 = reactor.iter().filter(|&(_,v)| *v).count();
- println!("Part 1: {}", part1); // 580012
- }
- fn main() {
- let args: Vec<String> = env::args().collect();
- let filename = &args[1];
- solve1(&filename);
- solve2(&filename);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement