2019-12-08 17:06:45 +01:00
|
|
|
use std::fmt::{self, Write};
|
|
|
|
use std::str::FromStr;
|
|
|
|
|
2020-12-14 19:24:43 +01:00
|
|
|
use anyhow::{Context, Result};
|
2019-12-08 17:06:45 +01:00
|
|
|
|
|
|
|
const IMG_WIDTH: usize = 25;
|
|
|
|
const IMG_HEIGHT: usize = 6;
|
|
|
|
|
|
|
|
const INPUT: &str = include_str!("../input/day08.txt");
|
|
|
|
|
|
|
|
pub fn run() -> Result<String> {
|
|
|
|
let mut res = String::with_capacity(128 + IMG_HEIGHT * IMG_WIDTH);
|
|
|
|
|
|
|
|
let image: Image = INPUT.parse()?;
|
|
|
|
|
|
|
|
writeln!(res, "part 1: {}", part1(&image)?)?;
|
|
|
|
writeln!(res, "part 2:")?;
|
|
|
|
part2(&image, &mut res)?;
|
|
|
|
|
|
|
|
Ok(res)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn part1(image: &Image) -> Result<usize> {
|
|
|
|
let most_zero_layer = image
|
|
|
|
.layers
|
|
|
|
.iter()
|
2019-12-09 16:34:48 +01:00
|
|
|
.min_by_key(|l| l.pixels.iter().flatten().filter(|d| **d == 0).count())
|
2020-12-14 19:24:43 +01:00
|
|
|
.context("image had 0 layers...")?;
|
2019-12-08 17:06:45 +01:00
|
|
|
|
|
|
|
let one_count = most_zero_layer
|
|
|
|
.pixels
|
|
|
|
.iter()
|
2019-12-09 16:34:48 +01:00
|
|
|
.flatten()
|
2019-12-08 17:06:45 +01:00
|
|
|
.filter(|d| **d == 1)
|
|
|
|
.count();
|
|
|
|
|
|
|
|
let two_count = most_zero_layer
|
|
|
|
.pixels
|
|
|
|
.iter()
|
2019-12-09 16:34:48 +01:00
|
|
|
.flatten()
|
2019-12-08 17:06:45 +01:00
|
|
|
.filter(|d| **d == 2)
|
|
|
|
.count();
|
|
|
|
|
|
|
|
Ok(one_count * two_count)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn part2(image: &Image, res: &mut String) -> Result<()> {
|
|
|
|
writeln!(res, "{}", image)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Layer {
|
|
|
|
pixels: Vec<Vec<u8>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Image {
|
|
|
|
layers: Vec<Layer>,
|
|
|
|
result: Vec<Vec<u8>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for Image {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
for i in 0..self.result.len() {
|
|
|
|
for j in 0..self.result[i].len() {
|
|
|
|
write!(f, "{}", if self.result[i][j] == 1 { '█' } else { ' ' })?;
|
|
|
|
}
|
|
|
|
writeln!(f)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromStr for Image {
|
2020-12-14 19:24:43 +01:00
|
|
|
type Err = anyhow::Error;
|
2019-12-08 17:06:45 +01:00
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<Self> {
|
|
|
|
let s = s.trim_end();
|
|
|
|
let digits: Vec<u8> = s
|
|
|
|
.chars()
|
|
|
|
.map(|c| c.to_digit(10))
|
|
|
|
.filter_map(|d| d.map(|d| d as u8))
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
let lines = digits
|
|
|
|
.chunks(IMG_WIDTH)
|
|
|
|
.map(|chunk| chunk.to_vec())
|
|
|
|
.collect::<Vec<Vec<u8>>>();
|
|
|
|
|
|
|
|
let layers = lines
|
|
|
|
.chunks(IMG_HEIGHT)
|
|
|
|
.map(|chunk| chunk.to_vec())
|
|
|
|
.map(|pixels| Layer { pixels })
|
|
|
|
.collect::<Vec<Layer>>();
|
|
|
|
|
|
|
|
let mut result = vec![vec![2; IMG_WIDTH]; IMG_HEIGHT];
|
|
|
|
|
|
|
|
// overlap layers
|
2020-12-17 01:23:10 +01:00
|
|
|
for layer in &layers {
|
2019-12-09 16:34:48 +01:00
|
|
|
for (src_row, dst_row) in layer.pixels.iter().zip(result.iter_mut()) {
|
|
|
|
for (src_pixel, dst_pixel) in src_row.iter().zip(dst_row.iter_mut()) {
|
|
|
|
if let 2 = *dst_pixel {
|
|
|
|
*dst_pixel = *src_pixel;
|
2019-12-08 17:06:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Image { layers, result })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn part1_real() {
|
|
|
|
let image: Image = INPUT.parse().unwrap();
|
|
|
|
assert_eq!(part1(&image).unwrap(), 1848);
|
|
|
|
}
|
|
|
|
}
|