use std::cmp::Ordering; use std::fs; use anyhow::Error; use chrono::{Datelike, Local}; use pico_args::Arguments; const DAYS: usize = 2; type Part = fn(String) -> u64; type Day = [Part; 2]; const SOLNS: [Day; DAYS] = [[day_1_part_1, day_1_part_2], [day_2_part_1, day_2_part_2]]; fn main() -> Result<(), Error> { let mut args = Arguments::from_env(); let small = args.contains("--small"); let part = args.opt_free_from_str()?.unwrap_or(1); let day = args .opt_free_from_str()? .unwrap_or_else(|| Local::now().day()); let small = if small { ".small" } else { "" }; let path = format!("inputs/{day}{small}.txt"); let input = fs::read_to_string(path)?; let result = SOLNS[day as usize - 1][part as usize - 1](input); println!("{result}"); Ok(()) } fn day_1_part_1(input: String) -> u64 { let lines = input.lines(); let (max, _) = lines.fold((0, 0), |(max, sum), line| { if line.is_empty() { (max.max(sum), 0) } else { let cal = line.parse::().expect("Got bad line"); (max, sum + cal) } }); max } fn day_1_part_2(input: String) -> u64 { let lines = input.lines(); let (a, b, c, _) = lines.fold((0, 0, 0, 0), |(a, b, c, sum), line| { if line.trim().is_empty() { if sum > a { (sum, a, b, 0) } else if sum > b { (a, sum, b, 0) } else if sum > c { (a, b, sum, 0) } else { (a, b, c, 0) } } else { let cal = line.trim().parse::().expect("Got bad line"); (a, b, c, sum + cal) } }); a + b + c } #[derive(Copy, Clone, PartialEq, Eq)] enum RPS { Rock, Paper, Scissors, } impl RPS { fn from_str(s: &str) -> Self { match s { "A" | "X" => RPS::Rock, "B" | "Y" => RPS::Paper, "C" | "Z" => RPS::Scissors, _ => unreachable!("you did a bad thing"), } } fn win(self) -> RPS { match self { RPS::Rock => RPS::Scissors, RPS::Paper => RPS::Rock, RPS::Scissors => RPS::Paper, } } fn lose(self) -> RPS { match self { RPS::Rock => RPS::Paper, RPS::Paper => RPS::Scissors, RPS::Scissors => RPS::Rock, } } fn cmp(self, other: Self) -> Ordering { if self == other { Ordering::Equal } else if self.win() == other { Ordering::Greater } else { Ordering::Less } } fn score(you: Self, me: Self) -> u64 { let base = match me { RPS::Rock => 1, RPS::Paper => 2, RPS::Scissors => 3, }; let win = match RPS::cmp(me, you) { Ordering::Less => 0, Ordering::Equal => 3, Ordering::Greater => 6, }; base + win } } fn day_2_part_1(input: String) -> u64 { input .lines() .map(|line| { let (you, me) = line.split_once(' ').expect("oof"); let (you, me) = (RPS::from_str(you), RPS::from_str(me)); RPS::score(you, me) }) .sum() } #[derive(Copy, Clone)] enum Outcome { Win, Draw, Lose, } impl Outcome { fn from_str(s: &str) -> Self { match s { "X" => Outcome::Lose, "Y" => Outcome::Draw, "Z" => Outcome::Win, _ => unreachable!("yikes"), } } fn requires(self, you: RPS) -> RPS { match self { Outcome::Win => you.lose(), Outcome::Draw => you, Outcome::Lose => you.win(), } } } fn day_2_part_2(input: String) -> u64 { input .lines() .map(|line| { let (you, out) = line.split_once(' ').expect("oof"); let (you, out) = (RPS::from_str(you), Outcome::from_str(out)); let me = out.requires(you); RPS::score(you, me) }) .sum() }