2021 day16/rust: clean up
This commit is contained in:
parent
f24e06da7d
commit
0220f88e27
1 changed files with 46 additions and 41 deletions
|
@ -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())),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue