use aoc2019::*; use rpds::vector::Vector; use rpds::RedBlackTreeMap; use std::io; use std::io::prelude::*; use std::process; use structopt::StructOpt; #[derive(Debug, StructOpt)] #[structopt(name = "Day 13: Care Package")] /// Executes an Intcode game /// /// The program is read from stdin as a series of comma-separated /// values. Newlines are ignored. /// /// See https://adventofcode.com/2019/day/13 for details. struct Opt { #[structopt(short = "i", long = "input")] input: Vec, } fn main() { let stdin = io::stdin(); let opt = Opt::from_args(); let program: IntcodeProgram = stdin .lock() .split(b',') .map(|x| exit_on_failed_assertion(x, "Error reading input")) .map(|x| exit_on_failed_assertion(String::from_utf8(x), "Input was not valid UTF-8")) .map(|x| exit_on_failed_assertion(x.trim().parse::(), "Invalid number")) .collect::() .with_input(opt.input.into_iter().collect()); let result = exit_on_failed_assertion(program.execute(), "Program errored"); println!("{}", count_blocks(result)); } fn exit_on_failed_assertion(data: Result, message: &str) -> A { match data { Ok(data) => data, Err(e) => { eprintln!("{}: {}", message, e); process::exit(1); } } } fn render_screen(output: Vector) -> RedBlackTreeMap<(Intcode, Intcode), Intcode> { (0..output.len() / 3) .map(|i| i * 3) .map(|i| { ( output[i].clone(), output[i + 1].clone(), output[i + 2].clone(), ) }) .fold(RedBlackTreeMap::new(), |acc, (x, y, tile)| { acc.insert((x, y), tile) }) } fn count_blocks(output: Vector) -> usize { render_screen(output) .values() .filter(|val| **val == Intcode::from(2)) .count() }