Compare commits
No commits in common. "0220f88e27bbd6bcb4f3a87141e45648f1051444" and "f41e7a76eacfc52de9a7ce9a7c16de03e0779b9b" have entirely different histories.
0220f88e27
...
f41e7a76ea
5 changed files with 0 additions and 257 deletions
|
@ -1,2 +0,0 @@
|
||||||
904
|
|
||||||
200476472872
|
|
|
@ -1 +0,0 @@
|
||||||
20546C8802538E136091C1802689BCD7DA45948D319D1B100747A009C97696E8B4ABFCA6AB8F4F26C401964A6271C80F802D392C01CEDDCE6E5CB829802F600A00021B14E34C361006E0AC418BB2CA6800BE4599BB6A73507002A52BEEB14D201802F600849E64D3369D37C74100866785B3D0ADFD8E601E5EB9DE2366D93ECB8B040142CB8ACE07CCB5CF34CA89380410B6134CE6FEF104A2B200243396976A00401A45004313D68435DBDDDA61CE6428C01491AEBF0C7E580AE00CCC401B86514216880370EE3443D2013DF003750004361343D88800084C4C8B116A679018300740010C8571BA32080350DA0D42800043A3044189AE0174B314D76E1F3ACF3BDAE3EE7298FF134002EF9DBCD0644127E3CAE7FCBA9A80393544F9A927C973DF1A500965A5CEA94C4DDA5658B94C6C3002A798A629CF21280532BAB4F4C7271E45EE6E71D8143A9BC7948804AB94D1D6006AC200EC1E8A10C00010985316A35C3620061E641644D661A4C012993E99208FC60097802F28F528F738606008CA47205400814C89CC8890064D400AB4BE0A66F2BF253E73AE8401424A7BFB16C0037E06CE0641E0013B08010A8930CE2B980351161DC3730066274188B020054A5E16965940057895ADEB5BF56A635ADE2354191D70566273A6F5B078266008D8022200D46E8291C4401A8CF0CE33CEDE55E9F9802BA00B4BD44A5EA2D10CC00B40316800BAE1003580A6D6026F00090E50024007C9500258068850035C00A4012ED8040B400D71002AF500284009700226336CA4980471D655E25D4650888023AB00525CAE5CBA5E428600BE003993778CB4732996E9887AE3F311C291004BD37517C0041E780A7808802AF8C1C00D0CDBE4ACAD69B3B004E13BDF23CAE7368C9F62448F64546008E0034F3720192A67AD9254917454200DCE801C99ADF182575BBAACAC7F8580
|
|
|
@ -1,9 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "day16_rs"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
nom = "7.1.0"
|
|
|
@ -1,204 +0,0 @@
|
||||||
#![warn(clippy::pedantic)]
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
io::{stdin, Read},
|
|
||||||
ops::ControlFlow,
|
|
||||||
};
|
|
||||||
|
|
||||||
use nom::{
|
|
||||||
bits::complete as bits,
|
|
||||||
multi::{many0, many_m_n},
|
|
||||||
};
|
|
||||||
use nom::{combinator::map, sequence::pair};
|
|
||||||
use parsers::fold_till;
|
|
||||||
|
|
||||||
mod parsers;
|
|
||||||
|
|
||||||
type Input<'a> = (&'a [u8], usize);
|
|
||||||
type IResult<'a, T> = nom::IResult<Input<'a>, T>;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
struct Packet {
|
|
||||||
version: u8,
|
|
||||||
typ: PacketType,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Packet {
|
|
||||||
pub fn parse(i: Input) -> IResult<Packet> {
|
|
||||||
map(
|
|
||||||
pair(bits::take(3_usize), PacketType::parse),
|
|
||||||
|(version, typ)| Packet { version, typ },
|
|
||||||
)(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn version_sum(&self) -> usize {
|
|
||||||
usize::from(self.version)
|
|
||||||
+ match self.typ {
|
|
||||||
PacketType::Literal(_) => 0,
|
|
||||||
PacketType::Operation {
|
|
||||||
ref sub_packets, ..
|
|
||||||
} => sub_packets.iter().map(Packet::version_sum).sum(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
enum PacketType {
|
|
||||||
Literal(usize),
|
|
||||||
Operation {
|
|
||||||
operator: Operator,
|
|
||||||
sub_packets: Vec<Packet>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PacketType {
|
|
||||||
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::parse_literal_value, PacketType::Literal)(i),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_sub_packets(i: Input) -> IResult<Vec<Packet>> {
|
|
||||||
enum LengthType {
|
|
||||||
Bits(usize),
|
|
||||||
Packets(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
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!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 parse_literal_value(i: Input) -> IResult<usize> {
|
|
||||||
fold_till(
|
|
||||||
pair(bits::take(1_usize), bits::take(4_usize)),
|
|
||||||
|| 0,
|
|
||||||
|acc, (marker, bits): (u8, usize)| {
|
|
||||||
(if marker == 1 {
|
|
||||||
ControlFlow::Continue
|
|
||||||
} else {
|
|
||||||
ControlFlow::Break
|
|
||||||
})((acc << 4) | bits)
|
|
||||||
},
|
|
||||||
)(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn evaluate(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
Self::Literal(n) => *n,
|
|
||||||
Self::Operation {
|
|
||||||
operator,
|
|
||||||
sub_packets,
|
|
||||||
} => operator.evaluate(sub_packets.iter().map(|p| p.typ.evaluate())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
||||||
enum Operator {
|
|
||||||
Sum,
|
|
||||||
Product,
|
|
||||||
Minimum,
|
|
||||||
Maximum,
|
|
||||||
GreaterThan,
|
|
||||||
LessThan,
|
|
||||||
EqualTo,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Operator {
|
|
||||||
pub fn evaluate(self, mut operands: impl Iterator<Item = usize>) -> usize {
|
|
||||||
match self {
|
|
||||||
Self::Sum => operands.sum(),
|
|
||||||
Self::Product => operands.product(),
|
|
||||||
Self::Minimum => operands.min().unwrap(),
|
|
||||||
Self::Maximum => operands.max().unwrap(),
|
|
||||||
Self::GreaterThan => usize::from(operands.next().unwrap() > operands.next().unwrap()),
|
|
||||||
Self::LessThan => usize::from(operands.next().unwrap() < operands.next().unwrap()),
|
|
||||||
Self::EqualTo => usize::from(operands.next().unwrap() == operands.next().unwrap()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<u8> for Operator {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
|
||||||
match value {
|
|
||||||
0 => Ok(Self::Sum),
|
|
||||||
1 => Ok(Self::Product),
|
|
||||||
2 => Ok(Self::Minimum),
|
|
||||||
3 => Ok(Self::Maximum),
|
|
||||||
5 => Ok(Self::GreaterThan),
|
|
||||||
6 => Ok(Self::LessThan),
|
|
||||||
7 => Ok(Self::EqualTo),
|
|
||||||
_ => Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let bytes: Vec<u8> = stdin()
|
|
||||||
.lock()
|
|
||||||
.bytes()
|
|
||||||
.filter_map(|c| char::from(c.unwrap()).to_digit(16))
|
|
||||||
.map(|c| {
|
|
||||||
#[allow(clippy::cast_possible_truncation)] // a hex digit always fits in a u8
|
|
||||||
let c = c as u8;
|
|
||||||
c
|
|
||||||
})
|
|
||||||
.scan(None, |prev, n| {
|
|
||||||
Some(match *prev {
|
|
||||||
Some(i) => {
|
|
||||||
*prev = None;
|
|
||||||
Some(i | n)
|
|
||||||
}
|
|
||||||
None => prev.replace(n << 4),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.flatten()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let packet = Packet::parse((&bytes, 0)).unwrap().1;
|
|
||||||
println!("{}", packet.version_sum());
|
|
||||||
println!("{}", packet.typ.evaluate());
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
use std::ops::ControlFlow;
|
|
||||||
|
|
||||||
use nom::{
|
|
||||||
error::{ErrorKind, ParseError},
|
|
||||||
Err, InputLength, Parser,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn fold_till<I, O, E, St, P, F, G>(
|
|
||||||
mut p: P,
|
|
||||||
mut init: F,
|
|
||||||
mut acc: G,
|
|
||||||
) -> impl FnMut(I) -> nom::IResult<I, St, E>
|
|
||||||
where
|
|
||||||
I: InputLength,
|
|
||||||
E: ParseError<I>,
|
|
||||||
P: Parser<I, O, E>,
|
|
||||||
F: FnMut() -> St,
|
|
||||||
G: FnMut(St, O) -> ControlFlow<St, St>,
|
|
||||||
{
|
|
||||||
move |i| {
|
|
||||||
let mut res = init();
|
|
||||||
let mut input = i;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let len = input.input_len();
|
|
||||||
let (i, o) = p.parse(input)?;
|
|
||||||
|
|
||||||
if i.input_len() == len {
|
|
||||||
return Err(Err::Error(E::from_error_kind(i, ErrorKind::Many0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
match acc(res, o) {
|
|
||||||
ControlFlow::Continue(next) => {
|
|
||||||
res = next;
|
|
||||||
input = i;
|
|
||||||
}
|
|
||||||
ControlFlow::Break(res) => return Ok((i, res)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue