pub mod challenge;
mod example;
mod data;
use serde::de::DeserializeOwned;
use serde::Serialize;
use serde_yaml;
use std::{fmt::{Display, Debug}, fs};
use crate::input::InputLoader;
use crate::aoc_runner::data::AOCData;
use crate::aoc_runner::example::Example;
use crate::aoc_runner::challenge::Challenge;
use crate::aoc_runner::challenge::ChallengePart;
pub struct AOCRunner<R, T: Challenge<R>> {
challenge: T,
examples: Vec<Example<R>>,
data: AOCData<R>
}
impl<'de, R: Eq + Display + PartialOrd + Serialize + DeserializeOwned + Debug, T: Challenge<R>> AOCRunner<R, T> {
pub fn new(challenge: T) -> Self {
if let Ok(data) = fs::read_to_string("assets/aoc.yaml") {
let data : AOCData<R> = serde_yaml::from_str(&data).expect("Unable to parse yaml");
return AOCRunner {
challenge,
examples: Vec::new(),
data
}
}
AOCRunner {
challenge,
examples: Vec::new(),
data: AOCData::new()
}
}
pub fn add_example(mut self, data: impl InputLoader, expected: R, part: ChallengePart) -> Self {
self.examples.push(Example::new(data.load(), expected, part));
self
}
pub fn run(mut self, input: impl InputLoader) {
let input = input.load();
println!("Executing Part 1");
let result = self.execute(input.clone(), ChallengePart::Part1);
match result {
Result::PossibleSolution(r) => {
self.get_feedback(r, ChallengePart::Part1);
},
_ => {}
}
println!("Executing Part 2");
let result = self.execute(input.clone(), ChallengePart::Part2);
match result {
Result::PossibleSolution(r) => {
self.get_feedback(r, ChallengePart::Part2);
},
_ => {}
}
let _data = serde_yaml::to_string(&self.data).expect("Unable to serialize yaml");
if let Err(e) = fs::write("assets/aoc.yaml", _data) {
println!("Unable to write yaml: {}", e);
}
}
fn execute(&mut self, input: Vec<String>, part: ChallengePart) -> Result<R> {
for (i, example) in self.examples.iter().filter(|example| example.part == part).enumerate() {
let result = match part {
ChallengePart::Part1 => self.challenge.part1(example.input.clone()),
ChallengePart::Part2 => self.challenge.part2(example.input.clone())
};
match result {
Some(result) => {
println!("Result for Example Nr. {}: {}", i, result);
if result == example.expected {
println!("Example Nr. {} Passed", i);
} else {
println!("Example Nr. {} Failed. Expected {}", i, example.expected);
return Result::Incorrect;
}
},
None => { println!("Part {} not implemented", part.to_number()); return Result::NotImplemented; }
}
}
let result = match part {
ChallengePart::Part1 => self.challenge.part1(input.clone()),
ChallengePart::Part2 => self.challenge.part2(input.clone())
};
if result.is_none() {
println!("Part {} not implemented", part.to_number());
return Result::NotImplemented;
}
let result = result.unwrap();
println!("Result: {}", result);
let index = (part.to_number() - 1) as usize;
if self.data.part[index].solution.is_some() {
if result == *self.data.part[index].solution.as_ref().unwrap() {
println!("Solution is correct.");
return Result::Correct;
} else {
println!("Solution is incorrect. Correct answer: {}", self.data.part[index].solution.as_ref().unwrap());
return Result::Incorrect;
}
}
if self.data.part[index].min.is_some() {
if result <= *self.data.part[index].min.as_ref().unwrap() {
println!("The result is too low. Solution is bigger than {} (If the result type is a String ignore the Order Information)", self.data.part[index].min.as_ref().unwrap());
return Result::TooLow;
}
}
if self.data.part[index].max.is_some() {
if result >= *self.data.part[index].max.as_ref().unwrap() {
println!("The result is too high. Solution is smaller than {} (If the result type is a String ignore the Order Information)", self.data.part[index].max.as_ref().unwrap());
return Result::TooHigh;
}
}
Result::PossibleSolution(result)
}
fn get_feedback(&mut self, result: R, part: ChallengePart) {
println!("Enter the answer in AOC and provide the given feedback. (0 = Incorrect, 1 = Correct, 2 = Too Low, 3 = Too High)");
let mut feedback = String::new();
let index = (part.to_number() - 1) as usize;
loop {
if let Err(e) = std::io::stdin().read_line(&mut feedback) {
println!("Something went wrong: {}", e);
continue;
}
match feedback.trim().parse::<u8>() {
Ok(1) => {
println!("The result is correct ");
self.data.part[index].solution = Some(result);
break;
},
Ok(2) => {
println!("The result is too low ");
self.data.part[index].min = Some(result);
break;
},
Ok(3) => {
println!("The result is too high ");
self.data.part[index].max = Some(result);
break;
},
_ => {
println!("Please enter 0 or 1");
continue;
}
}
}
}
}
enum Result<T> {
Correct,
Incorrect,
TooLow,
TooHigh,
PossibleSolution(T),
NotImplemented
}