mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 12:50:32 +01:00
Implementation day 16
Not clean but it works.
This commit is contained in:
@@ -7,7 +7,7 @@ use criterion::criterion_main;
|
||||
use criterion::BenchmarkId;
|
||||
use criterion::Criterion;
|
||||
|
||||
const DAYS_IMPLEMENTED: usize = 15;
|
||||
const DAYS_IMPLEMENTED: usize = 16;
|
||||
|
||||
fn read_input(day: usize) -> Vec<u8> {
|
||||
let input_path = format!("inputs/{:02}.txt", day);
|
||||
|
||||
1
2021/inputs/16.txt
Normal file
1
2021/inputs/16.txt
Normal file
@@ -0,0 +1 @@
|
||||
620D49005AD2245800D0C9E72BD279CAFB0016B1FA2B1802DC00D0CC611A47FCE2A4ACE1DD144BFABBFACA002FB2C6F33DFF4A0C0119B169B013005F003720004263644384800087C3B8B51C26B449130802D1A0068A5BD7D49DE793A48B5400D8293B1F95C5A3005257B880F5802A00084C788AD0440010F8490F608CACE034401AB4D0F5802726B3392EE2199628CEA007001884005C92015CC8051800130EC0468A01042803B8300D8E200788018C027890088CE0049006028012AB00342A0060801B2EBE400424933980453EFB2ABB36032274C026E4976001237D964FF736AFB56F254CB84CDF136C1007E7EB42298FE713749F973F7283005656F902A004067CD27CC1C00D9CB5FDD4D0014348010C8331C21710021304638C513006E234308B060094BEB76CE3966AA007C6588A5670DC3754395485007A718A7F149CA2DD3B6E7B777800118E7B59C0ECF5AE5D3B6CB1496BAE53B7ADD78C013C00CD2629BF5371D1D4C537EA6E3A3E95A3E180592AC7246B34032CF92804001A1CCF9BA521782ECBD69A98648BC18025800F8C9C37C827CA7BEFB31EADF0AE801BA42B87935B8EF976194EEC426AAF640168CECAF84BC004AE7D1673A6A600B4AB65802D230D35CF81B803D3775683F3A3860087802132FB32F322C92A4C402524F2DE006E8000854378F710C0010D8F30FE224AE428C015E00D40401987F06E3600021D0CE3EC228DA000574E4C3080182931E936E953B200BF656E15400D3496E4A725B92998027C00A84EEEE6B347D30BE60094E537AA73A1D600B880371AA36C3200043235C4C866C018E4963B7E7AA2B379918C639F1550086064BB148BA499EC731004E1AC966BDBC7646600C080370822AC4C1007E38C428BE0008741689D0ECC01197CF216EA16802D3748FE91B25CAF6D5F11C463004E4FD08FAF381F6004D3232CC93E7715B463F780
|
||||
@@ -1,9 +1,245 @@
|
||||
use std::io::Read;
|
||||
|
||||
pub fn part1(_input: &mut dyn Read) -> String {
|
||||
todo!()
|
||||
use nom::bits::complete::tag;
|
||||
use nom::bits::complete::take;
|
||||
use nom::branch::alt;
|
||||
use nom::combinator::map;
|
||||
use nom::multi::count;
|
||||
use nom::sequence::preceded;
|
||||
use nom::sequence::tuple;
|
||||
use nom::IResult;
|
||||
|
||||
type Input<'a> = (&'a [u8], usize);
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
enum Contents {
|
||||
Literal(Vec<u8>),
|
||||
Operator(u8, Vec<Packet>),
|
||||
}
|
||||
|
||||
pub fn part2(_input: &mut dyn Read) -> String {
|
||||
todo!()
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
struct Packet {
|
||||
version: u8,
|
||||
contents: Contents,
|
||||
}
|
||||
|
||||
impl Packet {
|
||||
pub fn version_sum(&self) -> u32 {
|
||||
match &self.contents {
|
||||
Contents::Literal(_) => self.version as u32,
|
||||
Contents::Operator(_, sub_packets) => {
|
||||
self.version as u32 + sub_packets.iter().map(Packet::version_sum).sum::<u32>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn value(&self) -> u64 {
|
||||
match &self.contents {
|
||||
Contents::Literal(chunks) => chunks
|
||||
.iter()
|
||||
.fold(0, |acc, &chunk| (acc << 4) | (chunk as u64)),
|
||||
Contents::Operator(0, sub_packets) => sub_packets.iter().map(Packet::value).sum(),
|
||||
Contents::Operator(1, sub_packets) => sub_packets.iter().map(Packet::value).product(),
|
||||
Contents::Operator(2, sub_packets) => {
|
||||
sub_packets.iter().map(Packet::value).min().unwrap()
|
||||
}
|
||||
Contents::Operator(3, sub_packets) => {
|
||||
sub_packets.iter().map(Packet::value).max().unwrap()
|
||||
}
|
||||
Contents::Operator(5, sub_packets) => {
|
||||
(sub_packets[0].value() > sub_packets[1].value()) as u64
|
||||
}
|
||||
Contents::Operator(6, sub_packets) => {
|
||||
(sub_packets[0].value() < sub_packets[1].value()) as u64
|
||||
}
|
||||
Contents::Operator(7, sub_packets) => {
|
||||
(sub_packets[0].value() == sub_packets[1].value()) as u64
|
||||
}
|
||||
unknown => panic!("unknown packet {:?}", unknown),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_literal(mut input: Input) -> IResult<Input, (usize, Contents)> {
|
||||
let mut contents = Vec::new();
|
||||
|
||||
loop {
|
||||
let (new_input, result) = take::<_, u8, usize, _>(5)(input)?;
|
||||
input = new_input;
|
||||
|
||||
contents.push(result & 0xF);
|
||||
|
||||
if (result & 0x10) == 0 {
|
||||
let len = 5 * contents.len();
|
||||
let contents = Contents::Literal(contents);
|
||||
|
||||
return Ok((input, (len, contents)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_operator_len(input: Input) -> IResult<Input, (usize, Vec<Packet>)> {
|
||||
const SIZE_LEN: usize = 15;
|
||||
|
||||
let (mut input, to_read) = take(SIZE_LEN)(input)?;
|
||||
|
||||
let mut read = 0;
|
||||
let mut packets = Vec::new();
|
||||
|
||||
while read < to_read {
|
||||
let (new_input, (len, packet)) = parse_packet(input)?;
|
||||
input = new_input;
|
||||
read += len;
|
||||
packets.push(packet);
|
||||
}
|
||||
|
||||
Ok((input, (to_read + SIZE_LEN, packets)))
|
||||
}
|
||||
|
||||
fn parse_operator_count(input: Input) -> IResult<Input, (usize, Vec<Packet>)> {
|
||||
const SIZE_LEN: usize = 11;
|
||||
|
||||
let (input, to_read) = take::<_, usize, _, _>(SIZE_LEN)(input)?;
|
||||
|
||||
let (input, packets) = count(parse_packet, to_read)(input)?;
|
||||
|
||||
let read_total = SIZE_LEN + packets.iter().map(|(len, _)| *len).sum::<usize>();
|
||||
|
||||
Ok((
|
||||
input,
|
||||
(
|
||||
read_total,
|
||||
packets.into_iter().map(|(_, packet)| packet).collect(),
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_packet(input: Input) -> IResult<Input, (usize, Packet)> {
|
||||
let parse_literal_packet = map(
|
||||
tuple((take(3usize), preceded(tag(4u8, 3usize), parse_literal))),
|
||||
|(version, (len, contents))| (len + 6, Packet { version, contents }),
|
||||
);
|
||||
|
||||
let parse_operator_len_packet = map(
|
||||
tuple((
|
||||
take(3usize),
|
||||
take(3usize),
|
||||
preceded(tag(0u8, 1usize), parse_operator_len),
|
||||
)),
|
||||
|(version, operator, (len, contents))| {
|
||||
(
|
||||
len + 7,
|
||||
Packet {
|
||||
version,
|
||||
contents: Contents::Operator(operator, contents),
|
||||
},
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
let parse_operator_count_packet = map(
|
||||
tuple((
|
||||
take(3usize),
|
||||
take(3usize),
|
||||
preceded(tag(1u8, 1usize), parse_operator_count),
|
||||
)),
|
||||
|(version, operator, (len, contents))| {
|
||||
(
|
||||
len + 7,
|
||||
Packet {
|
||||
version,
|
||||
contents: Contents::Operator(operator, contents),
|
||||
},
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
alt((
|
||||
parse_literal_packet,
|
||||
parse_operator_len_packet,
|
||||
parse_operator_count_packet,
|
||||
))(input)
|
||||
}
|
||||
|
||||
fn convert_hex(hex: &[u8]) -> Vec<u8> {
|
||||
hex.chunks_exact(2)
|
||||
.map(|chunk| u8::from_str_radix(std::str::from_utf8(chunk).unwrap(), 16).unwrap())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn part1(input: &mut dyn Read) -> String {
|
||||
let mut buffer = Vec::new();
|
||||
input.read_to_end(&mut buffer).unwrap();
|
||||
|
||||
let binary_data = convert_hex(&buffer);
|
||||
let (_, (_, packet)) = parse_packet((&binary_data, 0)).unwrap();
|
||||
|
||||
packet.version_sum().to_string()
|
||||
}
|
||||
|
||||
pub fn part2(input: &mut dyn Read) -> String {
|
||||
let mut buffer = Vec::new();
|
||||
input.read_to_end(&mut buffer).unwrap();
|
||||
|
||||
let binary_data = convert_hex(&buffer);
|
||||
let (_, (_, packet)) = parse_packet((&binary_data, 0)).unwrap();
|
||||
|
||||
packet.value().to_string()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::test_implementation;
|
||||
|
||||
use super::*;
|
||||
|
||||
const SAMPLE: &[&[u8]] = &[
|
||||
&*b"8A004A801A8002F478",
|
||||
&*b"620080001611562C8802118E34",
|
||||
&*b"C0015000016115A2E0802F182340",
|
||||
&*b"A0016C880162017C3686B18A3D4780",
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn sample_part1() {
|
||||
let answers = [16, 12, 23, 31];
|
||||
|
||||
for (&sample, answer) in SAMPLE.into_iter().zip(answers) {
|
||||
test_implementation(part1, sample, answer);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_literal() {
|
||||
let (_, (len, packet)) = parse_packet((&convert_hex(b"D2FE28"), 0)).unwrap();
|
||||
|
||||
assert_eq!(len, 21);
|
||||
assert_eq!(
|
||||
packet,
|
||||
Packet {
|
||||
version: 6,
|
||||
contents: Contents::Literal(vec![7, 14, 5])
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_operator_len() {
|
||||
let (_, (len, packet)) = parse_packet((&convert_hex(b"38006F45291200"), 0)).unwrap();
|
||||
|
||||
assert_eq!(len, 22 + 27);
|
||||
assert_eq!(packet.version, 1);
|
||||
|
||||
assert!(matches!(packet.contents, Contents::Operator(6, _)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_operator_count() {
|
||||
let (_, (len, packet)) = parse_packet((&convert_hex(b"EE00D40C823060"), 0)).unwrap();
|
||||
|
||||
assert_eq!(len, 7 + 11 + 33);
|
||||
assert_eq!(packet.version, 7);
|
||||
|
||||
assert!(matches!(packet.contents, Contents::Operator(3, _)));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user