Skip to content

Commit

Permalink
Day 16
Browse files Browse the repository at this point in the history
  • Loading branch information
VictorKoenders committed Dec 16, 2021
1 parent 44c153c commit ac3c404
Show file tree
Hide file tree
Showing 4 changed files with 310 additions and 0 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ edition = "2021"
[dependencies]
bitvec = "0.22.3"
either = "1.6.1"
hex = "0.4.3"
1 change: 1 addition & 0 deletions input/day_16_input.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
C20D718021600ACDC372CD8DE7A057252A49C940239D68978F7970194EA7CCB310088760088803304A0AC1B100721EC298D3307440041CD8B8005D12DFD27CBEEF27D94A4E9B033006A45FE71D665ACC0259C689B1F99679F717003225900465800804E39CE38CE161007E52F1AEF5EE6EC33600BCC29CFFA3D8291006A92CA7E00B4A8F497E16A675EFB6B0058F2D0BD7AE1371DA34E730F66009443C00A566BFDBE643135FEDF321D000C6269EA66545899739ADEAF0EB6C3A200B6F40179DE31CB7B277392FA1C0A95F6E3983A100993801B800021B0722243D00042E0DC7383D332443004E463295176801F29EDDAA853DBB5508802859F2E9D2A9308924F9F31700AA4F39F720C733A669EC7356AC7D8E85C95E123799D4C44C0109C0AF00427E3CC678873F1E633C4020085E60D340109E3196023006040188C910A3A80021B1763FC620004321B4138E52D75A20096E4718D3E50016B19E0BA802325E858762D1802B28AD401A9880310E61041400043E2AC7E8A4800434DB24A384A4019401C92C154B43595B830002BC497ED9CC27CE686A6A43925B8A9CFFE3A9616E5793447004A4BBB749841500B26C5E6E306899C5B4C70924B77EF254B48688041CD004A726ED3FAECBDB2295AEBD984E08E0065C101812E006380126005A80124048CB010D4C03DC900E16A007200B98E00580091EE004B006902004B00410000AF00015933223100688010985116A311803D05E3CC4B300660BC7283C00081CF26491049F3D690E9802739661E00D400010A8B91F2118803310A2F43396699D533005E37E8023311A4BB9961524A4E2C027EC8C6F5952C2528B333FA4AD386C0A56F39C7DB77200C92801019E799E7B96EC6F8B7558C014977BD00480010D89D106240803518E31C4230052C01786F272FF354C8D4D437DF52BC2C300567066550A2A900427E0084C254739FB8E080111E0
301 changes: 301 additions & 0 deletions src/bin/day_16/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
type BitSlice<'a> = &'a bitvec::slice::BitSlice<bitvec::order::Msb0, u8>;

fn main() {
let input = Packet::new(include_str!("../../../input/day_16_input.txt"));

assert_eq!(16, dbg!(part_1(&Packet::new("8A004A801A8002F478"))));
assert_eq!(12, dbg!(part_1(&Packet::new("620080001611562C8802118E34"))));
assert_eq!(
23,
dbg!(part_1(&Packet::new("C0015000016115A2E0802F182340")))
);
assert_eq!(
31,
dbg!(part_1(&Packet::new("A0016C880162017C3686B18A3D4780")))
);
dbg!(part_1(&input));

assert_eq!(3, dbg!(part_2(&Packet::new("C200B40A82"))));
assert_eq!(54, dbg!(part_2(&Packet::new("04005AC33890"))));
assert_eq!(7, dbg!(part_2(&Packet::new("880086C3E88112"))));
assert_eq!(9, dbg!(part_2(&Packet::new("CE00C43D881120"))));
assert_eq!(1, dbg!(part_2(&Packet::new("D8005AC2A8F0"))));
assert_eq!(0, dbg!(part_2(&Packet::new("F600BC2D8F"))));
assert_eq!(0, dbg!(part_2(&Packet::new("9C005AC2F8F0"))));
assert_eq!(1, dbg!(part_2(&Packet::new("9C0141080250320F1802104A08"))));
dbg!(part_2(&input));
}

fn part_1(packet: &Packet) -> usize {
fn sum_version(packet: &Packet) -> usize {
packet.version as usize
+ match &packet.ty {
PacketType::Operator { children, .. } => children.iter().map(sum_version).sum(),
_ => 0,
}
}

sum_version(packet)
}

fn part_2(packet: &Packet) -> usize {
fn inner(packet: &Packet) -> usize {
match &packet.ty {
PacketType::Literal(lit) => *lit,
PacketType::Operator { ty, children } => {
let mut children = children.iter().map(inner);
match ty {
OperatorType::Sum => children.sum(),
OperatorType::Maximum => children.max().unwrap(),
OperatorType::Minimum => children.min().unwrap(),
OperatorType::Product => children.product(),
OperatorType::GreaterThan => {
let (first, second) = (children.next().unwrap(), children.next().unwrap());
if first > second {
1
} else {
0
}
}
OperatorType::LessThan => {
let (first, second) = (children.next().unwrap(), children.next().unwrap());
if first < second {
1
} else {
0
}
}
OperatorType::EqualTo => {
let (first, second) = (children.next().unwrap(), children.next().unwrap());
if first == second {
1
} else {
0
}
}
OperatorType::Unknown(op) => panic!("Unknown operator {}", op),
}
}
}
}

inner(packet)
}

