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::{
bits::complete as bits,
combinator::flat_map,
multi::{many0, many_m_n},
};
use nom::{combinator::map, sequence::pair};
@ -53,58 +52,64 @@ enum PacketType {
}
impl PacketType {
pub fn parse(input: Input) -> IResult<PacketType> {
flat_map(bits::take(3_usize), |type_id: u8| {
move |i| match Operator::try_from(type_id) {
Ok(operator) => map(Self::operation_inner, |sub_packets| PacketType::Operation {
pub fn parse(i: Input) -> IResult<PacketType> {
let (i, operator) = map(bits::take(3_usize), |type_id: u8| {
Operator::try_from(type_id)
})(i)?;
match operator {
Ok(operator) => map(Self::parse_sub_packets, |sub_packets| {
PacketType::Operation {
operator,
sub_packets,
})(i),
Err(_) => map(Self::literal_inner, PacketType::Literal)(i),
}
})(input)
}
})(i),
Err(_) => map(Self::parse_literal_value, PacketType::Literal)(i),
}
}
fn operation_inner(i: Input) -> IResult<Vec<Packet>> {
fn parse_sub_packets(i: Input) -> IResult<Vec<Packet>> {
enum LengthType {
Bits(u16),
Packets(u16),
Bits(usize),
Packets(usize),
}
flat_map(
flat_map(bits::take(1_usize), |length_type_id: u8| {
move |i| match length_type_id {
impl LengthType {
pub fn parse(i: Input) -> IResult<Self> {
let (i, length_type_id) = bits::take(1_usize)(i)?;
match length_type_id {
0 => map(bits::take(15_usize), LengthType::Bits)(i),
1 => map(bits::take(11_usize), LengthType::Packets)(i),
_ => 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 extra_bits_required = (usize::from(n) + i.1) % 8;
}
}
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((
(&i.0[extra_bytes_required..], extra_bits_required),
subpackets,
))
}
}
},
)(i)
let (i, length_type) = LengthType::parse(i)?;
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);
Ok((
new_input,
subpackets,
))
}
}
}
fn literal_inner(i: Input) -> IResult<usize> {
fn parse_literal_value(i: Input) -> IResult<usize> {
fold_till(
pair(bits::take(1_usize), bits::take(4_usize)),
|| 0,
@ -122,8 +127,8 @@ impl PacketType {
match self {
Self::Literal(n) => *n,
Self::Operation {
ref operator,
ref sub_packets,
operator,
sub_packets,
} => operator.evaluate(sub_packets.iter().map(|p| p.typ.evaluate())),
}
}