aoc-2021-rust

git clone https://git.sinitax.com/sinitax/aoc-2021-rust
Log | Files | Refs | README | sfeed.txt

commit 3dbffcd9e45cb9f629131725bf5ad2e3b2b8fb47
parent dd2922f82a453544355fe683e3bd66bc0c21b4ee
Author: Louis Burda <quent.burda@gmail.com>
Date:   Sat, 15 Apr 2023 01:32:23 -0400

[Day 16] Use enums fields

Diffstat:
Msrc/16/src/main.rs | 146+++++++++++++++++++++++++++++++++----------------------------------------------
1 file changed, 60 insertions(+), 86 deletions(-)

diff --git a/src/16/src/main.rs b/src/16/src/main.rs @@ -1,6 +1,18 @@ -use std::mem::ManuallyDrop; +enum PacketSizeType { + Count(usize), + Len(usize) +} + +struct LiteralPacket { + val: usize +} -#[derive(PartialEq,Eq,Copy,Clone,num_derive::FromPrimitive)] +struct OperatorPacket { + subsz: PacketSizeType, + sub: Vec<usize> +} + +#[derive(Copy,Clone,PartialEq,num_derive::FromPrimitive)] enum PacketType { Sum = 0, Product = 1, @@ -12,51 +24,15 @@ enum PacketType { EqualTo = 7 } -#[derive(PartialEq,Eq,Clone)] -enum PacketSizeType { - Count, - Len -} - -#[derive(Clone)] -struct LiteralPacket { - val: usize -} - -#[derive(Clone,Copy)] -union PacketSize { - cnt: usize, - len: usize -} - -#[derive(Clone)] -struct OperatorPacket { - sztype: PacketSizeType, - size: PacketSize, - sub: Vec<usize> -} - -union PacketUnion { - lit: ManuallyDrop<LiteralPacket>, - op: ManuallyDrop<OperatorPacket> +enum PacketClass { + Literal(LiteralPacket), + Operator(OperatorPacket) } struct Packet { ver: u8, typ: PacketType, - u: PacketUnion, -} - -impl Clone for Packet { - fn clone(&self) -> Self { - let pkt_u: PacketUnion; - if self.typ == PacketType::Literal { - pkt_u = PacketUnion { lit: unsafe { self.u.lit.clone() } }; - } else { - pkt_u = PacketUnion { op: unsafe { self.u.op.clone() } }; - } - return Packet { ver: self.ver, typ: self.typ, u: pkt_u }; - } + c: PacketClass } struct ParseState { @@ -80,8 +56,8 @@ fn decode_packet(bitstr: &str) -> (Packet, usize) { aoc::debugln!("{}", bitstr); let pver = u8::from_str_radix(&bitstr[0..3], 2).unwrap(); let ptype_val = u8::from_str_radix(&bitstr[3..6], 2).unwrap(); - let pu: PacketUnion; let mut cnt: usize = 0; + let pc : PacketClass; let ptype: PacketType = num::FromPrimitive::from_u8(ptype_val).unwrap(); if ptype == PacketType::Literal { let mut imm: usize = 0; @@ -92,27 +68,22 @@ fn decode_packet(bitstr: &str) -> (Packet, usize) { break; } } - let lit = ManuallyDrop::new(LiteralPacket { val: imm }); - pu = PacketUnion { lit }; + pc = PacketClass::Literal(LiteralPacket { val: imm }); } else { let szbit = bitstr[6..].chars().next().unwrap(); - let sztype: PacketSizeType; - let size: PacketSize; + let subsz: PacketSizeType; if szbit == '1' { - sztype = PacketSizeType::Count; - let imm = usize::from_str_radix(&bitstr[7..7+11], 2).unwrap(); - size = PacketSize { cnt: imm }; + let val = usize::from_str_radix(&bitstr[7..7+11], 2).unwrap(); + subsz = PacketSizeType::Count(val); cnt = 18; } else { - sztype = PacketSizeType::Len; - let imm = usize::from_str_radix(&bitstr[7..7+15], 2).unwrap(); - size = PacketSize { len: imm }; + let val = usize::from_str_radix(&bitstr[7..7+15], 2).unwrap(); + subsz = PacketSizeType::Len(val); cnt = 22; } - let op = ManuallyDrop::new(OperatorPacket { sztype, size, sub: Vec::new() }); - pu = PacketUnion { op }; + pc = PacketClass::Operator(OperatorPacket { subsz, sub: Vec::new() }); } - return (Packet { ver: pver, typ: ptype, u: pu }, cnt); + return (Packet { ver: pver, typ: ptype, c: pc }, cnt); } fn decode_packets(input: &str) -> Vec<Packet> { @@ -124,16 +95,16 @@ fn decode_packets(input: &str) -> Vec<Packet> { while !stack.is_empty() || pos + 8 <= bits.len() { if !stack.is_empty() { let state = stack.last_mut().unwrap(); - let op = unsafe { &*packets.get_mut(state.pkt).unwrap().u.op }; - let done = op.sztype == PacketSizeType::Count - && state.idx >= unsafe { op.size.cnt } - || op.sztype == PacketSizeType::Len - && pos - state.start >= unsafe { op.size.len }; + let pkt = packets.get_mut(state.pkt).unwrap(); + let op = match &pkt.c { + PacketClass::Operator(op) => op, + PacketClass::Literal(_) => { unreachable!(); } + }; + let done = match op.subsz { + PacketSizeType::Len(len) => pos - state.start >= len, + PacketSizeType::Count(cnt) => state.idx >= cnt + }; if done { - assert!(op.sztype == PacketSizeType::Count - && state.idx == unsafe { op.size.cnt } - || op.sztype == PacketSizeType::Len - && pos - state.start == unsafe { op.size.len }); stack.pop(); continue; } @@ -155,8 +126,10 @@ fn decode_packets(input: &str) -> Vec<Packet> { * soon as this state is at the top of the stack again */ state.idx += 1; let pkt = packets.get_mut(state.pkt).unwrap(); - assert!(pkt.typ != PacketType::Literal); - let op = unsafe { &mut pkt.u.op }; + let op = match &mut pkt.c { + PacketClass::Literal(_) => { unreachable!(); }, + PacketClass::Operator(op) => op + }; op.sub.push(pkt_idx); } @@ -191,27 +164,28 @@ fn eval_packets(packets: &Vec<Packet>) -> usize { while !stack.is_empty() { let top = stack.last().unwrap(); let pkt = packets.get(top.pkt).unwrap(); - aoc::debugln!("packet {}", pkt.typ as u8); - if pkt.typ == PacketType::Literal { - stack.pop(); - assert!(!stack.is_empty()); - let top = stack.last_mut().unwrap(); - top.ins.push(unsafe { pkt.u.lit.val }); - } else { - let op = unsafe { &pkt.u.op }; - let len = op.sub.len(); - let idx = top.ins.len(); - aoc::debugln!("=> op {} {}", idx, len); - assert!(len != 0); - if idx < len { - let child = *op.sub.get(idx).unwrap(); - stack.push(EvalState { pkt: child, ins: Vec::new() }); - } else { - let res = eval_packet(pkt.typ, &top.ins); + match &pkt.c { + PacketClass::Literal(lit) => { stack.pop(); - if stack.is_empty() { return res; } + assert!(!stack.is_empty()); let top = stack.last_mut().unwrap(); - top.ins.push(res); + top.ins.push(lit.val); + }, + PacketClass::Operator(op) => { + let len = op.sub.len(); + let idx = top.ins.len(); + aoc::debugln!("=> op {} {}", idx, len); + assert!(len != 0); + if idx < len { + let child = *op.sub.get(idx).unwrap(); + stack.push(EvalState { pkt: child, ins: Vec::new() }); + } else { + let res = eval_packet(pkt.typ, &top.ins); + stack.pop(); + if stack.is_empty() { return res; } + let top = stack.last_mut().unwrap(); + top.ins.push(res); + } } } }