1
0

feat: solve day 16 part 1 & 2

This commit is contained in:
Rokas Puzonas 2022-01-11 20:21:05 +02:00
parent b0fdf15e92
commit e306f40e3a
3 changed files with 260 additions and 0 deletions

1
input/16.txt Normal file
View File

@ -0,0 +1 @@
A20D790042F1274011955491808B802F1C60B20030327AF2CC248AA800E7CDD726F3D78F4966F571A300BA54D668E2519249265160803EA9DE562A1801204ACE53C954ACE53C94C659BDF318FD1366EF44D96EB11005FB39154E0068A7C3A6B379646C80348A0055E6642B332109B8D6F0F12980452C9D322B28012EC72D51B300426CF70017996DE6C2B2C70C01A04B67B9F9EC8DAFE679D0992A80380104065FA8012805BD380120051E380146006380142004A00E920034C0801CA007B0099420053007144016E28018800CCC8CBB5FE79A3D91E1DC9FB151A1006CC0188970D6109803B1D61344320042615C198C2A014C589D00943096B3CCC081009173D015B004C401C8E10421E8002110BA18C193004A52257E0094BCE1ABB94C2C9005112DFAA5E80292B405927020106BC01494DFA6E329BF4DD273B69E233DB04C435BEF7A0CC00CFCDF31DC6AD20A3002A498CC01D00042229479890200E4438A91700010F88F0EA251802D33FE976802538EF38E2401B84CA05004833529CD2A5BD9DDAC566009CC33E8024200CC528E71F40010A8DF0C61D8002B5076719A5D418034891895CFD320730F739A119CB2EA0072D25E870EA465E189FDC1126AF4B91100A03600A0803713E2FC7D00043A25C3B8A12F89D2E6440242489A7802400086C788FB09C0010C8BB132309005A1400D2CBE7E7F2F9F9F4BB83803B25286DFE628E129EBCB7483C8802F3D0A2542E3004AC0169BD944AFF263361F1B48010496089807100BA54A66675769B1787D230C621EF8B9007893F058A009AE4ED7A5BBDBE05262CEC0002FC7C20082622E0020D0D66A2D04021D5003ED3D396E19A1149054FCA3586BD00020129B0037300042E0CC1184C000874368F70A251D840239798AC8DC9A56F7C6C0E0728015294D9290030B226938A928D0

256
src/day16.rs Normal file
View File

