-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
44c153c
commit ac3c404
Showing
4 changed files
with
310 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,3 +8,4 @@ edition = "2021" | |
[dependencies] | ||
bitvec = "0.22.3" | ||
either = "1.6.1" | ||
hex = "0.4.3" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
C20D718021600ACDC372CD8DE7A057252A49C940239D68978F7970194EA7CCB310088760088803304A0AC1B100721EC298D3307440041CD8B8005D12DFD27CBEEF27D94A4E9B033006A45FE71D665ACC0259C689B1F99679F717003225900465800804E39CE38CE161007E52F1AEF5EE6EC33600BCC29CFFA3D8291006A92CA7E00B4A8F497E16A675EFB6B0058F2D0BD7AE1371DA34E730F66009443C00A566BFDBE643135FEDF321D000C6269EA66545899739ADEAF0EB6C3A200B6F40179DE31CB7B277392FA1C0A95F6E3983A100993801B800021B0722243D00042E0DC7383D332443004E463295176801F29EDDAA853DBB5508802859F2E9D2A9308924F9F31700AA4F39F720C733A669EC7356AC7D8E85C95E123799D4C44C0109C0AF00427E3CC678873F1E633C4020085E60D340109E3196023006040188C910A3A80021B1763FC620004321B4138E52D75A20096E4718D3E50016B19E0BA802325E858762D1802B28AD401A9880310E61041400043E2AC7E8A4800434DB24A384A4019401C92C154B43595B830002BC497ED9CC27CE686A6A43925B8A9CFFE3A9616E5793447004A4BBB749841500B26C5E6E306899C5B4C70924B77EF254B48688041CD004A726ED3FAECBDB2295AEBD984E08E0065C101812E006380126005A80124048CB010D4C03DC900E16A007200B98E00580091EE004B006902004B00410000AF00015933223100688010985116A311803D05E3CC4B300660BC7283C00081CF26491049F3D690E9802739661E00D400010A8B91F2118803310A2F43396699D533005E37E8023311A4BB9961524A4E2C027EC8C6F5952C2528B333FA4AD386C0A56F39C7DB77200C92801019E799E7B96EC6F8B7558C014977BD00480010D89D106240803518E31C4230052C01786F272FF354C8D4D437DF52BC2C300567066550A2A900427E0084C254739FB8E080111E0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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),] | ||
)] | ||
)] | ||
) | ||
); | ||
} |