@@ -19,8 +19,8 @@ import Shared
1919 and begin to make your way toward the star fruit grove.
2020
2121 As you move through the dense undergrowth, one of the Elves gives you a
22- handheld device. He says that it has many fancy features, but the most
23- important one to set up right now is the communication system.
22+ handheld ** device.** He says that it has many fancy features, but the most
23+ important one to set up right now is the ** communication system.**
2424
2525 However, because he's heard you have significant experience dealing with
2626 signal-based systems, he convinced the other Elves that it would be okay to
@@ -29,14 +29,14 @@ import Shared
2929
3030 As if inspired by comedic timing, the device emits a few colorful sparks.
3131
32- To be able to communicate with the Elves, the device needs to lock on to their
33- signal. The signal is a series of seemingly-random characters that the device
34- receives one at a time.
32+ To be able to communicate with the Elves, the device needs to ** lock on to
33+ their signal.** The signal is a series of seemingly-random characters that the
34+ device receives one at a time.
3535
3636 To fix the communication system, you need to add a subroutine to the device
37- that detects a start-of-packet marker in the datastream. In the protocol being
38- used by the Elves, the start of a packet is indicated by a sequence of four
39- characters that are all different.
37+ that detects a ** start-of-packet marker** in the datastream. In the protocol
38+ being used by the Elves, the start of a packet is indicated by a sequence
39+ of **four characters that are all different.**
4040
4141 The device will send your subroutine a datastream buffer (your puzzle input);
4242 your subroutine needs to identify the first position where the four most
@@ -53,45 +53,139 @@ import Shared
5353 marker could occur is after the fourth character is received, making the most
5454 recent four characters `mjqj`. Because `j` is repeated, this isn't a marker.
5555
56- The first time a marker appears is after the seventh character arrives. Once
57- it does, the last four characters received are `jpqm`, which are all different.
58- In this case, your subroutine should report the value `7`, because the first
59- start-of-packet marker is complete after 7 characters have been processed.
56+ The first time a marker appears is after the **seventh** character arrives.
57+ Once it does, the last four characters received are `jpqm`, which are all
58+ different. In this case, your subroutine should report the value `7`, because
59+ the first start-of-packet marker is complete after 7 characters have
60+ been processed.
6061
6162 Here are a few more examples:
6263
63- * `bvwbjplbgvbhsrlpgdmjqwftvncz` : first marker after character `5`
64- * `nppdvjthqldpwncqszvftbrmjlhg` : first marker after character `6`
65- * `nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg` : first marker after character `10`
66- * `zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw` : first marker after character `11`
64+ * `bvwbjplbgvbhsrlpgdmjqwftvncz` : first marker `p` after character `5`
65+ ....^
66+ * `nppdvjthqldpwncqszvftbrmjlhg` : first marker `t` after character `6`
67+ ....^
68+ * `nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg` : first marker `j` after character `10`
69+ ....^
70+ * `zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw` : first marker `l` after character `11`
71+ ....^
6772
68- How many characters need to be processed before the first start-of-packet marker is detected?
73+ How many characters need to be processed before the first start-of-packet
74+ marker is detected?
75+
76+
77+ # Part Two
78+
79+ Your device's communication system is correctly detecting packets, but still
80+ isn't working. It looks like it also needs to look for **messages.**
81+
82+ A **start-of-message marker** is just like a start-of-packet marker, except it
83+ consists of **14 distinct characters** rather than 4.
84+
85+ Here are the first positions of start-of-message markers for all of the
86+ above examples:
87+
88+ * `mjqjpqmgbljsphdztnvjfqwrcgsmlb` : first marker after character `19`
89+ * `bvwbjplbgvbhsrlpgdmjqwftvncz` : first marker after character `23`
90+ * `nppdvjthqldpwncqszvftbrmjlhg` : first marker after character `23`
91+ * `nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg` : first marker after character `29`
92+ * `zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw` : first marker after character `26`
93+
94+ How many characters need to be processed before the first start-of-message
95+ marker is detected?
6996 */
7097@main
71- struct TuningTrouble : ParsableCommand
98+ struct TuningTrouble : AsyncParsableCommand
7299{
73- // /// <#Enumeration for argument which activates "Part Two" behavior#>
74- // enum Mode: String, ExpressibleByArgument, CaseIterable
75- // {
76- // case modeA
77- // case modeB
78- // }
79- //
80- // @Option(help: "<#Argument used to activate “Part Two” behavior.#>")
81- // var mode: Mode
100+ /// Enumeration for argument which activates "Part Two" behavior
101+ enum Mode : String , ExpressibleByArgument , CaseIterable
102+ {
103+ case packet
104+ case message
105+
106+ var checkLength : Int
107+ {
108+ switch self
109+ {
110+ case . packet : return 4
111+ case . message : return 14
112+ }
113+ }
114+ }
115+
116+ @Option ( help: " Switch between searching for 'packet' or 'message' marker. " )
117+ var mode : Mode
82118}
83119
84120
121+ struct MarkerFinder : AsyncSequence , AsyncIteratorProtocol
122+ {
123+ typealias Element = Character
124+
125+ var signalIterator = FileHandle . standardInput. bytes. characters. makeAsyncIterator ( )
126+ var checkSegment = [ Character] ( )
127+
128+ let mode : TuningTrouble . Mode
129+
130+
131+ var markerIndex : Int
132+ {
133+ get async throws
134+ {
135+ let countBeforeMarker = try await self . reduce ( 0 )
136+ {
137+ count, _ in return ( count + 1 )
138+ }
139+
140+ return ( countBeforeMarker + 1 )
141+ }
142+ }
143+
144+
145+ mutating func next( ) async throws -> Character ?
146+ {
147+ guard let character = try await signalIterator. next ( ) else { fatalError ( " [ERROR] We've hit the end, Jim. " ) }
148+ let checkLength = self . mode. checkLength
149+
150+ checkSegment. append ( character)
151+
152+ switch checkSegment. count
153+ {
154+ case 0 ..< checkLength : return character
155+ case ( checkLength + 1 ) . . . . max : checkSegment. removeFirst ( )
156+ default : break
157+ }
158+
159+ if ( checkSegment. isDistinct )
160+ {
161+ return nil
162+ }
163+
164+ return character
165+ }
166+
167+
168+ func makeAsyncIterator( ) -> MarkerFinder
169+ {
170+ return self
171+ }
172+ }
173+
174+
175+
85176// MARK: - Command Execution
86177
87178extension TuningTrouble
88179{
89- mutating func run ( ) throws
180+ enum TuningError : Error
90181 {
91- while let inputLine = readLine ( )
92- {
93- print ( " \( inputLine) " )
94- }
182+ case foundMarker
183+ }
184+
185+ mutating func run( ) async throws
186+ {
187+ let markerIndex = try await MarkerFinder ( mode: self . mode) . markerIndex
188+ print ( markerIndex)
95189 }
96190}
97191
0 commit comments