advent_of_code_data/
data.rs

1use std::io::{BufRead, BufReader, BufWriter, Read, Write};
2
3use serde::{Deserialize, Serialize};
4use std::str::FromStr;
5use thiserror::Error;
6
7use crate::{Answer, Day, Part, Year};
8
9pub const CORRECT_ANSWER_CHAR: char = '=';
10pub const WRONG_ANSWER_CHAR: char = 'X';
11pub const LOW_ANSWER_CHAR: char = '[';
12pub const HIGH_ANSWER_CHAR: char = ']';
13
14/// Stores puzzle input and answer data.
15#[derive(Debug, PartialEq)]
16pub struct Puzzle {
17    pub day: Day,
18    pub year: Year,
19    pub input: String,
20    pub part_one_answers: Answers,
21    pub part_two_answers: Answers,
22}
23
24impl Puzzle {
25    pub fn answers(&self, part: Part) -> &Answers {
26        match part {
27            Part::One => &self.part_one_answers,
28            Part::Two => &self.part_two_answers,
29        }
30    }
31
32    pub fn answers_mut(&mut self, part: Part) -> &mut Answers {
33        match part {
34            Part::One => &mut self.part_one_answers,
35            Part::Two => &mut self.part_two_answers,
36        }
37    }
38}
39
40/// Represents the various outcomes of checking an answer against an answers
41/// database.
42#[derive(Clone, Debug, PartialEq)]
43pub enum CheckResult {
44    /// The answer is correct.
45    Correct,
46    /// The answer is incorrect.
47    Wrong,
48    /// The answer is too low and incorrect.
49    TooLow,
50    /// The answer is too high and incorrect.
51    TooHigh,
52}
53
54/// Stores correct and incorrect answers for a puzzle, along with hints such as
55/// "too large" and "too small".
56#[derive(Debug, PartialEq)]
57pub struct Answers {
58    correct_answer: Option<Answer>,
59    wrong_answers: Vec<Answer>,
60    low_bounds: Option<i128>,
61    high_bounds: Option<i128>,
62}
63
64impl Answers {
65    /// Initialize new `Answers` object.
66    pub fn new() -> Self {
67        Answers {
68            correct_answer: None,
69            wrong_answers: Vec::new(),
70            low_bounds: None,
71            high_bounds: None,
72        }
73    }
74
75    pub fn correct_answer_ref(&self) -> &Option<Answer> {
76        &self.correct_answer
77    }
78
79    pub fn wrong_answers_ref(&self) -> &Vec<Answer> {
80        &self.wrong_answers
81    }
82
83    pub fn low_bounds_ref(&self) -> &Option<i128> {
84        &self.low_bounds
85    }
86
87    pub fn high_bounds_ref(&self) -> &Option<i128> {
88        &self.high_bounds
89    }
90
91    /// Checks if this answer is correct or incorrect according to the information
92    /// stored in this `Answers` database.
93    ///
94    /// `None` is returned when the supplied answer does not match any known
95    /// incorrect values, and the database does not have a known correct value.
96    /// When a `None` value is returned, the caller should submit the answer as
97    /// a solution to the puzzle using the Advent of Code client. The caller
98    /// should then update this object with the response depending on if the
99    /// client say it was correct or incorrect.
100    pub fn check(&self, answer: &Answer) -> Option<CheckResult> {
101        // Check the answer against the optional low and high value boundaries.
102        match (answer.to_i128(), &self.low_bounds, &self.high_bounds) {
103            (Some(answer), Some(low), _) if answer <= *low => {
104                return Some(CheckResult::TooLow);
105            }
106            (Some(answer), _, Some(high)) if answer >= *high => return Some(CheckResult::TooHigh),
107            _ => {}
108        };
109
110        // Check if the answer is matches any known incorrect answers.
111        for wrong_answer in &self.wrong_answers {
112            if wrong_answer == answer {
113                return Some(CheckResult::Wrong);
114            }
115        }
116
117        // Now see if the answer matches the correct answer or return `None` if
118        // the correct answer is not known.
119        match &self.correct_answer {
120            Some(correct) if correct == answer => Some(CheckResult::Correct),
121            Some(_) => Some(CheckResult::Wrong),
122            None => None,
123        }
124    }
125
126    /// Adds an answer to the list of known wrong answers.
127    pub fn add_wrong_answer(&mut self, answer: Answer) {
128        // TODO: Verify that wrong answer is not the correct answer
129        // TODO: Error if the wrong answer has a newline.
130        if self.wrong_answers.iter().all(|x| x != &answer) {
131            self.wrong_answers.push(answer);
132        } else {
133            tracing::warn!(
134                "skipped adding duplicate wrong answer to answers cache: `{}`",
135                answer
136            );
137        }
138    }
139
140    /// Sets this answer as the known correct answer.
141    pub fn set_correct_answer(&mut self, answer: Answer) {
142        // TODO: Verify that correct answer is not a wrong answer, hi or low.
143        // TODO: Error if the right answer has a newline.
144        self.correct_answer = Some(answer);
145    }
146
147    /// Sets a low boundary value in the cache.
148    ///
149    /// If the cache has an existing low boundary then the highest value will be
150    /// used as the new high boundary.
151    ///
152    /// Any numeric answer passed to `Answers::check` will be returned as
153    /// `CheckResult::TooLow` if it equals or is smaller than the low boundary.
154    pub fn set_low_bounds(&mut self, answer: Answer) -> i128 {
155        // TODO: Verify that low bounds is not a correct answer.
156        // TODO: Verify that low bounds is not larger or equal to high bounds.
157        // TODO: Remove panic and return Error if the answer is not an integer.
158        let answer = answer.to_i128().expect("low bounds answer must be numeric");
159
160        match &self.low_bounds {
161            Some(low) if answer > *low => {
162                self.low_bounds = Some(answer);
163                answer
164            }
165            Some(low) => *low,
166            None => {
167                self.low_bounds = Some(answer);
168                answer
169            }
170        }
171    }
172
173    /// Sets a high boundary value in the cache.
174    ///
175    /// If the cache has an existing high boundary then the lowest value will be
176    /// used as the new high boundary.
177    ///
178    /// Any numeric answer passed to `Answers::check` will be returned as
179    /// `CheckResult::TooHigh` if it equals or is larger than the high boundary.
180    pub fn set_high_bounds(&mut self, answer: Answer) -> i128 {
181        // TODO: Verify that high bounds is not a correct answer.
182        // TODO: Verify that high bounds is not smaller or equal to low bounds.
183        // TODO: Remove panic and return Error if the answer is not an integer.
184        let answer = answer
185            .to_i128()
186            .expect("high bounds answer must be numeric");
187
188        match &self.high_bounds {
189            Some(high) if answer < *high => {
190                self.high_bounds = Some(answer);
191                answer
192            }
193            Some(high) => *high,
194            None => {
195                self.high_bounds = Some(answer);
196                answer
197            }
198        }
199    }
200
201    pub fn serialize_to_string(&self) -> String {
202        // TODO: Convert unwraps into Errors.
203        let mut buf = BufWriter::new(Vec::new());
204        self.serialize(&mut buf);
205
206        String::from_utf8(buf.into_inner().unwrap()).unwrap()
207    }
208
209    pub fn serialize<W: Write>(&self, writer: &mut BufWriter<W>) {
210        // TODO: Support newlines in answers.
211        // TODO: Convert unwraps to Errors.
212
213        // Sort wrong answers alphabetically to ensure stability with diffs
214        // for version control.
215        let mut wrong_answers: Vec<String> =
216            self.wrong_answers.iter().map(|x| x.to_string()).collect();
217        wrong_answers.sort();
218
219        // Serialize all the answers to buffered writer.
220        fn write_field<S: ToString, W: Write>(
221            field: &Option<S>,
222            prefix: char,
223            writer: &mut BufWriter<W>,
224        ) {
225            if let Some(f) = field {
226                let s = f.to_string();
227                assert!(!s.contains('\n'));
228
229                writeln!(writer, "{} {}", prefix, &s).unwrap();
230            }
231        }
232
233        write_field(&self.correct_answer, CORRECT_ANSWER_CHAR, writer);
234        write_field(&self.low_bounds, LOW_ANSWER_CHAR, writer);
235        write_field(&self.high_bounds, HIGH_ANSWER_CHAR, writer);
236
237        for wrong_answer in wrong_answers {
238            write_field(&Some(wrong_answer), WRONG_ANSWER_CHAR, writer);
239        }
240    }
241
242    pub fn deserialize_from_str(text: &str) -> Result<Self, AnswerDeserializationError> {
243        // TODO: Write tests.
244        let mut buf = BufReader::new(text.as_bytes());
245        Self::deserialize(&mut buf)
246    }
247
248    pub fn deserialize<R: Read>(
249        reader: &mut BufReader<R>,
250    ) -> Result<Self, AnswerDeserializationError> {
251        // TODO: Convert unwrap/expect into Errors
252        // TODO: Write tests.
253        let mut answers = Answers::new();
254
255        // Each line in the input string is an entry in the answers database.
256        // The first character indicates the type of answer, and the characters
257        // following the space hold the answer value.
258        for line in reader.lines() {
259            let line = line.unwrap();
260            let (ty, value) = line
261                .split_once(' ')
262                .ok_or_else(|| AnswerDeserializationError::UnknownLineFormat(line.clone()))?;
263
264            match ty.chars().next().unwrap() {
265                CORRECT_ANSWER_CHAR => {
266                    answers.set_correct_answer(
267                        Answer::from_str(value).expect("Answer::from_str does not return Err"),
268                    );
269                }
270                WRONG_ANSWER_CHAR => {
271                    answers.add_wrong_answer(
272                        Answer::from_str(value).expect("Answer::from_str does not return Err"),
273                    );
274                }
275                LOW_ANSWER_CHAR => {
276                    let low = value.parse::<i128>().map_err(|_| {
277                        AnswerDeserializationError::LowBoundRequiresInt(value.to_string())
278                    })?;
279                    answers.set_low_bounds(Answer::Int(low));
280                }
281                HIGH_ANSWER_CHAR => {
282                    let high = value.parse::<i128>().map_err(|_| {
283                        AnswerDeserializationError::HighBoundRequiresInt(value.to_string())
284                    })?;
285                    answers.set_high_bounds(Answer::Int(high));
286                }
287                c => {
288                    return Err(AnswerDeserializationError::UnknownAnswerType(c));
289                }
290            }
291        }
292
293        Ok(answers)
294    }
295}
296
297impl Default for Answers {
298    fn default() -> Self {
299        Self::new()
300    }
301}
302
303#[derive(Debug, Error)]
304pub enum AnswerDeserializationError {
305    #[error(
306        "expected type char followed by a space followed by the answer value, but got `{}`", .0
307    )]
308    UnknownLineFormat(String),
309    #[error(
310        "unknown answer type char `{}` when deserializing (expected `{}`, `{}`, `{}`, or `{}`)",
311        .0,
312        CORRECT_ANSWER_CHAR,
313        WRONG_ANSWER_CHAR,
314        LOW_ANSWER_CHAR,
315        HIGH_ANSWER_CHAR
316    )]
317    UnknownAnswerType(char),
318    #[error("the low bound answer `{}` must be parsable as an i128 integer", .0)]
319    LowBoundRequiresInt(String),
320    #[error("the high bound answer `{}` must be parsable as an i128 integer", .0)]
321    HighBoundRequiresInt(String),
322}
323
324#[derive(Serialize, Deserialize)]
325pub struct Session {
326    pub session_id: String,
327    pub submit_wait_until: Option<chrono::DateTime<chrono::Utc>>,
328}
329
330impl Session {
331    pub fn new<S: Into<String>>(session_id: S) -> Self {
332        Self {
333            session_id: session_id.into(),
334            submit_wait_until: None,
335        }
336    }
337}
338
339#[cfg(test)]
340mod tests {
341
342    use super::*;
343
344    #[test]
345    fn add_wrong_answers() {
346        let mut answers = Answers::new();
347
348        answers.add_wrong_answer(Answer::from_str("hello world").unwrap());
349        answers.add_wrong_answer(Answer::from_str("foobar").unwrap());
350        answers.add_wrong_answer(Answer::Int(42));
351
352        assert_eq!(
353            answers.wrong_answers_ref(),
354            &vec![
355                Answer::String("hello world".to_string()),
356                Answer::String("foobar".to_string()),
357                Answer::Int(42)
358            ]
359        )
360    }
361
362    #[test]
363    fn correct_answer_when_checking() {
364        let mut answers = Answers::new();
365
366        answers.set_correct_answer(Answer::from_str("hello").unwrap());
367        answers.add_wrong_answer(Answer::from_str("abc").unwrap());
368        answers.add_wrong_answer(Answer::from_str("stop").unwrap());
369
370        assert_eq!(
371            answers.check(&Answer::from_str("hello").unwrap()),
372            Some(CheckResult::Correct)
373        );
374    }
375
376    #[test]
377    fn wrong_answer_when_checking() {
378        let mut answers = Answers::new();
379
380        answers.set_correct_answer(Answer::from_str("hello").unwrap());
381        answers.add_wrong_answer(Answer::from_str("abc").unwrap());
382        answers.add_wrong_answer(Answer::from_str("stop").unwrap());
383
384        assert_eq!(
385            answers.check(&Answer::from_str("abc").unwrap()),
386            Some(CheckResult::Wrong)
387        );
388        assert_eq!(
389            answers.check(&Answer::from_str("stop").unwrap()),
390            Some(CheckResult::Wrong)
391        );
392    }
393
394    #[test]
395    fn set_lower_high_boundary_replaces_prev() {
396        let mut answers = Answers::new();
397        assert_eq!(answers.high_bounds_ref(), &None);
398
399        assert_eq!(answers.set_high_bounds(Answer::Int(30)), 30);
400        assert_eq!(answers.high_bounds_ref(), &Some(30));
401
402        assert_eq!(answers.set_high_bounds(Answer::Int(31)), 30);
403        assert_eq!(answers.high_bounds_ref(), &Some(30));
404
405        assert_eq!(answers.set_high_bounds(Answer::Int(12)), 12);
406        assert_eq!(answers.high_bounds_ref(), &Some(12));
407    }
408
409    #[test]
410    fn set_higher_low_boundary_replaces_prev() {
411        let mut answers = Answers::new();
412        assert_eq!(answers.low_bounds_ref(), &None);
413
414        assert_eq!(answers.set_low_bounds(Answer::Int(4)), 4);
415        assert_eq!(answers.low_bounds_ref(), &Some(4));
416
417        assert_eq!(answers.set_low_bounds(Answer::Int(-2)), 4);
418        assert_eq!(answers.low_bounds_ref(), &Some(4));
419
420        assert_eq!(answers.set_low_bounds(Answer::Int(187)), 187);
421        assert_eq!(answers.low_bounds_ref(), &Some(187));
422    }
423
424    #[test]
425    fn check_answer_uses_low_bounds_if_set() {
426        let mut answers = Answers::new();
427        assert!(answers.check(&Answer::Int(100)).is_none());
428
429        answers.set_low_bounds(Answer::Int(90));
430
431        assert_eq!(answers.check(&Answer::Int(85)), Some(CheckResult::TooLow));
432        assert_eq!(answers.check(&Answer::Int(90)), Some(CheckResult::TooLow));
433        assert!(answers.check(&Answer::Int(100)).is_none());
434
435        answers.add_wrong_answer(Answer::Int(90));
436        assert_eq!(answers.check(&Answer::Int(90)), Some(CheckResult::TooLow));
437    }
438
439    #[test]
440    fn check_answer_uses_high_bounds_if_set() {
441        let mut answers = Answers::new();
442        assert!(answers.check(&Answer::Int(100)).is_none());
443
444        answers.set_high_bounds(Answer::Int(90));
445
446        assert_eq!(answers.check(&Answer::Int(100)), Some(CheckResult::TooHigh));
447        assert_eq!(answers.check(&Answer::Int(90)), Some(CheckResult::TooHigh));
448        assert!(answers.check(&Answer::Int(85)).is_none());
449
450        answers.add_wrong_answer(Answer::Int(90));
451        assert_eq!(answers.check(&Answer::Int(90)), Some(CheckResult::TooHigh));
452    }
453
454    #[test]
455    fn check_answer_checks_high_and_low_bounds_if_set() {
456        let mut answers = Answers::new();
457
458        answers.set_low_bounds(Answer::Int(96));
459        answers.set_high_bounds(Answer::Int(103));
460
461        assert_eq!(answers.check(&Answer::Int(107)), Some(CheckResult::TooHigh));
462        assert_eq!(answers.check(&Answer::Int(103)), Some(CheckResult::TooHigh));
463        assert_eq!(answers.check(&Answer::Int(100)), None);
464        assert_eq!(answers.check(&Answer::Int(98)), None);
465        assert_eq!(answers.check(&Answer::Int(96)), Some(CheckResult::TooLow));
466        assert_eq!(answers.check(&Answer::Int(-5)), Some(CheckResult::TooLow));
467    }
468
469    #[test]
470    fn check_answer_bounds_checked_if_int_or_int_str() {
471        let mut answers = Answers::new();
472
473        answers.set_low_bounds(Answer::Int(-50));
474        answers.set_high_bounds(Answer::Int(25));
475        answers.add_wrong_answer(Answer::Int(-9));
476        answers.add_wrong_answer(Answer::Int(1));
477        answers.add_wrong_answer(Answer::from_str("xyz").unwrap());
478
479        assert_eq!(
480            answers.check(&Answer::from_str("55").unwrap()),
481            Some(CheckResult::TooHigh)
482        );
483        assert_eq!(answers.check(&Answer::Int(55)), Some(CheckResult::TooHigh));
484
485        assert_eq!(answers.check(&Answer::Int(10)), None);
486        assert_eq!(answers.check(&Answer::from_str("10").unwrap()), None);
487
488        assert_eq!(
489            answers.check(&Answer::from_str("-74").unwrap()),
490            Some(CheckResult::TooLow)
491        );
492        assert_eq!(answers.check(&Answer::Int(-74)), Some(CheckResult::TooLow));
493    }
494
495    #[test]
496    fn wrong_answers_if_in_bounds() {
497        let mut answers = Answers::new();
498
499        answers.set_low_bounds(Answer::Int(-50));
500        answers.set_high_bounds(Answer::Int(25));
501        answers.add_wrong_answer(Answer::Int(-9));
502        answers.add_wrong_answer(Answer::Int(1));
503        answers.add_wrong_answer(Answer::Int(100));
504        answers.add_wrong_answer(Answer::Int(-100));
505        answers.add_wrong_answer(Answer::from_str("xyz").unwrap());
506
507        assert_eq!(
508            answers.check(&Answer::from_str("-9").unwrap()),
509            Some(CheckResult::Wrong)
510        );
511        assert_eq!(answers.check(&Answer::Int(-9)), Some(CheckResult::Wrong));
512        assert_eq!(
513            answers.check(&Answer::from_str("1").unwrap()),
514            Some(CheckResult::Wrong)
515        );
516        assert_eq!(answers.check(&Answer::Int(1)), Some(CheckResult::Wrong));
517        assert_eq!(
518            answers.check(&Answer::from_str("xyz").unwrap()),
519            Some(CheckResult::Wrong)
520        );
521        assert_eq!(
522            answers.check(&Answer::from_str("100").unwrap()),
523            Some(CheckResult::TooHigh)
524        );
525        assert_eq!(answers.check(&Answer::Int(100)), Some(CheckResult::TooHigh));
526        assert_eq!(
527            answers.check(&Answer::from_str("-100").unwrap()),
528            Some(CheckResult::TooLow)
529        );
530        assert_eq!(answers.check(&Answer::Int(-100)), Some(CheckResult::TooLow));
531    }
532
533    #[test]
534    fn answers_are_wrong_when_there_is_correct_answer_that_does_not_match() {
535        let mut answers = Answers::new();
536
537        answers.set_correct_answer(Answer::from_str("yes").unwrap());
538
539        assert_eq!(
540            answers.check(&Answer::from_str("yes").unwrap()),
541            Some(CheckResult::Correct)
542        );
543        assert_eq!(
544            answers.check(&Answer::from_str("no").unwrap()),
545            Some(CheckResult::Wrong)
546        );
547        assert_eq!(
548            answers.check(&Answer::from_str("maybe").unwrap()),
549            Some(CheckResult::Wrong)
550        );
551    }
552
553    #[test]
554    fn serialize_answers_to_text() {
555        let text = Answers {
556            correct_answer: Some(Answer::Int(12)),
557            wrong_answers: vec![
558                Answer::Int(-9),
559                Answer::Int(1),
560                Answer::Int(100),
561                Answer::from_str("xyz").unwrap(),
562            ],
563            low_bounds: Some(-50),
564            high_bounds: Some(25),
565        }
566        .serialize_to_string();
567
568        assert_eq!(text, "= 12\n[ -50\n] 25\nX -9\nX 1\nX 100\nX xyz\n");
569    }
570
571    #[test]
572    fn serialize_answers_to_text_with_no_correct() {
573        let text = Answers {
574            correct_answer: None,
575            wrong_answers: vec![
576                Answer::Int(-9),
577                Answer::Int(1),
578                Answer::Int(100),
579                Answer::from_str("xyz").unwrap(),
580            ],
581            low_bounds: Some(-50),
582            high_bounds: Some(25),
583        }
584        .serialize_to_string();
585
586        assert_eq!(text, "[ -50\n] 25\nX -9\nX 1\nX 100\nX xyz\n");
587    }
588
589    #[test]
590    fn serialize_answers_to_text_with_missing_correct_and_high() {
591        let text = Answers {
592            correct_answer: None,
593            wrong_answers: vec![
594                Answer::Int(-9),
595                Answer::Int(1),
596                Answer::Int(100),
597                Answer::from_str("xyz").unwrap(),
598            ],
599            low_bounds: Some(-50),
600            high_bounds: None,
601        }
602        .serialize_to_string();
603
604        assert_eq!(text, "[ -50\nX -9\nX 1\nX 100\nX xyz\n");
605    }
606
607    #[test]
608    fn deserialize_answers_from_text() {
609        let answers = Answers::deserialize_from_str("= 12\n[ -50\n] 25\nX -9\nX 1\nX 100\nX xyz\n")
610            .expect("no deserialization errors exepcted");
611
612        assert_eq!(
613            answers,
614            Answers {
615                correct_answer: Some(Answer::Int(12)),
616                wrong_answers: vec![
617                    Answer::Int(-9),
618                    Answer::Int(1),
619                    Answer::Int(100),
620                    Answer::from_str("xyz").unwrap(),
621                ],
622                low_bounds: Some(-50),
623                high_bounds: Some(25),
624            }
625        );
626    }
627
628    #[test]
629    fn deserialize_answers_to_text_with_no_correct() {
630        let answers = Answers::deserialize_from_str("[ -50\n] 25\nX -9\nX 1\nX 100\nX xyz\n")
631            .expect("no deserialization errors exepcted");
632
633        assert_eq!(
634            answers,
635            Answers {
636                correct_answer: None,
637                wrong_answers: vec![
638                    Answer::Int(-9),
639                    Answer::Int(1),
640                    Answer::Int(100),
641                    Answer::from_str("xyz").unwrap(),
642                ],
643                low_bounds: Some(-50),
644                high_bounds: Some(25),
645            }
646        );
647    }
648
649    #[test]
650    fn deserialize_answers_to_text_with_missing_correct_and_high() {
651        let answers = Answers::deserialize_from_str("[ -50\nX -9\nX 1\nX 100\nX xyz\n")
652            .expect("no deserialization errors exepcted");
653
654        assert_eq!(
655            answers,
656            Answers {
657                correct_answer: None,
658                wrong_answers: vec![
659                    Answer::Int(-9),
660                    Answer::Int(1),
661                    Answer::Int(100),
662                    Answer::from_str("xyz").unwrap(),
663                ],
664                low_bounds: Some(-50),
665                high_bounds: None,
666            }
667        );
668    }
669
670    #[test]
671    fn deserialize_answers_with_spaces() {
672        let answers = Answers::deserialize_from_str("= hello world\nX foobar\nX one two three\n")
673            .expect("no deserialization errors exepcted");
674
675        assert_eq!(
676            answers,
677            Answers {
678                correct_answer: Some(Answer::from_str("hello world").unwrap()),
679                wrong_answers: vec![
680                    Answer::from_str("foobar").unwrap(),
681                    Answer::from_str("one two three").unwrap(),
682                ],
683                low_bounds: None,
684                high_bounds: None,
685            }
686        );
687    }
688}