From 9892e3ebde304726903a1e5c358d05c2e343ea5e Mon Sep 17 00:00:00 2001 From: Justin Wernick Date: Tue, 19 Apr 2022 20:26:36 +0200 Subject: Refile for merging repos --- 2019/src/bin/day_8.rs | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 2019/src/bin/day_8.rs (limited to '2019/src/bin/day_8.rs') diff --git a/2019/src/bin/day_8.rs b/2019/src/bin/day_8.rs new file mode 100644 index 0000000..0508e7c --- /dev/null +++ b/2019/src/bin/day_8.rs @@ -0,0 +1,135 @@ +use std::fmt; +use std::io; +use std::io::prelude::*; +use std::process; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +#[structopt(name = "Day 8: Space Image Format")] +/// Executes an Intcode program on 5 amplifiers, and finds the input that gives the max output +/// +/// See https://adventofcode.com/2019/day/8 for details. +struct Opt { + /// Rather than rendering the image, calculate and print its checksum + #[structopt(short = "c", long = "checksum")] + checksum_mode: bool, + #[structopt(short = "w", long = "width")] + width: u32, + #[structopt(short = "h", long = "height")] + height: u32, +} + +fn main() { + let opt = Opt::from_args(); + + let image: Image = { + let mut buffer = String::new(); + exit_on_failed_assertion( + io::stdin().read_to_string(&mut buffer), + "Error reading input", + ); + + Image::from_str(&buffer.trim(), opt.width, opt.height) + }; + + if opt.checksum_mode { + println!("{}", image.checksum()); + } else { + println!("{}", image); + } +} + +fn exit_on_failed_assertion(data: Result, message: &str) -> A { + match data { + Ok(data) => data, + Err(e) => { + eprintln!("{}: {}", message, e); + process::exit(1); + } + } +} + +#[derive(Debug)] +struct Image { + width: u32, + height: u32, + layers: Vec, +} + +impl fmt::Display for Image { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.flatten() + .pixels + .chunks(self.width as usize) + .map(|line| { + line.iter() + .map(|c| write!(f, "{}", if *c == 0 { ' ' } else { '1' })) + .collect::() + .and_then(|_| writeln!(f)) + }) + .collect() + } +} + +impl Image { + fn from_str(s: &str, width: u32, height: u32) -> Image { + Image { + width, + height, + layers: s + .as_bytes() + .chunks((width * height) as usize) + .map(|chunk| ImageLayer::new(chunk)) + .collect(), + } + } + + fn checksum(&self) -> usize { + self.layers + .iter() + .min_by_key(|layer| layer.pixel_count(0)) + .map(|layer| layer.pixel_count(1) * layer.pixel_count(2)) + .unwrap_or(0) + } + + fn flatten(&self) -> ImageLayer { + self.layers + .iter() + .fold(ImageLayer::empty(self.width, self.height), |acc, next| { + ImageLayer { + pixels: acc + .pixels + .iter() + .zip(next.pixels.iter()) + .map(|(a, b)| if *a == 2 { *b } else { *a }) + .collect(), + } + }) + } +} + +#[derive(Debug)] +struct ImageLayer { + pixels: Vec, +} + +impl ImageLayer { + fn new(char_pixels: &[u8]) -> ImageLayer { + ImageLayer { + pixels: char_pixels + .iter() + .map(|c| c.overflowing_sub(b'0').0) + .collect(), + } + } + + fn empty(width: u32, height: u32) -> ImageLayer { + ImageLayer { + pixels: vec![2; (width * height) as usize], + } + } + + fn pixel_count(&self, value: u8) -> usize { + self.pixels.iter().filter(|p| **p == value).count() + } +} -- cgit v1.2.3