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
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#![forbid(unsafe_code)]
/*!
This crates provides solutions for Advent of Code problems.
*/
#![crate_name = "advent_of_code"]

mod input;
#[cfg(feature = "visualization")]
pub mod painter;
mod year2017;
mod year2018;
mod year2019;

use input::{Input, Part};
#[cfg(feature = "visualization")]
use painter::PainterRef;

fn to_stringer<T: ToString>(
    function: fn(&str) -> Result<T, String>,
    input: &str,
) -> Result<String, String> {
    function(input).map(|value| value.to_string())
}

fn to_stringer_input<T: ToString>(
    function: fn(&mut Input) -> Result<T, String>,
    input: &mut Input,
) -> Result<String, String> {
    function(input).map(|value| value.to_string())
}

/// Returns the solution for the specified given problem and input.
///
/// # Arguments
///
/// * `year` - The year of the problem, as in 2018 or 2019.
/// * `day` - The day of the problem - from 1 to 25.
/// * `part` - The part of the problem - either 1 or 2.
/// * `input` - The input to the problem.
///
/// # Examples
/// ```
/// use advent_of_code::solve;
/// let solution = solve(2019, 1, 1, "14");
/// assert_eq!(solution, Ok("2".to_string()));
/// ```
pub fn solve(
    year: u16,
    day: u8,
    part: u8,
    input_string: &str,
    #[cfg(feature = "visualization")] painter: PainterRef,
) -> Result<String, String> {
    #![allow(clippy::let_and_return)]

    if input_string.is_empty() {
        return Err("Empty input".to_string());
    }

    let mut input = Input {
        // FIXME: Validate parts.
        part: if part == 1 { Part::One } else { Part::Two },
        text: input_string.to_string(),
        #[cfg(feature = "visualization")]
        painter,
    };

    let result = match (year, day, part) {
        (2017, 1, 1) => to_stringer(year2017::day01::part1, input_string),
        (2017, 1, 2) => to_stringer(year2017::day01::part2, input_string),
        (2017, 2, 1) => to_stringer(year2017::day02::part1, input_string),
        (2017, 2, 2) => to_stringer(year2017::day02::part2, input_string),
        (2017, 3, 1) => to_stringer(year2017::day03::part1, input_string),
        (2017, 3, 2) => to_stringer(year2017::day03::part2, input_string),
        (2017, 4, 1) => to_stringer(year2017::day04::part1, input_string),
        (2017, 4, 2) => to_stringer(year2017::day04::part2, input_string),
        (2017, 5, 1) => to_stringer(year2017::day05::part1, input_string),
        (2017, 5, 2) => to_stringer(year2017::day05::part2, input_string),
        (2017, 6, 1) => to_stringer(year2017::day06::part1, input_string),
        (2017, 6, 2) => to_stringer(year2017::day06::part2, input_string),
        (2017, 7, 1) => to_stringer(year2017::day07::part1, input_string),
        (2017, 7, 2) => to_stringer(year2017::day07::part2, input_string),
        (2017, 8, 1) => to_stringer(year2017::day08::part1, input_string),
        (2017, 8, 2) => to_stringer(year2017::day08::part2, input_string),
        (2017, 9, 1) => to_stringer(year2017::day09::part1, input_string),
        (2017, 9, 2) => to_stringer(year2017::day09::part2, input_string),
        (2017, 10, 1) => to_stringer(year2017::day10::part1, input_string),
        (2017, 10, 2) => to_stringer(year2017::day10::part2, input_string),
        (2017, 11, 1) => to_stringer(year2017::day11::part1, input_string),
        (2017, 11, 2) => to_stringer(year2017::day11::part2, input_string),
        (2017, 12, 1) => to_stringer(year2017::day12::part1, input_string),
        (2017, 12, 2) => to_stringer(year2017::day12::part2, input_string),
        (2017, 13, 1) => to_stringer(year2017::day13::part1, input_string),
        (2017, 13, 2) => to_stringer(year2017::day13::part2, input_string),
        (2017, 14, _) => to_stringer_input(year2017::day14::solve, &mut input),
        (2017, 15, _) => to_stringer_input(year2017::day15::solve, &mut input),
        (2018, 1, 1) => to_stringer(year2018::day01::part1, input_string),
        (2018, 1, 2) => to_stringer(year2018::day01::part2, input_string),
        (2018, 2, 1) => to_stringer(year2018::day02::part1, input_string),
        (2018, 2, 2) => to_stringer(year2018::day02::part2, input_string),
        (2018, 3, 1) => to_stringer(year2018::day03::part1, input_string),
        (2018, 3, 2) => to_stringer(year2018::day03::part2, input_string),
        (2018, 4, 1) => to_stringer(year2018::day04::part1, input_string),
        (2018, 4, 2) => to_stringer(year2018::day04::part2, input_string),
        (2018, 5, 1) => to_stringer(year2018::day05::part1, input_string),
        (2018, 5, 2) => to_stringer(year2018::day05::part2, input_string),
        (2018, 6, 1) => to_stringer(year2018::day06::part1, input_string),
        (2018, 6, 2) => to_stringer(year2018::day06::part2, input_string),
        (2018, 7, 1) => to_stringer(year2018::day07::part1, input_string),
        (2018, 7, 2) => to_stringer(year2018::day07::part2, input_string),
        (2018, 8, 1) => to_stringer(year2018::day08::part1, input_string),
        (2018, 8, 2) => to_stringer(year2018::day08::part2, input_string),
        (2018, 9, 1) => to_stringer(year2018::day09::part1, input_string),
        (2018, 9, 2) => to_stringer(year2018::day09::part2, input_string),
        (2018, 10, 1) => to_stringer(year2018::day10::part1, input_string),
        (2018, 10, 2) => to_stringer(year2018::day10::part2, input_string),
        (2018, 11, 1) => to_stringer(year2018::day11::part1, input_string),
        (2018, 11, 2) => to_stringer(year2018::day11::part2, input_string),
        (2018, 12, 1) => to_stringer(year2018::day12::part1, input_string),
        (2018, 12, 2) => to_stringer(year2018::day12::part2, input_string),
        (2018, 13, 1) => to_stringer(year2018::day13::part1, input_string),
        (2018, 13, 2) => to_stringer(year2018::day13::part2, input_string),
        (2018, 14, 1) => to_stringer(year2018::day14::part1, input_string),
        (2018, 14, 2) => to_stringer(year2018::day14::part2, input_string),
        (2018, 15, 1) => to_stringer(year2018::day15::part1, input_string),
        (2018, 15, 2) => to_stringer(year2018::day15::part2, input_string),
        (2018, 16, 1) => to_stringer(year2018::day16::part1, input_string),
        (2018, 16, 2) => to_stringer(year2018::day16::part2, input_string),
        (2018, 17, 1) => to_stringer(year2018::day17::part1, input_string),
        (2018, 17, 2) => to_stringer(year2018::day17::part2, input_string),
        (2018, 18, 1) => to_stringer(year2018::day18::part1, input_string),
        (2018, 18, 2) => to_stringer(year2018::day18::part2, input_string),
        (2018, 19, 1) => to_stringer(year2018::day19::part1, input_string),
        (2018, 19, 2) => to_stringer(year2018::day19::part2, input_string),
        (2018, 20, 1) => to_stringer(year2018::day20::part1, input_string),
        (2018, 20, 2) => to_stringer(year2018::day20::part2, input_string),
        (2018, 21, 1) => to_stringer(year2018::day21::part1, input_string),
        (2018, 21, 2) => to_stringer(year2018::day21::part2, input_string),
        (2018, 22, 1) => to_stringer(year2018::day22::part1, input_string),
        (2018, 22, 2) => to_stringer(year2018::day22::part2, input_string),
        (2018, 23, 1) => to_stringer(year2018::day23::part1, input_string),
        (2018, 23, 2) => to_stringer(year2018::day23::part2, input_string),
        (2018, 24, 1) => to_stringer(year2018::day24::part1, input_string),
        (2018, 24, 2) => to_stringer(year2018::day24::part2, input_string),
        (2018, 25, 1) => to_stringer(year2018::day25::part1, input_string),
        (2018, 25, 2) => to_stringer(year2018::day25::part2, input_string),
        (2019, 1, 1) => to_stringer(year2019::day01::part1, input_string),
        (2019, 1, 2) => to_stringer(year2019::day01::part2, input_string),
        (2019, 2, 1) => to_stringer(year2019::day02::part1, input_string),
        (2019, 2, 2) => to_stringer(year2019::day02::part2, input_string),
        (2019, 3, _) => to_stringer_input(year2019::day03::solve, &mut input),
        (2019, 4, 1) => to_stringer(year2019::day04::part1, input_string),
        (2019, 4, 2) => to_stringer(year2019::day04::part2, input_string),
        (2019, 5, 1) => to_stringer(year2019::day05::part1, input_string),
        (2019, 5, 2) => to_stringer(year2019::day05::part2, input_string),
        (2019, 6, 1) => to_stringer(year2019::day06::part1, input_string),
        (2019, 6, 2) => to_stringer(year2019::day06::part2, input_string),
        (2019, 7, _) => to_stringer_input(year2019::day07::solve, &mut input),
        (2019, 8, 1) => to_stringer(year2019::day08::part1, input_string),
        (2019, 8, 2) => to_stringer(year2019::day08::part2, input_string),
        (2019, 9, 1) => to_stringer(year2019::day09::part1, input_string),
        (2019, 9, 2) => to_stringer(year2019::day09::part2, input_string),
        (2019, 10, 1) => to_stringer(year2019::day10::part1, input_string),
        (2019, 10, 2) => to_stringer(year2019::day10::part2, input_string),
        (2019, 11, 1) => to_stringer(year2019::day11::part1, input_string),
        (2019, 11, 2) => to_stringer(year2019::day11::part2, input_string),
        (2019, 12, 1) => to_stringer(year2019::day12::part1, input_string),
        (2019, 12, 2) => to_stringer(year2019::day12::part2, input_string),
        (2019, 13, _) => to_stringer_input(year2019::day13::solve, &mut input),
        (2019, 14, 1) => to_stringer(year2019::day14::part1, input_string),
        (2019, 14, 2) => to_stringer(year2019::day14::part2, input_string),
        (2019, 15, 1) => to_stringer(year2019::day15::part1, input_string),
        (2019, 15, 2) => to_stringer(year2019::day15::part2, input_string),
        (2019, 16, 1) => to_stringer(year2019::day16::part1, input_string),
        (2019, 16, 2) => to_stringer(year2019::day16::part2, input_string),
        (2019, 17, 1) => to_stringer(year2019::day17::part1, input_string),
        (2019, 17, 2) => to_stringer(year2019::day17::part2, input_string),
        (2019, 18, _) => to_stringer_input(year2019::day18::solve, &mut input),
        (2019, 19, 1) => to_stringer(year2019::day19::part1, input_string),
        (2019, 19, 2) => to_stringer(year2019::day19::part2, input_string),
        (2019, 20, 1) => to_stringer(year2019::day20::part1, input_string),
        (2019, 20, 2) => to_stringer(year2019::day20::part2, input_string),
        (2019, 21, 1) => to_stringer(year2019::day21::part1, input_string),
        (2019, 21, 2) => to_stringer(year2019::day21::part2, input_string),
        (2019, 22, 1) => to_stringer(year2019::day22::part1, input_string),
        (2019, 22, 2) => to_stringer(year2019::day22::part2, input_string),
        (2019, 23, 1) => to_stringer(year2019::day23::part1, input_string),
        (2019, 23, 2) => to_stringer(year2019::day23::part2, input_string),
        (2019, 24, 1) => to_stringer(year2019::day24::part1, input_string),
        (2019, 24, 2) => to_stringer(year2019::day24::part2, input_string),
        (2019, 25, 1) => to_stringer(year2019::day25::part1, input_string),
        (2019, 25, 2) => to_stringer(year2019::day25::part2, input_string),
        _ => Err(format!(
            "Unsupported year={}, day={}, part={}",
            year, day, part
        )),
    };

    #[cfg(feature = "visualization")]
    if result.is_err() {
        // TODO: Report error. But perhaps not, return normally, and await ack in wait_forever.
        input.painter.shadow_blur(10);
    }

    result
}

/// A version of [solve](fn.solve.html) that takes strings as arguments and parses them to the required types.
pub fn solve_raw(
    year_string: &str,
    day_string: &str,
    part_string: &str,
    input: &str,
    #[cfg(feature = "visualization")] painter: PainterRef,
) -> Result<String, String> {
    let year = year_string.parse::<u16>().map_err(|_| "Invalid year")?;
    let day = day_string.parse::<u8>().map_err(|_| "Invalid day")?;
    let part = part_string.parse::<u8>().map_err(|_| "Invalid part")?;
    solve(
        year,
        day,
        part,
        input,
        #[cfg(feature = "visualization")]
        painter,
    )
}