aoc.2022/src/main.rs

168 lines
4.0 KiB
Rust

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::<u64>().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::<u64>().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()
}