1mod api;
2mod challenge;
3mod input_getter;
4mod persist;
5
6use clap::Parser;
7use linkme::distributed_slice;
8
9pub use bddap_aoc_macros::{register, unregistered_challenge};
10pub use challenge::Challenge;
11pub use input_getter::Getter;
12pub use linkme;
13
14#[distributed_slice]
15pub static CHALLENGES: [Challenge] = [..];
16
17#[derive(clap::Parser)]
18#[command(author, version, about, long_about = None)]
19enum Args {
20 #[clap(about = "Run challenge[s]")]
21 Run(Run),
22 #[clap(about = "Save your session token so challenges inputs can be downloaded")]
23 Login,
24}
25
26#[derive(clap::Parser)]
27struct Run {
28 #[arg(short, long)]
30 year: Vec<usize>,
31
32 #[arg(short, long)]
34 day: Vec<usize>,
35
36 #[arg(short, long)]
38 part: Vec<usize>,
39}
40
41pub fn run_default() {
43 let argss = Args::parse();
44
45 let run = match argss {
46 Args::Run(run) => run,
47 Args::Login => {
48 unwrap_or_print(persist::login());
49 return;
50 }
51 };
52
53 let getter = unwrap_or_print(Getter::load());
54
55 let mut todos: Vec<&Challenge> = CHALLENGES
56 .iter()
57 .filter(|c| run.year.contains(&c.year) || run.year.is_empty())
58 .filter(|c| run.day.contains(&c.day) || run.day.is_empty())
59 .filter(|c| run.part.contains(&c.part) || run.part.is_empty())
60 .collect();
61
62 if todos.is_empty() {
63 eprintln!("No matching challenges.");
64 }
65
66 todos.sort_by_key(|c| (c.year, c.day, c.part));
67
68 for challenge in todos {
69 println!(
70 "year {} day {} part {} - {}",
71 challenge.year, challenge.day, challenge.part, challenge.name
72 );
73 let input = match getter.get_input(challenge.year, challenge.day) {
74 Ok(input) => input,
75 Err(api::Error::ChallengeNotReady { time_till_ready }) => {
76 eprintln!(
77 "Challenge not ready yet. Try again in {}",
78 humantime::format_duration(time_till_ready)
79 );
80 continue;
81 }
82 Err(api::Error::Other(e)) => {
83 eprintln!("Error getting input: {}", e);
84 continue;
85 }
86 };
87 let output = challenge.run(&input);
88 println!("{}", output);
89 println!();
90 }
91}
92
93fn unwrap_or_print<T, E: std::fmt::Display>(result: Result<T, E>) -> T {
94 match result {
95 Ok(t) => t,
96 Err(e) => {
97 eprintln!("{}", e);
98 std::process::exit(1);
99 }
100 }
101}