1use std::{error, fmt};
2
3pub struct Problem {
4 year: u16,
5 day: u8,
6 title: &'static str,
7 parts: u8,
8 parse: for<'a> fn(&'a str) -> Result<Box<dyn Solver>, ParseError<'a>>,
9}
10
11impl Problem {
12 pub fn year(&self) -> u16 {
13 self.year
14 }
15 pub fn day(&self) -> u8 {
16 self.day
17 }
18 pub fn title(&self) -> &str {
19 self.title
20 }
21 pub fn parts(&self) -> u8 {
22 self.parts
23 }
24 pub fn parse<'a>(&self, input: &'a str) -> Result<Box<dyn Solver>, ParseError<'a>> {
25 (self.parse)(input)
26 }
27 pub fn solve_all<'a>(&self, input: &'a str) -> Result<Vec<String>, ParseError<'a>> {
28 let mut res = Vec::<String>::new();
29 let mut solver = self.parse(input)?;
30 for part in 1..=self.parts {
31 res.push(solver.solve(part).unwrap());
32 }
33 Ok(res)
34 }
35}
36
37impl fmt::Display for Problem {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 write!(f, "Day {}: {}", self.day, self.title)
40 }
41}
42
43#[derive(Debug)]
44pub struct ParseError<'a> {
45 msg: &'static str,
46 line: usize,
47 pos: usize,
48 source: Option<Box<dyn error::Error + 'static>>,
49 arg: &'a str,
50}
51
52impl<'a> PartialEq for ParseError<'a> {
53 fn eq(&self, rhs: &Self) -> bool {
54 let left = (self.msg, self.line, self.pos, self.arg);
55 let right = (rhs.msg, rhs.line, rhs.pos, rhs.arg);
56 left == right
57 }
58}
59
60impl<'a> fmt::Display for ParseError<'a> {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 write!(f, "{}:{} {}", self.line, self.pos, self.msg)?;
63 if let Some(inner) = &self.source {
64 write!(f, ": {}", inner)?;
65 }
66 if !self.arg.is_empty() {
67 write!(f, ": {}", self.arg)?;
68 }
69 Ok(())
70 }
71}
72
73impl<'a> error::Error for ParseError<'a> {
74 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
75 Some(self.source.as_ref()?.as_ref())
76 }
77}
78
79#[derive(Debug, PartialEq)]
80pub enum SolveError {
81 NotImplemented,
82 PartNotFound(u8),
83}
84
85impl fmt::Display for SolveError {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 match self {
88 SolveError::NotImplemented => write!(f, "Not implemented")?,
89 SolveError::PartNotFound(part) => write!(f, "Part#{part} not found")?,
90 }
91 Ok(())
92 }
93}
94
95impl error::Error for SolveError {}
96
97pub trait Solver {
98 fn solve(&mut self, part: u8) -> Result<String, SolveError>;
99}
100
101mod y2015 {
102 pub mod d1;
103 pub mod d2;
104 pub mod d3;
105 pub mod d4;
106 pub mod d5;
107}
108
109pub const PROBLEMS: [Problem; 5] = [
110 y2015::d1::PROBLEM,
111 y2015::d2::PROBLEM,
112 y2015::d3::PROBLEM,
113 y2015::d4::PROBLEM,
114 y2015::d5::PROBLEM,
115];
116
117#[cfg(test)]
118mod tests {
119 #[test]
120 fn problems_order() {
121 let mut year: u16 = 0;
122 let mut day: u8 = 0;
123 for problem in super::PROBLEMS {
124 if year < problem.year() {
125 year = problem.year();
126 day = 0;
127 }
128 assert!(year == problem.year());
129 assert!(day < problem.day());
130 day = problem.day();
131 assert!(year >= 2015 && year < 2024);
132 assert!(day >= 1 && day <= 25);
133 assert_eq!(problem.parts(), 2)
134 }
135 }
136}