Skip to content

Instantly share code, notes, and snippets.

@koivunej
Last active December 2, 2023 15:50
Show Gist options
  • Save koivunej/cbc9274574da7273c2bb94be8544018e to your computer and use it in GitHub Desktop.
Save koivunej/cbc9274574da7273c2bb94be8544018e to your computer and use it in GitHub Desktop.
aoc 2023 day 01, spider "dfa"
fn main() {
let stdin = std::io::stdin();
let stdin = stdin.lock();
let mut phases = (Phase1::default(), Phase2::default());
ingest(stdin, &mut phases);
println!("{phases:?}");
}
trait Ingest {
fn ingest(&mut self, buf: &str);
}
#[derive(Default, Debug)]
struct Phase1(u64);
impl Ingest for Phase1 {
fn ingest(&mut self, buf: &str) {
let mut chars = buf
.char_indices()
.filter_map(|(i, ch)| {
if ch.is_digit(10) {
Some((i, ch as u8 - '0' as u8))
} else {
None
}
})
.fuse();
let first = chars.next();
let last = chars.last();
let val = [first, last]
.into_iter()
.filter_map(|x| x)
.cycle()
.take(2)
.fold(0u64, |acc, (_, digit)| acc * 10 + digit as u64);
self.0 += val;
}
}
#[derive(Default, Debug)]
struct Phase2(u64);
impl Ingest for Phase2 {
fn ingest(&mut self, mut buf: &str) {
let mut first = None;
let mut last = None;
'outer: while !buf.is_empty() {
let mut rem = buf.chars().peekable();
while let Some(next) = rem.next() {
let (consume_more, value) = match next {
'o' => ("ne", Some(1)),
't' => match rem.peek() {
Some('w') => ("wo", Some(2)),
Some('h') => ("hree", Some(3)),
_ => ("", None),
},
'f' => match rem.peek() {
Some('o') => ("our", Some(4)),
Some('i') => ("ive", Some(5)),
_ => ("", None),
},
's' => match rem.peek() {
Some('i') => ("ix", Some(6)),
Some('e') => ("even", Some(7)),
_ => ("", None),
},
'e' => ("ight", Some(8)),
'n' => ("ine", Some(9)),
// 'z' => ("ero", Some(0)),
x @ '0'..='9' => ("", Some(x as u8 - '0' as u8)),
_ => ("", None),
};
for ch in consume_more.chars() {
if rem.next() == Some(ch) {
// good
} else {
// println!("mismatch");
let mut rem = buf.chars();
rem.next();
buf = rem.as_str();
continue 'outer;
}
}
let value = value.map(|x| x as u64);
if first.is_none() {
first = value;
}
if value.is_some() {
last = value;
}
let mut rem = buf.chars();
rem.next();
// leave the last value unconsumed, so sevenine is 79
if !consume_more.is_empty() {
for _ in 0..(consume_more.len() - 1) {
rem.next().unwrap();
}
}
buf = rem.as_str();
continue 'outer;
}
}
let value = first.unwrap() * 10 + last.unwrap();
self.0 += value;
}
}
impl<A: Ingest, B: Ingest> Ingest for (A, B) {
fn ingest(&mut self, buf: &str) {
self.0.ingest(buf);
self.1.ingest(buf);
}
}
fn ingest(mut input: impl std::io::BufRead, phase: &mut impl Ingest) {
let mut buf = String::new();
loop {
buf.clear();
let read = input.read_line(&mut buf).unwrap();
if read == 0 {
break;
}
let buf = buf.trim();
phase.ingest(buf);
}
}
#[cfg(test)]
fn phase1(input: impl std::io::BufRead) -> u64 {
let mut phase = Phase1::default();
ingest(input, &mut phase);
phase.0
}
#[cfg(test)]
fn phase2(input: impl std::io::BufRead) -> u64 {
let mut phase = Phase2::default();
ingest(input, &mut phase);
phase.0
}
#[test]
fn example1() {
let input = "1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet";
assert_eq!(phase1(std::io::Cursor::new(input)), 142);
}
#[test]
fn example2() {
let input = "two1nine
eightwothree
abcone2threexyz
xtwone3four
4nineeightseven2
zoneight234
7pqrstsixteen";
assert_eq!(phase2(std::io::Cursor::new(input)), 281);
}
#[test]
fn reddit_hint() {
let input = "eighthree
sevenine";
assert_eq!(phase2(std::io::Cursor::new(input)), 83 + 79);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment