aoc-rs-2021/src/day_14/parsing.rs
Jan Christian Grünhage 403be5d4da implement day 14
2021-12-16 00:08:46 +01:00

70 lines
1.9 KiB
Rust

use yap::Tokens;
use crate::parsing::{newline, parse_n};
use super::{Input, Polymer, Rule, Rules};
pub fn parse_input(tokens: &mut impl Tokens<Item = char>) -> Option<Input> {
tokens.optional(|t| {
let polymer = parse_polymer(t);
let tag = newline(t) && newline(t);
let rules = parse_rules(t);
if let (Some(polymer), true, Some(rules)) = (polymer, tag, rules) {
Some(Input { polymer, rules })
} else {
None
}
})
}
pub fn parse_polymer(tokens: &mut impl Tokens<Item = char>) -> Option<Polymer> {
tokens.optional(|t| {
let polymer: String = t.many(|t| parse_element(t)).collect();
if polymer.len() >= 2 {
polymer.parse().ok()
} else {
None
}
})
}
pub fn parse_rule(tokens: &mut impl Tokens<Item = char>) -> Option<Rule> {
tokens.optional(|t| {
let neighbours = parse_neighbours(t);
let tag = t.tokens(" -> ".chars());
let separator = parse_element(t);
if let (Some(neighbours), true, Some(separator)) = (neighbours, tag, separator) {
let neighbours = (neighbours[0], neighbours[1]);
Some(Rule {
neighbours,
separator,
})
} else {
None
}
})
}
pub fn parse_neighbours(tokens: &mut impl Tokens<Item = char>) -> Option<[char; 2]> {
parse_n(tokens, |t| parse_element(t), |_| true)
}
pub fn parse_element(tokens: &mut impl Tokens<Item = char>) -> Option<char> {
tokens.optional(|t| {
if let Some(c) = t.next() {
if c.is_ascii_uppercase() {
return Some(c);
}
}
None
})
}
pub fn parse_rules(tokens: &mut impl Tokens<Item = char>) -> Option<Rules> {
tokens.optional(|t| {
let rules: Vec<Rule> = t.sep_by(|t| parse_rule(t), |t| newline(t)).collect();
rules.try_into().ok()
})
}