@@ -8,92 +8,107 @@ namespace AdventOfCode.Y2021.Day16;
8
8
class Solution : Solver {
9
9
10
10
public object PartOne ( string input ) =>
11
- GetTotalVersion ( GetPacket ( GetInput ( input ) ) ) ;
11
+ GetTotalVersion ( GetPacket ( GetReader ( input ) ) ) ;
12
12
13
13
public object PartTwo ( string input ) =>
14
- Evaluate ( GetPacket ( GetInput ( input ) ) ) ;
14
+ Evaluate ( GetPacket ( GetReader ( input ) ) ) ;
15
15
16
+ // recursively sum the versions of a packet and its content for part 1:
17
+ int GetTotalVersion ( Packet packet ) =>
18
+ packet . version + packet . packets . Select ( GetTotalVersion ) . Sum ( ) ;
19
+
20
+ // recursively evaluate the packet and its contents based on the type tag for part 2:
16
21
long Evaluate ( Packet packet ) {
17
22
var parts = packet . packets . Select ( Evaluate ) . ToArray ( ) ;
18
23
return packet . type switch {
19
24
0 => parts . Sum ( ) ,
20
25
1 => parts . Aggregate ( 1L , ( acc , x ) => acc * x ) ,
21
26
2 => parts . Min ( ) ,
22
27
3 => parts . Max ( ) ,
23
- 4 => packet . payload ,
28
+ 4 => packet . payload , // <--- literal packet is handled uniformly
24
29
5 => parts [ 0 ] > parts [ 1 ] ? 1 : 0 ,
25
30
6 => parts [ 0 ] < parts [ 1 ] ? 1 : 0 ,
26
31
7 => parts [ 0 ] == parts [ 1 ] ? 1 : 0 ,
27
32
_ => throw new Exception ( )
28
33
} ;
29
34
}
30
35
31
- int GetTotalVersion ( Packet packet ) =>
32
- packet . version + packet . packets . Select ( GetTotalVersion ) . Sum ( ) ;
36
+ // convert hex string to bit sequence reader
37
+ BitSequenceReader GetReader ( string input ) => new BitSequenceReader (
38
+ from hexChar in input
39
+
40
+ // first get the 4 bits out of a hex char:
41
+ let value = Convert . ToInt32 ( hexChar . ToString ( ) , 16 )
42
+ let nibble = Convert . ToString ( value , 2 ) . PadLeft ( 4 , '0' )
33
43
34
- Input GetInput ( string input ) => new Input (
35
- ( from ch in input
36
- let bits = Convert . ToString ( Convert . ToInt32 ( ch . ToString ( ) , 16 ) , 2 ) . PadLeft ( 4 , '0' )
37
- from bit in bits
38
- select bit - '0' ) . ToList ( )
44
+ // then convert them to numbers:
45
+ from bitChar in nibble
46
+ select ( byte ) ( bitChar - '0' )
39
47
) ;
40
48
41
- Packet GetPacket ( Input input ) {
42
- var version = input . ReadInt ( 3 ) ;
43
- var type = input . ReadInt ( 3 ) ;
49
+ // make sense of the bit sequence:
50
+ Packet GetPacket ( BitSequenceReader reader ) {
51
+ var version = reader . ReadInt ( 3 ) ;
52
+ var type = reader . ReadInt ( 3 ) ;
44
53
var packets = new List < Packet > ( ) ;
45
54
var payload = 0L ;
46
55
47
56
if ( type == 0x4 ) {
57
+ // literal, payload is encoded in the following bits in 5 bit long chunks:
48
58
while ( true ) {
49
- var isLast = input . ReadInt ( 1 ) == 0 ;
50
- payload = payload * 16 + input . ReadInt ( 4 ) ;
59
+ var isLast = reader . ReadInt ( 1 ) == 0 ;
60
+ payload = payload * 16 + reader . ReadInt ( 4 ) ;
51
61
if ( isLast ) {
52
62
break ;
53
63
}
54
64
}
55
- } else if ( input . ReadInt ( 1 ) == 0 ) {
56
- var length = input . ReadInt ( 15 ) ;
57
- var subPackages = input . ReadInput ( length ) ;
65
+ } else if ( reader . ReadInt ( 1 ) == 0 ) {
66
+ // operator, the next 'length' long bit sequence encodes the sub packages:
67
+ var length = reader . ReadInt ( 15 ) ;
68
+ var subPackages = reader . GetBitSequenceReader ( length ) ;
58
69
while ( subPackages . Any ( ) ) {
59
70
packets . Add ( GetPacket ( subPackages ) ) ;
60
71
}
61
72
} else {
62
- var packetCount = input . ReadInt ( 11 ) ;
63
- packets . AddRange ( from _ in Enumerable . Range ( 0 , packetCount ) select GetPacket( input ) ) ;
73
+ // operator with 'packetCount' sub packages:
74
+ var packetCount = reader . ReadInt ( 11 ) ;
75
+ packets . AddRange ( from _ in Enumerable . Range ( 0 , packetCount ) select GetPacket( reader ) ) ;
64
76
}
65
77
66
78
return new Packet ( version , type , payload , packets . ToArray ( ) ) ;
67
79
}
68
80
}
69
81
70
- class Input {
71
- private List < int > bits ;
82
+ // Rader class with convenience methods to retrieve n-bit integers and subreaders as needed
83
+ class BitSequenceReader {
84
+ private List < byte > bits ;
72
85
private int ptr ;
73
86
74
- public Input ( List < int > numbers ) {
75
- this . bits = numbers ;
87
+ public BitSequenceReader ( IEnumerable < byte > bits ) {
88
+ // copying the input, and representing each bit with a byte is not very attracitve,
89
+ // but it's aoc time....
90
+ this . bits = bits . ToList ( ) ;
76
91
}
77
92
78
93
public bool Any ( ) {
79
94
return ptr < bits . Count ( ) ;
80
95
}
81
96
82
- public Input ReadInput ( int n ) {
83
- var sub = bits . GetRange ( ptr , n ) . ToList ( ) ;
84
- var res = new Input ( sub ) ;
85
- ptr += n ;
97
+ public BitSequenceReader GetBitSequenceReader ( int bitCount ) {
98
+ var res = new BitSequenceReader ( bits . GetRange ( ptr , bitCount ) ) ;
99
+ ptr += bitCount ;
86
100
return res ;
87
101
}
88
102
89
- public int ReadInt ( int n ) {
103
+ public int ReadInt ( int bitCount ) {
90
104
var res = 0 ;
91
- foreach ( var bit in bits . GetRange ( ptr , n ) ) {
105
+ foreach ( var bit in bits . GetRange ( ptr , bitCount ) ) {
92
106
res = res * 2 + bit ;
93
107
}
94
- ptr += n ;
108
+ ptr += bitCount ;
95
109
return res ;
96
110
}
97
111
}
98
112
113
+ // Each packet has all fields, type tag tells how to interpret the contents
99
114
record Packet ( int version , int type , long payload , Packet [ ] packets ) ;
0 commit comments