advent_of_code/
lib.rs

1#![cfg_attr(feature = "simd", feature(portable_simd))]
2#![forbid(unsafe_code)]
3/*!
4This crate provides solutions for [Advent of Code](https://adventofcode.com/) problems.
5
6# Usage
7
8This crate is [on crates.io](https://crates.io/crates/advent_of_code) and can be
9used by adding `advent_of_code` to your dependencies in your project's `Cargo.toml`.
10
11```toml
12[dependencies]
13advent_of_code = "*"
14```
15
16# Example
17By specifying a year, day and part together with a specific problem input
18a solution can be obtained:
19
20```rust
21use advent_of_code::solve;
22let solution = solve(2019, 1, 1, "14");
23assert_eq!(solution, Ok("2".to_string()));
24```
25*/
26#![crate_name = "advent_of_code"]
27
28mod common;
29#[cfg_attr(test, macro_use)]
30mod input;
31mod mod_exp;
32mod year2015;
33mod year2016;
34mod year2017;
35mod year2018;
36mod year2019;
37mod year2020;
38mod year2021;
39mod year2022;
40mod year2023;
41mod year2024;
42
43#[cfg(feature = "visualization")]
44pub type ResultType = String;
45
46#[cfg(not(feature = "visualization"))]
47pub type ResultType = String;
48
49// Never inline to prevent stack size from blowing up in release builds.
50#[inline(never)]
51fn to_stringer_input<T: ToString>(
52    function: fn(&input::Input) -> Result<T, String>,
53    input: &input::Input,
54) -> Result<String, String> {
55    function(input).map(|value| value.to_string())
56}
57
58/// Returns the solution for the specified given problem and input.
59///
60/// # Arguments
61///
62/// * `year` - The year of the problem, as in 2018 or 2019.
63/// * `day` - The day of the problem - from 1 to 25.
64/// * `part` - The part of the problem - either 1 or 2.
65/// * `input` - The input to the problem.
66///
67/// # Example
68/// ```
69/// use advent_of_code::solve;
70/// let solution = solve(2019, 1, 1, "14");
71/// assert_eq!(solution, Ok("2".to_string()));
72/// ```
73pub fn solve(year: u16, day: u8, part: u8, input: &str) -> Result<ResultType, String> {
74    #![allow(clippy::let_and_return)]
75    use crate::input::{Input, Part};
76    let input = input.trim_end();
77
78    if input.is_empty() {
79        return Err("Empty input".to_string());
80    } else if input.len() > 200_000 {
81        return Err("Too long input".to_string());
82    } else if !input.is_ascii() {
83        return Err("Non-ASCII input".to_string());
84    } else if !matches!(day, 1..=25) {
85        return Err(format!("Invalid day {day} - must be 1-25"));
86    } else if !matches!(part, 1 | 2) {
87        return Err(format!("Invalid part {part} - must be 1-2"));
88    }
89
90    #[cfg(feature = "visualization")]
91    let visualization = std::cell::RefCell::new("".to_string());
92
93    let input = Input {
94        part: if part == 1 { Part::One } else { Part::Two },
95        text: input,
96        #[cfg(feature = "visualization")]
97        visualization,
98    };
99
100    let result = match (year, day) {
101        (2015, 1) => to_stringer_input(year2015::day01::solve, &input),
102        (2015, 2) => to_stringer_input(year2015::day02::solve, &input),
103        (2015, 3) => to_stringer_input(year2015::day03::solve, &input),
104        (2015, 4) => to_stringer_input(year2015::day04::solve, &input),
105        (2015, 5) => to_stringer_input(year2015::day05::solve, &input),
106        (2015, 6) => to_stringer_input(year2015::day06::solve, &input),
107        (2015, 7) => to_stringer_input(year2015::day07::solve, &input),
108        (2015, 8) => to_stringer_input(year2015::day08::solve, &input),
109        (2015, 9) => to_stringer_input(year2015::day09::solve, &input),
110        (2015, 10) => to_stringer_input(year2015::day10::solve, &input),
111        (2015, 11) => to_stringer_input(year2015::day11::solve, &input),
112        (2015, 12) => to_stringer_input(year2015::day12::solve, &input),
113        (2015, 13) => to_stringer_input(year2015::day13::solve, &input),
114        (2015, 14) => to_stringer_input(year2015::day14::solve, &input),
115        (2015, 15) => to_stringer_input(year2015::day15::solve, &input),
116        (2015, 16) => to_stringer_input(year2015::day16::solve, &input),
117        (2015, 17) => to_stringer_input(year2015::day17::solve, &input),
118        (2015, 18) => to_stringer_input(year2015::day18::solve, &input),
119        (2015, 19) => to_stringer_input(year2015::day19::solve, &input),
120        (2015, 20) => to_stringer_input(year2015::day20::solve, &input),
121        (2015, 21) => to_stringer_input(year2015::day21::solve, &input),
122        (2015, 22) => to_stringer_input(year2015::day22::solve, &input),
123        (2015, 23) => to_stringer_input(year2015::day23::solve, &input),
124        (2015, 24) => to_stringer_input(year2015::day24::solve, &input),
125        (2015, 25) => to_stringer_input(year2015::day25::solve, &input),
126        (2016, 1) => to_stringer_input(year2016::day01::solve, &input),
127        (2016, 2) => to_stringer_input(year2016::day02::solve, &input),
128        (2016, 3) => to_stringer_input(year2016::day03::solve, &input),
129        (2016, 4) => to_stringer_input(year2016::day04::solve, &input),
130        (2016, 5) => to_stringer_input(year2016::day05::solve, &input),
131        (2016, 6) => to_stringer_input(year2016::day06::solve, &input),
132        (2016, 7) => to_stringer_input(year2016::day07::solve, &input),
133        (2016, 8) => to_stringer_input(year2016::day08::solve, &input),
134        (2016, 9) => to_stringer_input(year2016::day09::solve, &input),
135        (2016, 10) => to_stringer_input(year2016::day10::solve, &input),
136        (2016, 11) => to_stringer_input(year2016::day11::solve, &input),
137        (2016, 12) => to_stringer_input(year2016::day12::solve, &input),
138        (2016, 13) => to_stringer_input(year2016::day13::solve, &input),
139        (2016, 14) => to_stringer_input(year2016::day14::solve, &input),
140        (2016, 15) => to_stringer_input(year2016::day15::solve, &input),
141        (2016, 16) => to_stringer_input(year2016::day16::solve, &input),
142        (2016, 17) => to_stringer_input(year2016::day17::solve, &input),
143        (2016, 18) => to_stringer_input(year2016::day18::solve, &input),
144        (2016, 19) => to_stringer_input(year2016::day19::solve, &input),
145        (2016, 20) => to_stringer_input(year2016::day20::solve, &input),
146        (2016, 21) => to_stringer_input(year2016::day21::solve, &input),
147        (2016, 22) => to_stringer_input(year2016::day22::solve, &input),
148        (2016, 23) => to_stringer_input(year2016::day23::solve, &input),
149        (2016, 24) => to_stringer_input(year2016::day24::solve, &input),
150        (2016, 25) => to_stringer_input(year2016::day25::solve, &input),
151        (2017, 1) => to_stringer_input(year2017::day01::solve, &input),
152        (2017, 2) => to_stringer_input(year2017::day02::solve, &input),
153        (2017, 3) => to_stringer_input(year2017::day03::solve, &input),
154        (2017, 4) => to_stringer_input(year2017::day04::solve, &input),
155        (2017, 5) => to_stringer_input(year2017::day05::solve, &input),
156        (2017, 6) => to_stringer_input(year2017::day06::solve, &input),
157        (2017, 7) => to_stringer_input(year2017::day07::solve, &input),
158        (2017, 8) => to_stringer_input(year2017::day08::solve, &input),
159        (2017, 9) => to_stringer_input(year2017::day09::solve, &input),
160        (2017, 10) => to_stringer_input(year2017::day10::solve, &input),
161        (2017, 11) => to_stringer_input(year2017::day11::solve, &input),
162        (2017, 12) => to_stringer_input(year2017::day12::solve, &input),
163        (2017, 13) => to_stringer_input(year2017::day13::solve, &input),
164        (2017, 14) => to_stringer_input(year2017::day14::solve, &input),
165        (2017, 15) => to_stringer_input(year2017::day15::solve, &input),
166        (2017, 16) => to_stringer_input(year2017::day16::solve, &input),
167        (2017, 17) => to_stringer_input(year2017::day17::solve, &input),
168        (2017, 18) => to_stringer_input(year2017::day18::solve, &input),
169        (2017, 19) => to_stringer_input(year2017::day19::solve, &input),
170        (2017, 20) => to_stringer_input(year2017::day20::solve, &input),
171        (2017, 21) => to_stringer_input(year2017::day21::solve, &input),
172        (2017, 22) => to_stringer_input(year2017::day22::solve, &input),
173        (2017, 23) => to_stringer_input(year2017::day23::solve, &input),
174        (2017, 24) => to_stringer_input(year2017::day24::solve, &input),
175        (2017, 25) => to_stringer_input(year2017::day25::solve, &input),
176        (2018, 1) => to_stringer_input(year2018::day01::solve, &input),
177        (2018, 2) => to_stringer_input(year2018::day02::solve, &input),
178        (2018, 3) => to_stringer_input(year2018::day03::solve, &input),
179        (2018, 4) => to_stringer_input(year2018::day04::solve, &input),
180        (2018, 5) => to_stringer_input(year2018::day05::solve, &input),
181        (2018, 6) => to_stringer_input(year2018::day06::solve, &input),
182        (2018, 7) => to_stringer_input(year2018::day07::solve, &input),
183        (2018, 8) => to_stringer_input(year2018::day08::solve, &input),
184        (2018, 9) => to_stringer_input(year2018::day09::solve, &input),
185        (2018, 10) => to_stringer_input(year2018::day10::solve, &input),
186        (2018, 11) => to_stringer_input(year2018::day11::solve, &input),
187        (2018, 12) => to_stringer_input(year2018::day12::solve, &input),
188        (2018, 13) => to_stringer_input(year2018::day13::solve, &input),
189        (2018, 14) => to_stringer_input(year2018::day14::solve, &input),
190        (2018, 15) => to_stringer_input(year2018::day15::solve, &input),
191        (2018, 16) => to_stringer_input(year2018::day16::solve, &input),
192        (2018, 17) => to_stringer_input(year2018::day17::solve, &input),
193        (2018, 18) => to_stringer_input(year2018::day18::solve, &input),
194        (2018, 19) => to_stringer_input(year2018::day19::solve, &input),
195        (2018, 20) => to_stringer_input(year2018::day20::solve, &input),
196        (2018, 21) => to_stringer_input(year2018::day21::solve, &input),
197        (2018, 22) => to_stringer_input(year2018::day22::solve, &input),
198        (2018, 23) => to_stringer_input(year2018::day23::solve, &input),
199        (2018, 24) => to_stringer_input(year2018::day24::solve, &input),
200        (2018, 25) => to_stringer_input(year2018::day25::solve, &input),
201        (2019, 1) => to_stringer_input(year2019::day01::solve, &input),
202        (2019, 2) => to_stringer_input(year2019::day02::solve, &input),
203        (2019, 3) => to_stringer_input(year2019::day03::solve, &input),
204        (2019, 4) => to_stringer_input(year2019::day04::solve, &input),
205        (2019, 5) => to_stringer_input(year2019::day05::solve, &input),
206        (2019, 6) => to_stringer_input(year2019::day06::solve, &input),
207        (2019, 7) => to_stringer_input(year2019::day07::solve, &input),
208        (2019, 8) => to_stringer_input(year2019::day08::solve, &input),
209        (2019, 9) => to_stringer_input(year2019::day09::solve, &input),
210        (2019, 10) => to_stringer_input(year2019::day10::solve, &input),
211        (2019, 11) => to_stringer_input(year2019::day11::solve, &input),
212        (2019, 12) => to_stringer_input(year2019::day12::solve, &input),
213        (2019, 13) => to_stringer_input(year2019::day13::solve, &input),
214        (2019, 14) => to_stringer_input(year2019::day14::solve, &input),
215        (2019, 15) => to_stringer_input(year2019::day15::solve, &input),
216        (2019, 16) => to_stringer_input(year2019::day16::solve, &input),
217        (2019, 17) => to_stringer_input(year2019::day17::solve, &input),
218        (2019, 18) => to_stringer_input(year2019::day18::solve, &input),
219        (2019, 19) => to_stringer_input(year2019::day19::solve, &input),
220        (2019, 20) => to_stringer_input(year2019::day20::solve, &input),
221        (2019, 21) => to_stringer_input(year2019::day21::solve, &input),
222        (2019, 22) => to_stringer_input(year2019::day22::solve, &input),
223        (2019, 23) => to_stringer_input(year2019::day23::solve, &input),
224        (2019, 24) => to_stringer_input(year2019::day24::solve, &input),
225        (2019, 25) => to_stringer_input(year2019::day25::solve, &input),
226        (2020, 1) => to_stringer_input(year2020::day01::solve, &input),
227        (2020, 2) => to_stringer_input(year2020::day02::solve, &input),
228        (2020, 3) => to_stringer_input(year2020::day03::solve, &input),
229        (2020, 4) => to_stringer_input(year2020::day04::solve, &input),
230        (2020, 5) => to_stringer_input(year2020::day05::solve, &input),
231        (2020, 6) => to_stringer_input(year2020::day06::solve, &input),
232        (2020, 7) => to_stringer_input(year2020::day07::solve, &input),
233        (2020, 8) => to_stringer_input(year2020::day08::solve, &input),
234        (2020, 9) => to_stringer_input(year2020::day09::solve, &input),
235        (2020, 10) => to_stringer_input(year2020::day10::solve, &input),
236        (2020, 11) => to_stringer_input(year2020::day11::solve, &input),
237        (2020, 12) => to_stringer_input(year2020::day12::solve, &input),
238        (2020, 13) => to_stringer_input(year2020::day13::solve, &input),
239        (2020, 14) => to_stringer_input(year2020::day14::solve, &input),
240        (2020, 15) => to_stringer_input(year2020::day15::solve, &input),
241        (2020, 16) => to_stringer_input(year2020::day16::solve, &input),
242        (2020, 17) => to_stringer_input(year2020::day17::solve, &input),
243        (2020, 18) => to_stringer_input(year2020::day18::solve, &input),
244        (2020, 19) => to_stringer_input(year2020::day19::solve, &input),
245        (2020, 20) => to_stringer_input(year2020::day20::solve, &input),
246        (2020, 21) => to_stringer_input(year2020::day21::solve, &input),
247        (2020, 22) => to_stringer_input(year2020::day22::solve, &input),
248        (2020, 23) => to_stringer_input(year2020::day23::solve, &input),
249        (2020, 24) => to_stringer_input(year2020::day24::solve, &input),
250        (2020, 25) => to_stringer_input(year2020::day25::solve, &input),
251        (2021, 1) => to_stringer_input(year2021::day01::solve, &input),
252        (2021, 2) => to_stringer_input(year2021::day02::solve, &input),
253        (2021, 3) => to_stringer_input(year2021::day03::solve, &input),
254        (2021, 4) => to_stringer_input(year2021::day04::solve, &input),
255        (2021, 5) => to_stringer_input(year2021::day05::solve, &input),
256        (2021, 6) => to_stringer_input(year2021::day06::solve, &input),
257        (2021, 7) => to_stringer_input(year2021::day07::solve, &input),
258        (2021, 8) => to_stringer_input(year2021::day08::solve, &input),
259        (2021, 9) => to_stringer_input(year2021::day09::solve, &input),
260        (2021, 10) => to_stringer_input(year2021::day10::solve, &input),
261        (2021, 11) => to_stringer_input(year2021::day11::solve, &input),
262        (2021, 12) => to_stringer_input(year2021::day12::solve, &input),
263        (2021, 13) => to_stringer_input(year2021::day13::solve, &input),
264        (2021, 14) => to_stringer_input(year2021::day14::solve, &input),
265        (2021, 15) => to_stringer_input(year2021::day15::solve, &input),
266        (2021, 16) => to_stringer_input(year2021::day16::solve, &input),
267        (2021, 17) => to_stringer_input(year2021::day17::solve, &input),
268        (2021, 18) => to_stringer_input(year2021::day18::solve, &input),
269        (2021, 19) => to_stringer_input(year2021::day19::solve, &input),
270        (2021, 20) => to_stringer_input(year2021::day20::solve, &input),
271        (2021, 21) => to_stringer_input(year2021::day21::solve, &input),
272        (2021, 22) => to_stringer_input(year2021::day22::solve, &input),
273        (2021, 23) => to_stringer_input(year2021::day23::solve, &input),
274        (2021, 24) => to_stringer_input(year2021::day24::solve, &input),
275        (2021, 25) => to_stringer_input(year2021::day25::solve, &input),
276        (2022, 1) => to_stringer_input(year2022::day01::solve, &input),
277        (2022, 2) => to_stringer_input(year2022::day02::solve, &input),
278        (2022, 3) => to_stringer_input(year2022::day03::solve, &input),
279        (2022, 4) => to_stringer_input(year2022::day04::solve, &input),
280        (2022, 5) => to_stringer_input(year2022::day05::solve, &input),
281        (2022, 6) => to_stringer_input(year2022::day06::solve, &input),
282        (2022, 7) => to_stringer_input(year2022::day07::solve, &input),
283        (2022, 8) => to_stringer_input(year2022::day08::solve, &input),
284        (2022, 9) => to_stringer_input(year2022::day09::solve, &input),
285        (2022, 10) => to_stringer_input(year2022::day10::solve, &input),
286        (2022, 11) => to_stringer_input(year2022::day11::solve, &input),
287        (2022, 12) => to_stringer_input(year2022::day12::solve, &input),
288        (2022, 13) => to_stringer_input(year2022::day13::solve, &input),
289        (2022, 14) => to_stringer_input(year2022::day14::solve, &input),
290        (2022, 15) => to_stringer_input(year2022::day15::solve, &input),
291        (2022, 16) => to_stringer_input(year2022::day16::solve, &input),
292        (2022, 17) => to_stringer_input(year2022::day17::solve, &input),
293        (2022, 18) => to_stringer_input(year2022::day18::solve, &input),
294        (2022, 19) => to_stringer_input(year2022::day19::solve, &input),
295        (2022, 20) => to_stringer_input(year2022::day20::solve, &input),
296        (2022, 21) => to_stringer_input(year2022::day21::solve, &input),
297        (2022, 22) => to_stringer_input(year2022::day22::solve, &input),
298        (2022, 23) => to_stringer_input(year2022::day23::solve, &input),
299        (2022, 24) => to_stringer_input(year2022::day24::solve, &input),
300        (2022, 25) => to_stringer_input(year2022::day25::solve, &input),
301        (2023, 1) => to_stringer_input(year2023::day01::solve, &input),
302        (2023, 2) => to_stringer_input(year2023::day02::solve, &input),
303        (2023, 3) => to_stringer_input(year2023::day03::solve, &input),
304        (2023, 4) => to_stringer_input(year2023::day04::solve, &input),
305        (2023, 5) => to_stringer_input(year2023::day05::solve, &input),
306        (2023, 6) => to_stringer_input(year2023::day06::solve, &input),
307        (2023, 7) => to_stringer_input(year2023::day07::solve, &input),
308        (2023, 8) => to_stringer_input(year2023::day08::solve, &input),
309        (2023, 9) => to_stringer_input(year2023::day09::solve, &input),
310        (2023, 10) => to_stringer_input(year2023::day10::solve, &input),
311        (2023, 11) => to_stringer_input(year2023::day11::solve, &input),
312        (2023, 12) => to_stringer_input(year2023::day12::solve, &input),
313        (2023, 13) => to_stringer_input(year2023::day13::solve, &input),
314        (2023, 14) => to_stringer_input(year2023::day14::solve, &input),
315        (2023, 15) => to_stringer_input(year2023::day15::solve, &input),
316        (2023, 16) => to_stringer_input(year2023::day16::solve, &input),
317        (2023, 17) => to_stringer_input(year2023::day17::solve, &input),
318        (2023, 18) => to_stringer_input(year2023::day18::solve, &input),
319        (2023, 19) => to_stringer_input(year2023::day19::solve, &input),
320        (2023, 20) => to_stringer_input(year2023::day20::solve, &input),
321        (2023, 21) => to_stringer_input(year2023::day21::solve, &input),
322        (2023, 22) => to_stringer_input(year2023::day22::solve, &input),
323        (2023, 23) => to_stringer_input(year2023::day23::solve, &input),
324        (2023, 24) => to_stringer_input(year2023::day24::solve, &input),
325        (2023, 25) => to_stringer_input(year2023::day25::solve, &input),
326        (2024, 1) => to_stringer_input(year2024::day01::solve, &input),
327        (2024, 2) => to_stringer_input(year2024::day02::solve, &input),
328        (2024, 3) => to_stringer_input(year2024::day03::solve, &input),
329        (2024, 4) => to_stringer_input(year2024::day04::solve, &input),
330        (2024, 5) => to_stringer_input(year2024::day05::solve, &input),
331        (2024, 6) => to_stringer_input(year2024::day06::solve, &input),
332        (2024, 7) => to_stringer_input(year2024::day07::solve, &input),
333        (2024, 8) => to_stringer_input(year2024::day08::solve, &input),
334        (2024, 9) => to_stringer_input(year2024::day09::solve, &input),
335        (2024, 10) => to_stringer_input(year2024::day10::solve, &input),
336        (2024, 11) => to_stringer_input(year2024::day11::solve, &input),
337        (2024, 12) => to_stringer_input(year2024::day12::solve, &input),
338        (2024, 13) => to_stringer_input(year2024::day13::solve, &input),
339        (2024, 14) => to_stringer_input(year2024::day14::solve, &input),
340        (2024, 15) => to_stringer_input(year2024::day15::solve, &input),
341        (2024, 16) => to_stringer_input(year2024::day16::solve, &input),
342        (2024, 17) => to_stringer_input(year2024::day17::solve, &input),
343        (2024, 18) => to_stringer_input(year2024::day18::solve, &input),
344        (2024, 19) => to_stringer_input(year2024::day19::solve, &input),
345        (2024, 20) => to_stringer_input(year2024::day20::solve, &input),
346        (2024, 21) => to_stringer_input(year2024::day21::solve, &input),
347        (2024, 22) => to_stringer_input(year2024::day22::solve, &input),
348        (2024, 23) => to_stringer_input(year2024::day23::solve, &input),
349        (2024, 24) => to_stringer_input(year2024::day24::solve, &input),
350        (2024, 25) => to_stringer_input(year2024::day25::solve, &input),
351        _ => Err(format!("Unsupported year={year}, day={day}, part={part}")),
352    };
353
354    #[cfg(feature = "visualization")]
355    return result.map(|_| input.visualization.take());
356
357    #[cfg(not(feature = "visualization"))]
358    result
359}
360
361/// A version of [solve](fn.solve.html) that takes strings as arguments and parses them to the required types.
362pub fn solve_raw(year: &str, day: &str, part: &str, input: &str) -> Result<ResultType, String> {
363    let year = year.parse::<u16>().map_err(|_| "Invalid year")?;
364    let day = day.parse::<u8>().map_err(|_| "Invalid day")?;
365    let part = part.parse::<u8>().map_err(|_| "Invalid part")?;
366    solve(year, day, part, input)
367}