@ -0,0 +1,256 @@
pub enum PacketBody {
Literal(u64),
Operator(Vec<Packet>)
}
pub struct Packet {
version: u8,
r#type: u8,
body: PacketBody
}
fn to_bits(hex: &str) -> String {
let mut bits = String::new();
for c in hex.bytes() {
match c {
b'0'..=b'9' => bits.push_str(format!("{:0>4b}", c - b'0').as_str()),
b'A'..=b'F' => bits.push_str(format!("{:0>4b}", c - b'A' + 10).as_str()),
_ => ()
}
}
return bits;
}
fn parse_literal_body(bits_str: &str) -> (PacketBody, u32) {
let mut value_bits = String::new();
let mut cursor = 0;
let bytes = bits_str.as_bytes();
loop {
value_bits.push_str(&bits_str[cursor+1..cursor+5]);
if bytes[cursor] == b'0' { break; }
cursor += 5;
}
let value = u64::from_str_radix(&value_bits, 2).unwrap();
return (PacketBody::Literal(value), (cursor+5) as u32);
}
fn parse_operator_body(bits_str: &str) -> (PacketBody, u32) {
let mut size: usize = 0;
let mut packets = Vec::new();
let bytes = bits_str.as_bytes();
size += 1;
if bytes[0] == b'1' {
size += 11;
let count = u32::from_str_radix(&bits_str[1..12], 2).unwrap();
for _ in 0..count {
let (packet, s) = parse_packet(&bits_str[size..]);
packets.push(packet);
size += s as usize;
}
} else {
let total_size = u32::from_str_radix(&bits_str[1..16], 2).unwrap();
size += 15;
while ((size-16) as u32) < total_size {
let (packet, s) = parse_packet(&bits_str[size..]);
packets.push(packet);
size += s as usize;
}
}
return (PacketBody::Operator(packets), size as u32);
}
fn parse_packet(bits: &str) -> (Packet, u32) {
let r#type = u8::from_str_radix(&bits[3..6], 2).unwrap();
let (body, body_size) = match r#type {
4 => parse_literal_body(&bits[6..]),
_ => parse_operator_body(&bits[6..])
};
return (Packet {
version: u8::from_str_radix(&bits[0..3], 2).unwrap(),
r#type,
body
},
body_size + 6
);
}
pub fn parse_input(input: &str) -> Packet {
let (packet, _) = parse_packet(&to_bits(input));
return packet;
}
fn sum_packet_versions(packet: &Packet) -> u32 {
let mut sum: u32 = packet.version.into();
match &packet.body {
PacketBody::Operator(packets) => {
for sub_packet in packets {
sum += sum_packet_versions(sub_packet);
}
},
_ => ()
};
return sum;
}
pub fn part1(packet: &Packet) -> u32 {
sum_packet_versions(packet)
}
fn eval_sum_packets(packets: &[Packet]) -> u64 {
let mut sum = 0;
for packet in packets {
sum += eval_packet(packet);
}
return sum;
}
fn eval_product_packets(packets: &[Packet]) -> u64 {
let mut product = 1;
for packet in packets {
product *= eval_packet(packet);
}
return product;
}
fn eval_minimum_packets(packets: &[Packet]) -> u64 {
let mut min = u64::MAX;
for packet in packets {
min = min.min(eval_packet(packet));
}
return min;
}
fn eval_maximum_packets(packets: &[Packet]) -> u64 {
let mut max = 0;
for packet in packets {
max = max.max(eval_packet(packet));
}
return max;
}
fn eval_greater_packets(packets: &[Packet]) -> u64 {
let first_packet = packets.get(0).unwrap();
let second_packet = packets.get(1).unwrap();
if eval_packet(first_packet) > eval_packet(second_packet) { 1 } else { 0 }
}
fn eval_less_packets(packets: &[Packet]) -> u64 {
let first_packet = packets.get(0).unwrap();
let second_packet = packets.get(1).unwrap();
if eval_packet(first_packet) < eval_packet(second_packet) { 1 } else { 0 }
}
fn eval_equal_packets(packets: &[Packet]) -> u64 {
let first_packet = packets.get(0).unwrap();
let second_packet = packets.get(1).unwrap();
if eval_packet(first_packet) == eval_packet(second_packet) { 1 } else { 0 }
}
fn eval_packet(packet: &Packet) -> u64 {
match &packet.body {
PacketBody::Literal(value) => *value,
PacketBody::Operator(packets) => {
match packet.r#type {
0 => eval_sum_packets(packets),
1 => eval_product_packets(packets),
2 => eval_minimum_packets(packets),
3 => eval_maximum_packets(packets),
5 => eval_greater_packets(packets),
6 => eval_less_packets(packets),
7 => eval_equal_packets(packets),
_ => unreachable!()
}
}
}
}
pub fn part2(packet: &Packet) -> u64 {
eval_packet(packet)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn part1_example_1() {
let packet = parse_input("8A004A801A8002F478");
let result = part1(&packet);
assert_eq!(result, 16);
}
#[test]
fn part1_example_2() {
let packet = parse_input("620080001611562C8802118E34");
let result = part1(&packet);
assert_eq!(result, 12);
}
#[test]
fn part1_example_3() {
let packet = parse_input("C0015000016115A2E0802F182340");
let result = part1(&packet);
assert_eq!(result, 23);
}
#[test]
fn part1_example_4() {
let packet = parse_input("A0016C880162017C3686B18A3D4780");
let result = part1(&packet);
assert_eq!(result, 31);
}
#[test]
fn part2_example_1() {
let packet = parse_input("C200B40A82");
let result = part2(&packet);
assert_eq!(result, 3);
}
#[test]
fn part2_example_2() {
let packet = parse_input("04005AC33890");
let result = part2(&packet);
assert_eq!(result, 54);
}
#[test]
fn part2_example_3() {
let packet = parse_input("880086C3E88112");
let result = part2(&packet);
assert_eq!(result, 7);
}
#[test]
fn part2_example_4() {
let packet = parse_input("CE00C43D881120");
let result = part2(&packet);
assert_eq!(result, 9);
}
#[test]
fn part2_example_5() {
let packet = parse_input("D8005AC2A8F0");
let result = part2(&packet);
assert_eq!(result, 1);
}
#[test]
fn part2_example_6() {
let packet = parse_input("F600BC2D8F");
let result = part2(&packet);
assert_eq!(result, 0);
}
#[test]
fn part2_example_7() {
let packet = parse_input("9C005AC2F8F0");
let result = part2(&packet);
assert_eq!(result, 0);
}
#[test]
fn part2_example_8() {
let packet = parse_input("9C0141080250320F1802104A08");
let result = part2(&packet);
assert_eq!(result, 1);
}
}

View File

@ -13,6 +13,7 @@ mod day12;
mod day13;
mod day14;
mod day15;
mod day16;
use std::{env, process};
use std::fs::File;
@ -59,6 +60,8 @@ fn run(day: i32, part: i32, input_filename: &str) {
"14.2" => println!("{}", day14::part2(&day14::parse_input(&contents))),
"15.1" => println!("{}", day15::part1(&day15::parse_input(&contents))),
"15.2" => println!("{}", day15::part2(&mut day15::parse_input(&contents))),
"16.1" => println!("{}", day16::part1(&day16::parse_input(&contents))),
"16.2" => println!("{}", day16::part2(&day16::parse_input(&contents))),
_ => println!("Day {} part {} not found", day, part)
}
}