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::{
|
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())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue