1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
use clap::Parser;
use std::fs::File;
use std::io;
use std::io::{BufRead, BufReader, Read};
use std::panic::catch_unwind;
use std::time::Instant;
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct Args {
#[arg(short, long, default_value = "-")]
file: String,
#[arg(short, long, default_value_t = 1)]
part: u8,
}
pub trait Day {
fn example_input(&self) -> &'static str;
fn example_input_part_1(&self) -> &'static str {
self.example_input()
}
fn example_input_part_2(&self) -> &'static str {
self.example_input()
}
fn example_result_part_1(&self) -> &'static str;
fn example_result_part_2(&self) -> &'static str;
fn read_lines(&self, input: BufReader<Box<dyn Read>>) -> Vec<String> {
let mut lines = Vec::new();
for line in input.lines() {
match line {
Ok(content) => lines.push(content),
Err(e) => eprintln!("Error reading line: {}", e),
}
}
lines
}
fn part_1(&self, input: BufReader<Box<dyn Read>>) -> String;
fn part_2(&self, input: BufReader<Box<dyn Read>>) -> String;
}
pub fn main(day: &dyn Day) {
let args = Args::parse();
let reader: Box<dyn Read> = if args.file == "-" {
Box::new(io::stdin())
} else {
Box::new(File::open(&args.file).expect("Failed to open file"))
};
let buffer = BufReader::new(reader);
let result: String;
let now = Instant::now();
if args.part == 1 {
result = day.part_1(buffer);
} else {
result = day.part_2(buffer);
}
println!("Result: {result}");
println!("Time to run: {}s", now.elapsed().as_secs_f64());
}
pub fn test_day<T: Day + std::panic::RefUnwindSafe>(day: &T) {
use std::io::Cursor;
use std::io::{BufReader, Read};
// Test Part 1
let output = catch_unwind(|| {
let input = BufReader::new(Box::new(Cursor::new(day.example_input_part_1())) as Box<dyn Read>);
day.part_1(input)
});
if output.is_ok() {
assert_eq!(output.unwrap().trim(), day.example_result_part_1(), "Part 1 failed");
}
// Test Part 2
let output = catch_unwind(|| {
let input = BufReader::new(Box::new(Cursor::new(day.example_input_part_2())) as Box<dyn Read>);
day.part_2(input)
});
if output.is_ok() {
assert_eq!(output.unwrap().trim(), day.example_result_part_2(), "Part 2 failed");
}
}
|