generated from janezicmatej/aoc-template
	solution: day 22
This commit is contained in:
		
							
								
								
									
										7
									
								
								data/examples/22.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								data/examples/22.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
1,0,1~1,2,1
 | 
			
		||||
0,0,2~2,0,2
 | 
			
		||||
0,2,3~2,2,3
 | 
			
		||||
0,0,4~0,2,4
 | 
			
		||||
2,0,5~2,2,5
 | 
			
		||||
0,1,6~2,1,6
 | 
			
		||||
1,1,9~1,1,8
 | 
			
		||||
							
								
								
									
										143
									
								
								src/bin/22.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								src/bin/22.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,143 @@
 | 
			
		||||
use std::{collections::HashMap, str::FromStr};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
 | 
			
		||||
struct Brick {
 | 
			
		||||
    from: (usize, usize, usize),
 | 
			
		||||
    to: (usize, usize, usize),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
struct ParseBrickError;
 | 
			
		||||
 | 
			
		||||
impl FromStr for Brick {
 | 
			
		||||
    type Err = ParseBrickError;
 | 
			
		||||
    fn from_str(s: &str) -> Result<Self, Self::Err> {
 | 
			
		||||
        let (first, second) = s.split_once('~').ok_or(ParseBrickError)?;
 | 
			
		||||
 | 
			
		||||
        let sorted: Vec<_> = first
 | 
			
		||||
            .split(',')
 | 
			
		||||
            .filter_map(|y| y.parse().ok())
 | 
			
		||||
            .zip(second.split(',').filter_map(|y| y.parse().ok()))
 | 
			
		||||
            .map(|(x, y)| if x < y { (x, y) } else { (y, x) })
 | 
			
		||||
            .collect();
 | 
			
		||||
        let from = (sorted[0].0, sorted[1].0, sorted[2].0);
 | 
			
		||||
        let to = (sorted[0].1, sorted[1].1, sorted[2].1);
 | 
			
		||||
 | 
			
		||||
        Ok(Self { from, to })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Brick {
 | 
			
		||||
    fn height(&self) -> usize {
 | 
			
		||||
        self.to.2 - self.from.2 + 1
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn points(&self) -> impl Iterator<Item = (usize, usize, usize)> + '_ {
 | 
			
		||||
        (self.from.0..=self.to.0).flat_map(move |x| {
 | 
			
		||||
            (self.from.1..=self.to.1)
 | 
			
		||||
                .flat_map(move |y| (self.from.2..=self.to.2).map(move |z| (x, y, z)))
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PartialOrd for Brick {
 | 
			
		||||
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
 | 
			
		||||
        Some(self.cmp(other))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Ord for Brick {
 | 
			
		||||
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
 | 
			
		||||
        self.from
 | 
			
		||||
            .2
 | 
			
		||||
            .cmp(&other.from.2)
 | 
			
		||||
            .then((self.from.0, self.from.1).cmp(&(other.from.0, other.from.1)))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
struct Tower {
 | 
			
		||||
    bricks: Vec<Brick>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Tower {
 | 
			
		||||
    fn new(mut bricks: Vec<Brick>) -> Self {
 | 
			
		||||
        bricks.sort();
 | 
			
		||||
        let mut ret = Self { bricks };
 | 
			
		||||
        ret.compress(None);
 | 
			
		||||
        ret
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn compress(&mut self, skip: Option<usize>) -> usize {
 | 
			
		||||
        let mut heights: HashMap<(usize, usize), usize> = HashMap::new();
 | 
			
		||||
        let mut moved = 0;
 | 
			
		||||
 | 
			
		||||
        for brick in self
 | 
			
		||||
            .bricks
 | 
			
		||||
            .iter_mut()
 | 
			
		||||
            .enumerate()
 | 
			
		||||
            .filter(|(i, _)| *i != skip.unwrap_or(usize::MAX))
 | 
			
		||||
            .map(|(_, x)| x)
 | 
			
		||||
        {
 | 
			
		||||
            let height = brick.height();
 | 
			
		||||
            let new_height = brick
 | 
			
		||||
                .points()
 | 
			
		||||
                .map(|(x, y, _)| *heights.entry((x, y)).or_default())
 | 
			
		||||
                .max()
 | 
			
		||||
                .unwrap();
 | 
			
		||||
 | 
			
		||||
            for (x, y, _) in brick.points() {
 | 
			
		||||
                *heights.get_mut(&(x, y)).unwrap() = new_height + height;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if new_height + 1 == brick.from.2 {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if skip.is_none() {
 | 
			
		||||
                brick.from.2 = new_height + 1;
 | 
			
		||||
                brick.to.2 = new_height + height;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            moved += 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        moved
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn part_one(input: &str) -> Option<usize> {
 | 
			
		||||
    let mut tower = Tower::new(input.lines().filter_map(|x| x.parse().ok()).collect());
 | 
			
		||||
 | 
			
		||||
    Some(
 | 
			
		||||
        (0..tower.bricks.len())
 | 
			
		||||
            .map(|i| tower.compress(Some(i)))
 | 
			
		||||
            .filter(|m| *m == 0)
 | 
			
		||||
            .count(),
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn part_two(input: &str) -> Option<usize> {
 | 
			
		||||
    let mut tower = Tower::new(input.lines().filter_map(|x| x.parse().ok()).collect());
 | 
			
		||||
 | 
			
		||||
    Some(
 | 
			
		||||
        (0..tower.bricks.len())
 | 
			
		||||
            .map(|i| tower.compress(Some(i)))
 | 
			
		||||
            .sum(),
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
aoc::solution!(22);
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_part_one() {
 | 
			
		||||
        assert_eq!(part_one(&aoc::template::read_file("examples", 22)), Some(5));
 | 
			
		||||
    }
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_part_two() {
 | 
			
		||||
        assert_eq!(part_two(&aoc::template::read_file("examples", 22)), Some(7));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user