Implement another approach for day 1

This commit is contained in:
2023-12-01 20:55:29 +01:00
parent a3c6a7f80e
commit 93af7971e4

View File

@@ -1,6 +1,3 @@
fn main() {
let input = std::fs::read_to_string("./input").unwrap();
#[derive(Debug)] #[derive(Debug)]
struct FirstLast { struct FirstLast {
first: Option<u32>, first: Option<u32>,
@@ -31,7 +28,8 @@ fn main() {
struct SpelledOutNumber(u32); struct SpelledOutNumber(u32);
impl SpelledOutNumber { impl SpelledOutNumber {
fn parse(value: &str) -> Option<Self> { fn parse(value: &[char]) -> Option<Self> {
let value: String = value.into_iter().collect();
if value.starts_with("one") { if value.starts_with("one") {
Some(Self(1)) Some(Self(1))
} else if value.starts_with("two") { } else if value.starts_with("two") {
@@ -56,7 +54,13 @@ fn main() {
} }
} }
let out: u32 = input fn main() {
let input = std::fs::read_to_string("./input").unwrap();
let approaches: Vec<u32> = vec![
// go through the string one by one, check the value at that position and record it into
// a `FirstLast` recorder that holds state
input
.lines() .lines()
.map(|line| { .map(|line| {
let line: Vec<char> = line.chars().collect(); let line: Vec<char> = line.chars().collect();
@@ -66,8 +70,7 @@ fn main() {
if let Some(digit) = c.to_digit(10) { if let Some(digit) = c.to_digit(10) {
recorder.record(digit) recorder.record(digit)
} else { } else {
let rest = &line[i..].iter().collect::<String>(); if let Some(digit) = SpelledOutNumber::parse(&line[i..]) {
if let Some(digit) = SpelledOutNumber::parse(rest.as_str()) {
recorder.record(digit.0) recorder.record(digit.0)
} }
} }
@@ -75,7 +78,60 @@ fn main() {
recorder recorder
}) })
.map(FirstLast::value) .map(FirstLast::value)
.sum(); .sum(),
//
println!("{out}"); // go through the string one by one, transform it into an array of digits and go from there
// i prefer this approach, as there is no stateful iteration
input
.lines()
.map(|line| line.chars().collect::<Vec<char>>())
.map(|line| {
(0..line.len())
.map(move |pos| {
if let Some(digit) = line[pos].to_digit(10) {
Some(digit)
} else {
SpelledOutNumber::parse(&line[pos..line.len()]).map(|s| s.0)
}
})
.filter_map(|e| e)
.collect::<Vec<u32>>()
})
// peculiar: if there is only one digit, use it for both the tenths digit and and ones digit
.map(|result| (result[0], *result.last().unwrap_or(&result[0])))
.map(|(d1, d2)| d1 * 10 + d2)
.sum(),
];
enum Acc {
Init,
Some(u32),
}
impl Acc {
fn unwrap(self) -> u32 {
match self {
Self::Init => panic!("Accumulator did not contain a number"),
Self::Some(val) => val,
}
}
}
// check that all approaches result in the same result
let result = approaches
.iter()
// try_reduce would be nicer here
.try_fold(Acc::Init, |acc, value| {
if let Acc::Some(acc) = acc {
if acc != *value {
return Err("approaches give different results");
}
};
Ok(Acc::Some(*value))
})
.unwrap() // check that there were no different results
.unwrap() // check that there were results at all (cannot fail)
;
println!("{result}");
} }