day02 finished

This commit is contained in:
Ruediger Ludwig 2023-01-27 07:48:33 +01:00
parent 68fefd064a
commit eb1ce68486
9 changed files with 2758 additions and 30 deletions

225
src/days/day02/mod.rs Normal file
View file

@ -0,0 +1,225 @@
use std::cmp::Ordering;
use super::template::{DayTrait, ResultType};
use anyhow::Result;
use thiserror::Error;
const DAY_NUMBER: usize = 2;
pub struct Day;
impl DayTrait for Day {
fn get_day_number(&self) -> usize {
DAY_NUMBER
}
fn part1(&self, lines: &str) -> Result<ResultType> {
let sum = lines
.split("\n")
.map(RPS::parse_line)
.collect::<Result<Vec<_>>>()?
.into_iter()
.map(|(first, second)| second.asses_pair(&first))
.sum();
Ok(ResultType::IntResult(sum))
}
fn part2(&self, lines: &str) -> Result<ResultType> {
let sum = lines
.split("\n")
.map(Strategy::parse_line)
.collect::<Result<Vec<_>>>()?
.into_iter()
.map(|(first, second)| second.fullfill(&first).asses_pair(&first))
.sum();
Ok(ResultType::IntResult(sum))
}
}
#[derive(Debug, Error)]
enum RPSError {
#[error("No a valid RPS: {0}")]
ParseError(String),
#[error("Not a logal RPS line: {0}")]
IllegalLine(String),
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
enum RPS {
Rock,
Paper,
Scissors,
}
impl RPS {
pub fn parse_line(line: &str) -> Result<(Self, Self)> {
let mut parts = line.split(" ");
let (Some(first), Some(second)) = (parts.next(), parts.next()) else {
Err(RPSError::IllegalLine(line.to_owned()))?
};
let first = RPS::try_from(first)?;
let second = RPS::try_from(second)?;
Ok((first, second))
}
pub fn value(&self) -> i64 {
match self {
RPS::Rock => 1,
RPS::Paper => 2,
RPS::Scissors => 3,
}
}
pub fn asses_pair(&self, other: &Self) -> i64 {
let outcome = match self.partial_cmp(other) {
Some(Ordering::Less) => 0,
Some(Ordering::Equal) => 3,
Some(Ordering::Greater) => 6,
None => unreachable!(),
};
outcome + self.value()
}
}
impl PartialOrd for RPS {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (self, other) {
(RPS::Rock, RPS::Paper) | (RPS::Paper, RPS::Scissors) | (RPS::Scissors, RPS::Rock) => {
Some(Ordering::Less)
}
(RPS::Rock, RPS::Scissors) | (RPS::Paper, RPS::Rock) | (RPS::Scissors, RPS::Paper) => {
Some(Ordering::Greater)
}
_ => Some(Ordering::Equal),
}
}
}
impl TryFrom<&str> for RPS {
type Error = RPSError;
fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
match value {
"A" | "X" => Ok(RPS::Rock),
"B" | "Y" => Ok(RPS::Paper),
"C" | "Z" => Ok(RPS::Scissors),
_ => Err(RPSError::ParseError(value.to_owned())),
}
}
}
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
enum Strategy {
Loose,
Draw,
Win,
}
impl Strategy {
pub fn parse_line(line: &str) -> Result<(RPS, Self)> {
let mut parts = line.split(" ");
let (Some(first), Some(second)) = (parts.next(), parts.next()) else {
Err(RPSError::IllegalLine(line.to_owned()))?
};
let first = RPS::try_from(first)?;
let second = Strategy::try_from(second)?;
Ok((first, second))
}
pub fn fullfill(&self, other: &RPS) -> RPS {
match (other, self) {
(_, Strategy::Draw) => *other,
(RPS::Rock, Strategy::Win) | (RPS::Scissors, Strategy::Loose) => RPS::Paper,
(RPS::Paper, Strategy::Win) | (RPS::Rock, Strategy::Loose) => RPS::Scissors,
(RPS::Scissors, Strategy::Win) | (RPS::Paper, Strategy::Loose) => RPS::Rock,
}
}
}
impl TryFrom<&str> for Strategy {
type Error = RPSError;
fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
match value {
"X" => Ok(Strategy::Loose),
"Y" => Ok(Strategy::Draw),
"Z" => Ok(Strategy::Win),
_ => Err(RPSError::ParseError(value.to_owned())),
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::common::file::read_data;
use anyhow::Result;
#[test]
fn test_parse() -> Result<()> {
let input = "A Y";
let expected = (RPS::Rock, RPS::Paper);
let result = RPS::parse_line(input)?;
assert_eq!(result, expected);
Ok(())
}
#[test]
fn test_assess() -> Result<()> {
let first = RPS::Scissors;
let second = RPS::Paper;
let expected = 9;
let result = first.asses_pair(&second);
assert_eq!(result, expected);
Ok(())
}
#[test]
fn test_part1() -> Result<()> {
let day = Day {};
let lines = read_data(day.get_day_number(), "example01.txt")?;
let expected = ResultType::IntResult(15);
let result = day.part1(&lines)?;
assert_eq!(result, expected);
Ok(())
}
#[test]
fn test_parse_strategy() -> Result<()> {
let input = "A Y";
let expected = (RPS::Rock, Strategy::Draw);
let result = Strategy::parse_line(input)?;
assert_eq!(result, expected);
Ok(())
}
#[test]
fn test_assess_stragety() -> Result<()> {
let first = RPS::Scissors;
let second = Strategy::Win;
let expected = RPS::Rock;
let result = second.fullfill(&first);
assert_eq!(result, expected);
Ok(())
}
#[test]
fn test_part2() -> Result<()> {
let day = Day {};
let lines = read_data(day.get_day_number(), "example01.txt")?;
let expected = ResultType::NoResult;
let result = day.part2(&lines)?;
assert_eq!(result, expected);
Ok(())
}
}

View file

@ -1,21 +0,0 @@
use super::{day01, DayTrait};
use thiserror::Error;
const MAX_DAY: usize = 1;
pub fn get_day(day_num: usize) -> Result<Box<dyn DayTrait>, ProviderError> {
match day_num {
1 => Ok(Box::new(day01::Day)),
_ => Err(ProviderError::InvalidNumber(day_num)),
}
}
pub fn get_all_days() -> impl Iterator<Item = Box<dyn DayTrait>> {
(1..=MAX_DAY).map(|day_num| get_day(day_num).expect("Must never happen"))
}
#[derive(Debug, Error)]
pub enum ProviderError {
#[error("Not a valid day number: {0}")]
InvalidNumber(usize),
}

View file

@ -1,6 +1,31 @@
mod day01;
pub mod day_provider;
mod day02;
mod template;
pub use template::DayTrait;
pub use template::ResultType;
pub mod day_provider {
use super::*;
use thiserror::Error;
const MAX_DAY: usize = 2;
pub fn get_day(day_num: usize) -> Result<Box<dyn DayTrait>, ProviderError> {
match day_num {
1 => Ok(Box::new(day01::Day)),
2 => Ok(Box::new(day02::Day)),
_ => Err(ProviderError::InvalidNumber(day_num)),
}
}
pub fn get_all_days() -> impl Iterator<Item = Box<dyn DayTrait>> {
(1..=MAX_DAY).map(|day_num| get_day(day_num).expect("Must never happen"))
}
#[derive(Debug, Error)]
pub enum ProviderError {
#[error("Not a valid day number: {0}")]
InvalidNumber(usize),
}
}

View file

@ -31,10 +31,10 @@ fn output(day: usize, part: usize, result: ResultType) -> () {
fn run(day: Box<dyn DayTrait>, part1: bool, part2: bool) -> Result<()> {
let lines = read_data(day.get_day_number(), "input.txt")?;
if part1 {
output(1, 1, day.part1(&lines)?);
output(day.get_day_number(), 1, day.part1(&lines)?);
}
if part2 {
output(1, 2, day.part2(&lines)?);
output(day.get_day_number(), 2, day.part2(&lines)?);
}
Ok(())