use aoc2019::*; use std::io; use std::io::prelude::*; use std::process; use structopt::StructOpt; #[derive(Debug, StructOpt)] #[structopt(name = "Day 2: 1202 Program Alarm")] /// Executes an Intcode program /// /// The program is read from stdin as a series of comma-separated /// values. Newlines are ignored. When the program halts, the value at /// position 0 is returned. /// /// If an output is provided, all possible inputs are tried to find /// the input that results in the desired output. In this case, the /// inputs are returned in the format (noun, verb). /// ///See https://adventofcode.com/2019/day/2 for details. struct Opt { #[structopt(short = "n", long = "noun")] noun: Option, #[structopt(short = "v", long = "verb")] verb: Option, #[structopt(short = "o", long = "output")] output: Option, } 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(); match (opt.noun, opt.verb, opt.output) { (Some(noun), Some(verb), _) => { let result = exit_on_failed_assertion( program .with_noun_verb_input(noun, verb) .execute_returning_memory_0(), "Program errored", ); println!("{}", result); } (_, _, Some(output)) => { let (noun, verb) = exit_on_failed_assertion(find_input(&program, output), "Program errored"); println!("({}, {})", noun, verb); } (None, None, None) => { let result = exit_on_failed_assertion(program.execute_returning_memory_0(), "Program errored"); println!("{}", result); } _ => { eprintln!("Either a noun and verb or an expected output must be provided"); process::exit(1); } } } fn exit_on_failed_assertion(data: Result, message: &str) -> A { match data { Ok(data) => data, Err(e) => { eprintln!("{}: {}", message, e); process::exit(1); } } } fn find_input( program: &IntcodeProgram, output: Intcode, ) -> Result<(Intcode, Intcode), IntcodeProgramError> { (0..99) .flat_map(|noun| (0..99).map(move |verb| (Intcode::from(noun), Intcode::from(verb)))) .map(|(noun, verb)| { ( noun.clone(), verb.clone(), program .with_noun_verb_input(noun, verb) .execute_returning_memory_0(), ) }) .find(|(_noun, _verb, out)| *out == Ok(output.clone())) .map(|(noun, verb, _out)| Ok((noun, verb))) .unwrap_or(Err(IntcodeProgramError::Unknown)) }