#[derive(Clone, Debug, PartialEq)]
struct Packet {
pub version: u8,
pub ty: PacketType,
}

impl Packet {
fn new(input: &'static str) -> Self {
let decoded = hex::decode(input.trim()).unwrap();
let mut input = bitvec::view::BitView::view_bits(decoded.as_slice());
Self::decode(&mut input)
}

fn decode(input: &mut BitSlice) -> Self {
let version = take_u8(input, 3);
let ty = match take_u8(input, 3) {
4 => PacketType::literal(input),
x => {
let ty = OperatorType::new(x);
let children = Self::parse_children(input);
PacketType::Operator { ty, children }
}
};

Self { version, ty }
}

fn parse_children(input: &mut BitSlice) -> Vec<Packet> {
let mut children = Vec::new();
let (bit, remaining) = input.split_first().unwrap();
*input = remaining;
if *bit {
// next 11 bits are # of children
let num = take_usize(input, 11);
children.reserve_exact(num);
for _ in 0..num {
children.push(Packet::decode(input));
}
} else {
// next 15 bits are subslice len
let len = take_usize(input, 15);
let (mut slice, remaining) = input.split_at(len);
*input = remaining;
while !slice.is_empty() {
children.push(Packet::decode(&mut slice));
}
}
children
}
}

#[derive(Clone, Debug, PartialEq)]
enum PacketType {
Literal(usize),
Operator {
ty: OperatorType,
children: Vec<Packet>,
},
}

#[derive(Clone, Debug, PartialEq)]
enum OperatorType {
Sum,
Product,
Minimum,
Maximum,
GreaterThan,
LessThan,
EqualTo,
Unknown(u8),
}

impl OperatorType {
fn new(val: u8) -> Self {
match val {
0 => Self::Sum,
1 => Self::Product,
2 => Self::Minimum,
3 => Self::Maximum,
5 => Self::GreaterThan,
6 => Self::LessThan,
7 => Self::EqualTo,
val => Self::Unknown(val),
}
}
}

impl PacketType {
fn literal(slice: &mut BitSlice) -> Self {
let mut result = 0;
loop {
let (var, s) = slice.split_at(5);
*slice = s;

result = result << 4 | to_u8(&var[1..]) as usize;

if *var.first().unwrap() == false {
// if the first bit is 0, this is the last value
break;
}
}

Self::Literal(result)
}
}

fn take_u8(slice: &mut BitSlice, idx: usize) -> u8 {
let (var, remaining) = slice.split_at(idx);
*slice = remaining;
to_u8(var)
}

fn to_u8(slice: BitSlice) -> u8 {
let mut result = 0;
for bit in slice {
result = result << 1 | if *bit { 1 } else { 0 };
}
result
}

fn take_usize(slice: &mut BitSlice, idx: usize) -> usize {
let (var, remaining) = slice.split_at(idx);
*slice = remaining;
to_usize(var)
}

fn to_usize(slice: BitSlice) -> usize {
let mut result = 0;
for bit in slice {
result = result << 1 | if *bit { 1 } else { 0 };
}
result
}

#[test]
fn test_parse() {
fn lit(version: u8, val: usize) -> Packet {
Packet {
version,
ty: PacketType::Literal(val),
}
}
fn op(version: u8, ty: OperatorType, children: Vec<Packet>) -> Packet {
Packet {
version,
ty: PacketType::Operator { ty, children },
}
}

assert_eq!(Packet::new("D2FE28"), lit(6, 2021));
assert_eq!(
Packet::new("38006F45291200"),
op(1, OperatorType::LessThan, vec![lit(6, 10), lit(2, 20),])
);
assert_eq!(
Packet::new("EE00D40C823060"),
op(
7,
OperatorType::Maximum,
vec![lit(2, 1), lit(4, 2), lit(1, 3),]
)
);

assert_eq!(
Packet::new("8A004A801A8002F478"),
op(
4,
OperatorType::Minimum,
vec![op(
1,
OperatorType::Minimum,
vec![op(5, OperatorType::Minimum, vec![lit(6, 15)])]
)]
)
);

assert_eq!(
Packet::new("620080001611562C8802118E34"),
op(
3,
OperatorType::Sum,
vec![
op(0, OperatorType::Sum, vec![lit(0, 10), lit(5, 11)]),
op(1, OperatorType::Sum, vec![lit(0, 12), lit(3, 13)]),
]
)
);

assert_eq!(
Packet::new("C0015000016115A2E0802F182340"),
op(
6,
OperatorType::Sum,
vec![
op(0, OperatorType::Sum, vec![lit(0, 10), lit(6, 11)]),
op(4, OperatorType::Sum, vec![lit(7, 12), lit(0, 13)]),
]
)
);

assert_eq!(
Packet::new("A0016C880162017C3686B18A3D4780"),
op(
5,
OperatorType::Sum,
vec![op(
1,
OperatorType::Sum,
vec![op(
3,
OperatorType::Sum,
vec![lit(7, 6), lit(6, 6), lit(5, 12), lit(2, 15), lit(2, 15),]
)]
)]
)
);
}

0 comments on commit ac3c404

Please sign in to comment.