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#[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#[derive(Clone, Debug, PartialEq)]
43pub enum CheckResult {
44 Correct,
46 Wrong,
48 TooLow,
50 TooHigh,
52}
53
54#[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 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 pub fn check(&self, answer: &Answer) -> Option<CheckResult> {
101 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 for wrong_answer in &self.wrong_answers {
112 if wrong_answer == answer {
113 return Some(CheckResult::Wrong);
114 }
115 }
116
117 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 pub fn add_wrong_answer(&mut self, answer: Answer) {
128 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 pub fn set_correct_answer(&mut self, answer: Answer) {
142 self.correct_answer = Some(answer);
145 }
146
147 pub fn set_low_bounds(&mut self, answer: Answer) -> i128 {
155 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 pub fn set_high_bounds(&mut self, answer: Answer) -> i128 {
181 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 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 let mut wrong_answers: Vec<String> =
216 self.wrong_answers.iter().map(|x| x.to_string()).collect();
217 wrong_answers.sort();
218
219 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 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 let mut answers = Answers::new();
254
255 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}