First day
[advent_of_code_2023.git] / src / day01.rs
1 use std::str::Lines;
2
3 use itertools::Itertools;
4
5 pub fn parse(s: &str) -> Lines {
6 s.lines()
7 }
8
9 fn calibration_value(line: &str) -> u32 {
10 let first = line.chars().find(|c| c.is_digit(10)).unwrap();
11 let last = line.chars().rev().find(|c| c.is_digit(10)).unwrap();
12 format!("{}{}", first, last).parse().unwrap()
13 }
14
15 pub fn calibration_sum(lines: &Lines) -> u32 {
16 lines.clone().map(calibration_value).sum()
17 }
18
19 fn calibration_value_corrected(line: &str) -> u32 {
20 let line_chars = line.chars().collect_vec();
21 let mut first: i32 = -1;
22 let mut last: i32 = -1;
23 let spelled_digits = [
24 "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
25 ];
26 let mut i = 0;
27 while i < line.len() {
28 if let Some(d) = line_chars[i].to_digit(10) {
29 if first == -1 {
30 first = d as i32;
31 }
32 last = d as i32;
33 } else {
34 for j in 0..spelled_digits.len() {
35 let d = spelled_digits[j];
36 if line[i..].starts_with(d) {
37 if first == -1 {
38 first = j as i32;
39 }
40 last = j as i32;
41 i += 1;
42 // We can't skip an entire word because of cases like
43 // "twone", "nineight", etc.
44 break;
45 }
46 }
47 }
48
49 i += 1;
50 }
51 format!("{}{}", first, last).parse().unwrap()
52 }
53
54 pub fn calibration_sum_corrected(lines: &Lines) -> u32 {
55 lines.clone().map(calibration_value_corrected).sum()
56 }
57
58 #[cfg(test)]
59 mod tests {
60 use super::*;
61
62 static CALIBRATION_LINES: &str = "1abc2
63 pqr3stu8vwx
64 a1b2c3d4e5f
65 treb7uchet";
66
67 #[test]
68 fn part1() {
69 let lines = parse(CALIBRATION_LINES);
70 assert_eq!(calibration_sum(&lines), 142);
71 }
72
73 static CALIBRATION_LINES_2: &str = "two1nine
74 eightwothree
75 abcone2threexyz
76 xtwone3four
77 4nineeightseven2
78 zoneight234
79 7pqrstsixteen";
80
81 #[test]
82 fn part2() {
83 let lines = parse(CALIBRATION_LINES_2);
84 assert_eq!(calibration_sum_corrected(&lines), 281);
85 }
86 }