116 lines
3.0 KiB
Rust
116 lines
3.0 KiB
Rust
advent_of_code::solution!(1);
|
|
|
|
fn parse(input: &str) -> Vec<u32> {
|
|
input
|
|
.lines()
|
|
.filter_map(|l| {
|
|
let v: Vec<&str> = l.matches(char::is_numeric).collect();
|
|
if !v.is_empty() {
|
|
let tens = v[0].parse::<u32>().unwrap() * 10;
|
|
let ones = v[v.len() - 1].parse::<u32>().unwrap();
|
|
Some(tens + ones)
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
pub fn part_one(input: &str) -> Option<u32> {
|
|
let lines = parse(input);
|
|
Some(lines.iter().sum())
|
|
}
|
|
|
|
pub fn part_two(input: &str) -> Option<u32> {
|
|
Some(sub_letters_for_digits(input).iter().sum())
|
|
}
|
|
|
|
fn char_to_num(c: char) -> Option<u32> {
|
|
match c {
|
|
'0' => Some(0),
|
|
'1' => Some(1),
|
|
'2' => Some(2),
|
|
'3' => Some(3),
|
|
'4' => Some(4),
|
|
'5' => Some(5),
|
|
'6' => Some(6),
|
|
'7' => Some(7),
|
|
'8' => Some(8),
|
|
'9' => Some(9),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
const DIGITS: [&'static str; 10] = [
|
|
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
|
|
];
|
|
|
|
fn letter_digit_at(line: &str, index: usize) -> Option<u32> {
|
|
for (dindex, d) in DIGITS.iter().enumerate() {
|
|
if index + d.len() > line.len() {
|
|
continue;
|
|
}
|
|
let index2 = index + d.len();
|
|
let substring: &str = line[index..index2].as_ref();
|
|
if *d == substring {
|
|
return Some(dindex as u32);
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
fn digit_for_char(line: &str, index: usize, c: char) -> Option<u32> {
|
|
if c.is_ascii_digit() {
|
|
char_to_num(c)
|
|
} else {
|
|
letter_digit_at(line, index)
|
|
}
|
|
}
|
|
|
|
fn sub_letters_for_digits(input: &str) -> Vec<u32> {
|
|
input
|
|
.lines()
|
|
.filter_map(|line| {
|
|
if !line.is_empty() {
|
|
let mut first_digit = 0;
|
|
let mut second_digit = 0;
|
|
for (index, c) in line.chars().enumerate() {
|
|
if let Some(digit) = digit_for_char(line, index, c) {
|
|
first_digit = digit;
|
|
break;
|
|
}
|
|
}
|
|
for (index, c) in line.chars().rev().enumerate() {
|
|
if let Some(digit) = digit_for_char(line, line.len() - index - 1, c) {
|
|
second_digit = digit;
|
|
break;
|
|
}
|
|
}
|
|
let num = first_digit * 10 + second_digit;
|
|
Some(num)
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_part_one() {
|
|
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
|
|
assert_eq!(result, Some(142));
|
|
}
|
|
|
|
#[test]
|
|
fn test_part_two() {
|
|
let result = part_two(&advent_of_code::template::read_file_part(
|
|
"examples", DAY, 2,
|
|
));
|
|
assert_eq!(result, Some(281));
|
|
}
|
|
}
|