feat: solve day 16 part 1 & 2
This commit is contained in:
parent
b0fdf15e92
commit
e306f40e3a
1
input/16.txt
Normal file
1
input/16.txt
Normal file
@ -0,0 +1 @@
|
||||
A20D790042F1274011955491808B802F1C60B20030327AF2CC248AA800E7CDD726F3D78F4966F571A300BA54D668E2519249265160803EA9DE562A1801204ACE53C954ACE53C94C659BDF318FD1366EF44D96EB11005FB39154E0068A7C3A6B379646C80348A0055E6642B332109B8D6F0F12980452C9D322B28012EC72D51B300426CF70017996DE6C2B2C70C01A04B67B9F9EC8DAFE679D0992A80380104065FA8012805BD380120051E380146006380142004A00E920034C0801CA007B0099420053007144016E28018800CCC8CBB5FE79A3D91E1DC9FB151A1006CC0188970D6109803B1D61344320042615C198C2A014C589D00943096B3CCC081009173D015B004C401C8E10421E8002110BA18C193004A52257E0094BCE1ABB94C2C9005112DFAA5E80292B405927020106BC01494DFA6E329BF4DD273B69E233DB04C435BEF7A0CC00CFCDF31DC6AD20A3002A498CC01D00042229479890200E4438A91700010F88F0EA251802D33FE976802538EF38E2401B84CA05004833529CD2A5BD9DDAC566009CC33E8024200CC528E71F40010A8DF0C61D8002B5076719A5D418034891895CFD320730F739A119CB2EA0072D25E870EA465E189FDC1126AF4B91100A03600A0803713E2FC7D00043A25C3B8A12F89D2E6440242489A7802400086C788FB09C0010C8BB132309005A1400D2CBE7E7F2F9F9F4BB83803B25286DFE628E129EBCB7483C8802F3D0A2542E3004AC0169BD944AFF263361F1B48010496089807100BA54A66675769B1787D230C621EF8B9007893F058A009AE4ED7A5BBDBE05262CEC0002FC7C20082622E0020D0D66A2D04021D5003ED3D396E19A1149054FCA3586BD00020129B0037300042E0CC1184C000874368F70A251D840239798AC8DC9A56F7C6C0E0728015294D9290030B226938A928D0
|
256
src/day16.rs
Normal file
256
src/day16.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user