2021 day16/rust: clean up

This commit is contained in:
Xiretza 2021-12-16 20:36:23 +01:00
parent f24e06da7d
commit 0220f88e27

View file

@ -7,7 +7,6 @@ use std::{
use nom::{ use nom::{
bits::complete as bits, bits::complete as bits,
combinator::flat_map,
multi::{many0, many_m_n}, multi::{many0, many_m_n},
}; };
use nom::{combinator::map, sequence::pair}; use nom::{combinator::map, sequence::pair};
@ -53,58 +52,64 @@ enum PacketType {
} }
impl PacketType { impl PacketType {
pub fn parse(input: Input) -> IResult<PacketType> { pub fn parse(i: Input) -> IResult<PacketType> {
flat_map(bits::take(3_usize), |type_id: u8| { let (i, operator) = map(bits::take(3_usize), |type_id: u8| {
move |i| match Operator::try_from(type_id) { Operator::try_from(type_id)
Ok(operator) => map(Self::operation_inner, |sub_packets| PacketType::Operation { })(i)?;
match operator {
Ok(operator) => map(Self::parse_sub_packets, |sub_packets| {
PacketType::Operation {
operator, operator,
sub_packets, sub_packets,
}
})(i), })(i),
Err(_) => map(Self::literal_inner, PacketType::Literal)(i), Err(_) => map(Self::parse_literal_value, PacketType::Literal)(i),
} }
})(input)
} }
fn operation_inner(i: Input) -> IResult<Vec<Packet>> { fn parse_sub_packets(i: Input) -> IResult<Vec<Packet>> {
enum LengthType { enum LengthType {
Bits(u16), Bits(usize),
Packets(u16), Packets(usize),
} }
flat_map( impl LengthType {
flat_map(bits::take(1_usize), |length_type_id: u8| { pub fn parse(i: Input) -> IResult<Self> {
move |i| match length_type_id { let (i, length_type_id) = bits::take(1_usize)(i)?;
match length_type_id {
0 => map(bits::take(15_usize), LengthType::Bits)(i), 0 => map(bits::take(15_usize), LengthType::Bits)(i),
1 => map(bits::take(11_usize), LengthType::Packets)(i), 1 => map(bits::take(11_usize), LengthType::Packets)(i),
_ => unreachable!(), _ => unreachable!(),
} }
}),
|length_type| {
move |i| match length_type {
LengthType::Packets(n) => {
many_m_n(usize::from(n), usize::from(n), Packet::parse)(i)
} }
LengthType::Bits(n) => { }
// map_parser(recognize(bits::take(n)), many1(Packet::parse))(i)
let extra_bytes_required = (usize::from(n) + i.1) / 8; let (i, length_type) = LengthType::parse(i)?;
let extra_bits_required = (usize::from(n) + i.1) % 8; match length_type {
LengthType::Packets(n) => many_m_n(n, n, Packet::parse)(i),
LengthType::Bits(n) => {
// manual implementation of something like the following:
// map_parser(recognize(bits::take(n)), many0(Packet::parse))(i)
let new_byte_offset = (n + i.1) / 8;
let new_bit_offset = (n + i.1) % 8;
let subpackets_input = (&i.0[..=new_byte_offset], i.1);
let (subpackets_end, subpackets) = many0(Packet::parse)(subpackets_input)?;
let new_input = (&i.0[new_byte_offset..], new_bit_offset);
assert_eq!(subpackets_end, new_input);
let subpackets_slice = (&i.0[..=extra_bytes_required], i.1);
let (subpackets_end, subpackets) = many0(Packet::parse)(subpackets_slice)?;
if subpackets_end.0.len() > 1 {
todo!()
}
Ok(( Ok((
(&i.0[extra_bytes_required..], extra_bits_required), new_input,
subpackets, subpackets,
)) ))
} }
} }
},
)(i)
} }
fn literal_inner(i: Input) -> IResult<usize> { fn parse_literal_value(i: Input) -> IResult<usize> {
fold_till( fold_till(
pair(bits::take(1_usize), bits::take(4_usize)), pair(bits::take(1_usize), bits::take(4_usize)),
|| 0, || 0,
@ -122,8 +127,8 @@ impl PacketType {
match self { match self {
Self::Literal(n) => *n, Self::Literal(n) => *n,
Self::Operation { Self::Operation {
ref operator, operator,
ref sub_packets, sub_packets,
} => operator.evaluate(sub_packets.iter().map(|p| p.typ.evaluate())), } => operator.evaluate(sub_packets.iter().map(|p| p.typ.evaluate())),
} }
} }