Skip to content

Commit 4eaba47

Browse files
author
Matthew Judy
committed
Add solution for 2002-06 based on AsyncSequence.
1 parent b1b48e5 commit 4eaba47

File tree

1 file changed

+126
-32
lines changed

1 file changed

+126
-32
lines changed

Sources/2022/06/TuningTrouble.swift

Lines changed: 126 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -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

87178
extension 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

Comments
 (0)