# Day 6: Tuning Trouble

Please post your solutions in your own top-level comment. Here's a template you can copy-paste into your comment to format it nicely, with the code collapsed by default inside an expandable section with syntax highlighting (you can replace `python` with any of the "short names" listed in this page of supported languages):

``````<details>
<summary>Part 1</summary>

```python
```

</details>
``````

1. deckard
(edited )
My Python solutions, which are identical other than the WINSIZ constant. Surprised there were so many test cases given, since this one is rather straightforward. Part 1 #!/usr/bin/env pypy3 import...

My Python solutions, which are identical other than the `WINSIZ` constant.
Surprised there were so many test cases given, since this one is rather
straightforward.

Part 1
``````#!/usr/bin/env pypy3

import sys

WINSIZ = 4

def main():
nchars = next(i + WINSIZ for i in range(len(data) - WINSIZ)
if len(set(data[i:i + WINSIZ])) == WINSIZ)
print(nchars)

if __name__ == '__main__':
main()
``````
Part 2
``````#!/usr/bin/env pypy3

import sys

WINSIZ = 14

def main():
nchars = next(i + WINSIZ for i in range(len(data) - WINSIZ)
if len(set(data[i:i + WINSIZ])) == WINSIZ)
print(nchars)

if __name__ == '__main__':
main()
``````
2. 
primordial-soup
(edited )
Part 1, in Python-ish (l > p | (windowed, X, 4) | (locate, X, all_unique) | first) + 4 Python code generated from the above from more_itertools import all_unique from more_itertools import first...
Part 1, in Python-ish
``````(l > p
| (windowed, X, 4)
| (locate, X, all_unique)
| first) + 4
``````
Python code generated from the above
``````from more_itertools import all_unique
from more_itertools import first
from more_itertools import locate
from more_itertools import windowed
from pipetools import X
from pipetools import pipe
import sys
p = pipe
for l in sys.stdin:
l = l.rstrip('\n')
output = (l > p | (windowed, X, 4) | (locate, X, all_unique) | first) + 4
if output is not None:
print(output)
``````

`sed 's/4/14/'` for Part 2.

1. 
Gyrfalcon
Do you have a link to where I could learn more about Python-ish? When I try to google it I just get a bunch of people talking about things that are like or similar to Python and not what you are...

Do you have a link to where I could learn more about Python-ish? When I try to google it I just get a bunch of people talking about things that are like or similar to Python and not what you are using.

1. 
Crestwave
1. 
primordial-soup
thanks for linking to this! @Gyrfalcon—you won't find it searching "Python-ish" online, that's just a name i made up for the purpose of posting AoC solutions to Tildes :)

@Gyrfalcon—you won't find it searching "Python-ish" online, that's just a name i made up for the purpose of posting AoC solutions to Tildes :)

1. Gyrfalcon
Well I definitely appreciate you posting, even though I can't say I understand what is going on all that much better after reading you describe what it is.

Well I definitely appreciate you posting, even though I can't say I understand what is going on all that much better after reading you describe what it is.

1 vote
3. 
bhrgunatha
(edited )
Part 1 The nice thing about Racket's for iterators is they can be nested (for*) or in-parallel (for). This makes iterating a small sized window nicer because you don't need to deal with indexes...
Part 1 The nice thing about Racket's for iterators is they can be nested (for*) or in-parallel (for). This makes iterating a small sized window nicer because you don't need to deal with indexes except for initialising them.
``````(define (part-01 input)
(for/first ([(a i) (in-indexed (in-string input))]
[b (in-string (substring input 1))]
[c (in-string (substring input 2))]
[d (in-string (substring input 3))]
#:when (= 4 (set-count (set a b c d))))
(+ i 4)))
``````
Part 2 Extend the idea to part 2 but convert the string to a list. Named let in Racket/Scheme is an idiom like defining an internal function where the let bound variables correspond to function arguments. You _can_ define internal procedures in Racket but it's overhead for a simple case like this. The Racket libraries are littered with hundreds or thousands of named lets.
``````(define (part-02 input)
(let search ([cs (string->list input)]
[i 0])
(cond [(= 14 (set-count (list->set (take cs 14))))
(+ i 14)]
[else (search (rest cs) (add1 i))])))
``````
Speedrun Better to keep a running count of letters in a sliding substring. If Racket had a nice counting library like python's I wouldn't need to write these.

Attempt 1:

Part 1 ~75% elapsed time
Part 2 ~35% elapsed time

Attempt 2:
I wish I could remember that `hash-count` is a constant time count of keys.
Simply replace `(= n (length (hash-keys cs))` with `(= n (hash-count cs))` as the exit clause below gives
Part 1 ~50% elapsed time
Part 2 ~20% elapsed time

``````(define (package-start s n)
(for/fold ([cs (counts (substring s 0 n))]
[found? #f]
#:result found?)
([i (in-naturals)]
[start (in-string s)]
[end (in-string (substring s n))]
#:break found?)
(if (= n (length (hash-keys cs)))
(values cs (+ i n))
(values (udpate-counts cs start end) found?))))

(define removed
(if (<= (hash-ref counts removal 0) 1)
(hash-remove counts removal)
(hash-update counts removal sub1)))

(define (counts s)
(for/fold ([cs (hasheqv)])
([c (in-string s)])

(define (part-01 input) (package-start input 4))
(define (part-02 input) (package-start input 14))
``````
1. 
thorondir
Reading your solutions [and the docs, to figure out what you did xD] is always super helpful. :D I went about it a bit differently, by manually keeping track of the index. Which also meant part...

Reading your solutions [and the docs, to figure out what you did xD] is always super helpful. :D

I went about it a bit differently, by manually keeping track of the index. Which also meant part two was a change of adding a single character. xD

Both Parts
``````(define (unique? lst)
(= (length lst) (set-count (list->set lst))))

(define (process-slice slice idx slice-length)
(cond [(< (length slice) slice-length)
(displayln "slice too small")
(values empty -1)]
[(>= (length slice) slice-length)
(define new-slice (take slice slice-length))
(cond
[(unique? new-slice) (values empty (+ idx slice-length))]
[else (process-slice (rest slice) (add1 idx) slice-length)])]
[else
(values 'never-supposed-to-get-here -1)]))

(define (part-1 input)
(define-values (m i) (process-slice input 0 4))
i)

(define (part-2 input)
(define-values (m i) (process-slice input 0 14))
i)
``````
1. 
bhrgunatha
That's kind of you to say, thanks. I did essentially the same for part-02, except I didn't check the length because AoC basically guarantees we'll find an answer. In real code you bet I'd be...

That's kind of you to say, thanks.

I did essentially the same for part-02, except I didn't check the length because AoC basically guarantees we'll find an answer. In real code you bet I'd be checking if the list is running out of items.

One thing to be careful about is that length has to consume the whole list - the compiler doesn't have internal state for list length.

Instead of repeatedly checking the length, it would be more efficient to pass the length as an argument to process-slice and keep reducing that value as you chop off more of the list. That way, you don't go through the whole list every iteration, instead you just subtract from the value you calculate once at the start.

1. thorondir
Oh, right. O(n) in a place I didn't expect. Thanks for the pointers! :)

Oh, right. O(n) in a place I didn't expect.

Thanks for the pointers! :)

4. asterisk
Python buffer = open("input.txt").read() def device(length: int): for i in range(len(buffer) - length + 1): if len(set(buffer[i : i + length])) == length: return length + i print(device(4)) # Part...
Python
``````buffer = open("input.txt").read()

def device(length: int):
for i in range(len(buffer) - length + 1):
if len(set(buffer[i : i + length])) == length:
return length + i

print(device(4))  # Part One: 1625
print(device(14))  # Part Two: 2250
``````
5. jzimbel
(edited )
Elixir 👶 Both parts Wasn't sure what to name the function tbh. It's not really giving the index. defmodule AdventOfCode.Solution.Year2022.Day06 do def part1(input), do: index_of_marker(input, 4)...

Elixir

👶

Both parts

Wasn't sure what to name the function tbh. It's not really giving the index.

``````defmodule AdventOfCode.Solution.Year2022.Day06 do
def part1(input), do: index_of_marker(input, 4)
def part2(input), do: index_of_marker(input, 14)

defp index_of_marker(input, size) do
input
|> String.to_charlist()
|> Enum.find_index(&(MapSet.size(MapSet.new(&1)) == size))
|> Kernel.+(size)
end
end
``````
About `|>`

I abuse it in my solutions (because it's fun), but the `|>` ("pipe") operator is basically just syntactic sugar.

Functions in Elixir, for the most part, are not tightly coupled with data types. As a counterexample, arrays in JS have array functions as "methods"—`myArray.map(...)`. The method gets the "subject" array as an implicit first `this` argument. There are no methods in Elixir. Data and logic are more strictly separated. Instead, we have functions where you explicitly pass the "subject" as the first argument: `Enum.map(my_list, ...)`.

`|>` exists mostly to make "chaining" possible. It takes the result of the previous expression, and passes it as the first argument of the next function call. The code runs the same, but it reads more like a pipeline of sequential operations than one giant messy one-liner.

One thing I really like about this approach is that, in referencing the module for each function call—e.g. `String.*`, `Enum.*`, `MapSet.*`—you can sort of annotate what type you're working with at each step. In a longer pipeline, it's often very easy to see the type transformations that are happening; something that you don't get with chained method calls in other languages.

``````numbers_str = "1 2 25 93 8"

sum = Enum.sum(Enum.map(String.split(numbers_str, " "), &String.to_integer/1))

# compiles to the exact same byte code as

sum =
numbers_str
# We're using a function from the String module, so the subject is currently a string
|> String.split(" ")
# We're using a function from the Enum module, so the subject is currently an enumerable (a list, specifically)
|> Enum.map(&String.to_integer/1)
# Still an enumerable
|> Enum.sum()
``````
6. tomf
Google Sheets Not the prettiest thing, but it works. both parts This does both parts.. I'm still new to SCAN, though. :) =ARRAYFORMULA( SCAN(,{4,14}, LAMBDA(a,c, QUERY( {SEQUENCE(LEN(A2),1,c),...

Not the prettiest thing, but it works.

both parts

This does both parts.. I'm still new to SCAN, though. :)

``````=ARRAYFORMULA(
SCAN(,{4,14},
LAMBDA(a,c,
QUERY(
{SEQUENCE(LEN(A2),1,c),
BYROW(SPLIT(REGEXREPLACE(MID(A2,SEQUENCE(LEN(A2)),c),"(.)","\$1|"),"|"),
LAMBDA(x,TRANSPOSE(UNIQUE(TRANSPOSE(x)))))},
"select Col1
where Col"&c+1&" is not null
limit 1"))))
``````
7. spit-evil-olive-tips
part 1 from collections import deque with open('06.txt') as input_file: buffer = input_file.read().strip() def find_marker(buffer): window = deque(maxlen=4) for i, c in enumerate(buffer):...
part 1
``````from collections import deque

with open('06.txt') as input_file:

def find_marker(buffer):
window = deque(maxlen=4)
for i, c in enumerate(buffer):
window.append(c)

if len(window) == 4 and \
window not in (window, window, window) and \
window not in (window, window) and \
window != window:
return i + 1, ''.join(window)

index, marker = find_marker(buffer)

print(marker)
print(index)
``````
part 2

generalized it so that if I change the `size` parameter back to 4, it solves part 1 again

rather less efficient than it could be, because it constructs a `set` over and over again just to check for uniqueness. that could be improved by keeping track of characters as they both enter and leave the window, using that to maintain a dictionary of character counts, and checking those counts to see if we found the marker.

but, execution time on my desktop is ~20ms for both the example input and my real input, which is both fast enough and suggests that the long pole is the Python startup time and not my algorithm, so meh.

``````--- aoc06a.py   2022-12-05 23:55:26.426887947 -0800
+++ aoc06b.py   2022-12-05 23:53:52.512286534 -0800
@@ -3,18 +3,16 @@
with open('06.txt') as input_file:

-def find_marker(buffer):
-       window = deque(maxlen=4)
+def find_marker(buffer, size):
+       window = deque(maxlen=size)
for i, c in enumerate(buffer):
window.append(c)
+
+               charset = set(window)
+               if len(charset) == size:
+                       return i + 1, ''.join(window)

-               if len(window) == 4 and \
-                       window not in (window, window, window) and \
-                       window not in (window, window) and \
-                       window != window:
-                  return i + 1, ''.join(window)
-
-index, marker = find_marker(buffer)
+index, marker = find_marker(buffer, 14)
``````
8. MeckiSpaghetti
(edited )
Ruby Part 1 i = File.read("input.txt") i.chars.each_cons(4) do |s| if s == s.uniq p i.index(s.join)+4 break end end Part 2 i = File.read("input.txt") i.chars.each_cons(14) do |s| if s == s.uniq p...

Ruby

Part 1
``````i = File.read("input.txt")

i.chars.each_cons(4) do |s|
if s == s.uniq
p i.index(s.join)+4
break
end
end
``````
Part 2
``````i = File.read("input.txt")

i.chars.each_cons(14) do |s|
if s == s.uniq
p i.index(s.join)+14
break
end
end
``````
9. Eabryt
I felt like this one was especially easy, but maybe that's just me. Part1 & Part2 import queue def checkRepeats(input): chars = [] for item in input.queue: if item in chars: return False...

I felt like this one was especially easy, but maybe that's just me.

Part1 & Part2
``````import queue

def checkRepeats(input):
chars = []
for item in input.queue:
if item in chars:
return False
chars.append(item)
return True

def part1(input):
print(f"Part 1!")
window = queue.Queue(4)
for index,char in enumerate(input):
if window.full():
if checkRepeats(window):
break
window.get()
window.put(char)
print(f"Index: {index}")

def part2(input):
print(f"Part 2!")
window = queue.Queue(14)
for index,char in enumerate(input):
if window.full():
if checkRepeats(window):
break
window.get()
window.put(char)
print(f"Index: {index}")

def openFile():

def main():
f = openFile()
part1(f)
part2(f)

if __name__ == '__main__':
main()
``````
10. wycy
Rust use std::env; use std::io::{self}; use std::collections::HashSet; fn packet_start(s: &str) -> usize { const MARKER_SIZE: usize = 4; let mut start = MARKER_SIZE; for chs in...
Rust
``````use std::env;
use std::io::{self};
use std::collections::HashSet;

fn packet_start(s: &str) -> usize {
const MARKER_SIZE: usize = 4;
let mut start = MARKER_SIZE;
for chs in s.chars().collect::<Vec<_>>().windows(MARKER_SIZE) {
let (a,b,c,d) = (chs,chs,chs,chs);
if a != b && a != c && a != d && b != c && b != d && c != d { break }
else { start += 1; }
}
start
}

fn message_start(s: &str) -> usize {
const MARKER_SIZE: usize = 14;
let mut start = MARKER_SIZE;
'outer: for chs in s.chars().collect::<Vec<_>>().windows(MARKER_SIZE) {
start += 1;
let mut char_set: HashSet<char> = HashSet::new();
for ch in chs {
if char_set.contains(ch) { continue 'outer; }
else { char_set.insert(*ch); }
}
break;
}
start - 1
}

fn solve(input: &str) -> io::Result<()> {
// Input
let input_str = input_str.trim();

// Output
println!("Part 1: {}",packet_start(input_str)); // 1578
println!("Part 2: {}",message_start(input_str)); // 2178

Ok(())
}

fn main() {
let args: Vec<String> = env::args().collect();
let filename = &args;
solve(&filename).unwrap();
}
``````
11. kari
Today was much easier than I expected :) nim (both parts) import std/[sets, sequtils] proc day06*() = let f = open("inputs/day06.in") defer: f.close() let chars = f.readLine().toSeq() var...

Today was much easier than I expected :)

nim (both parts)
``````import std/[sets, sequtils]

proc day06*() =
let f = open("inputs/day06.in")
defer: f.close()

var
startOfPktIdx = -1
startOfMsgIdx = -1
curIdx = 0
pktSet: HashSet[char]
msgSet: HashSet[char]

while startOfPktIdx == -1 or startOfMsgIdx == -1:
# Part 1
if startOfPktIdx == -1:
pktSet = chars[curIdx .. curIdx + 3].toHashSet()
if pktSet.len == 4:
startOfPktIdx = curIdx + 4
# Part 2
if startOfMsgIdx == -1:
msgSet = chars[curIdx .. curIdx + 13].toHashSet()
if msgSet.len == 14:
startOfMsgIdx = curIdx + 14
curIdx += 1

echo "Part 1: " & \$startOfPktIdx
echo "Part 2: " & \$startOfMsgIdx
``````
12. ras
Today's was nice and easy. Solution - Parts 1 and 2 - JavaScript import { readFileSync } from "fs"; const input = readFileSync("input.txt", "utf8").toString().split("\n"); const MARKER_SIZE = 4;...

Today's was nice and easy.

Solution - Parts 1 and 2 - JavaScript
``````import { readFileSync } from "fs";

const MARKER_SIZE = 4;
// const MARKER_SIZE = 14;

const findMarker = (buffer) => {
for (let i = 0; i < buffer.length; i++) {
let s = new Set();
let x = [...buffer.slice(i, i + MARKER_SIZE)];
for (const i of x) {
}
if (s.size === MARKER_SIZE) return i + MARKER_SIZE;
}
};

input.forEach((item, index) => {
console.log(findMarker(item));
});
``````
13. Toric
today was nice and easy. Had to find rusts window() function, though. Driver mod part1; mod part2; mod utilities; fn main() { let _input = include_str!("./input.txt"); println!("Part One");...

today was nice and easy. Had to find rusts window() function, though.

Driver
``````mod part1;
mod part2;
mod utilities;

fn main() {
let _input = include_str!("./input.txt");

println!("Part One");
println!("Result: {}", part1::part1(_input));

println!("Part Two");
println!("Result: {}", part2::part2(_input));
}
``````
Utilities
``````pub fn find_dupes_stupid<T: PartialEq>(slice: &[T]) -> bool {
for i in 1..slice.len() {
if slice[i..].contains(&slice[i - 1]) {
return true;
}
}
false
}
``````
Part 1
``````use crate::utilities::*;

pub fn part1(input: &str) -> usize {
input
.as_bytes()
.windows(4)
.position(|x| !find_dupes_stupid(x))
.unwrap()+4
}
``````
Part 2
``````use crate::utilities::*;

pub fn part2(input: &str) -> usize {
input
.as_bytes()
.windows(14)
.position(|x| !find_dupes_stupid(x))
.unwrap()+14
}
``````
14. Crestwave
Quick and dirty because I am quite late. Part 1 #!/usr/bin/awk -f BEGIN { FS = "" } { for (i = 1; i <= NF; ++i) { a[\$i] += 1 if (i >= 4) { if (a[\$i]*a[\$(i-1)]*a[\$(i-2)]*a[\$(i-3)] == 1) { print(i)...

Quick and dirty because I am quite late.

Part 1
``````#!/usr/bin/awk -f
BEGIN { FS = "" }
{
for (i = 1; i <= NF; ++i) {
a[\$i] += 1

if (i >= 4) {
if (a[\$i]*a[\$(i-1)]*a[\$(i-2)]*a[\$(i-3)] == 1) {
print(i)
exit
}

a[\$(i-3)] -= 1
}
}
}
``````
Part 2
``````#!/usr/bin/awk -f
BEGIN { FS = "" }
{
for (i = 1; i <= NF; ++i) {
a[\$i] += 1

if (i >= 14) {
for (j in a)
if (a[j] > 1)
break

if (a[j] < 2) {
print(i)
exit
}

a[\$(i-13)] -= 1
}
}
}
``````
15. whispersilk
I'm using Rust this year, and trying to keep it std-only throughout the month. Part 1 use std::error::Error; use std::fs::File; use std::io::Read; struct Buffer { inner: [(usize, char); 4], } impl...

I'm using Rust this year, and trying to keep it `std`-only throughout the month.

Part 1
``````use std::error::Error;
use std::fs::File;

struct Buffer {
inner: [(usize, char); 4],
}

impl Buffer {
fn new() -> Buffer {
Buffer { inner: [(0, '\n'); 4] }
}

fn add(&mut self, new_elem: (usize, char)) {
let least_recent = self.inner.iter().enumerate().min_by(|x, y| x.1.0.cmp(&y.1.0)).unwrap();
self.inner[least_recent.0] = new_elem;
}

fn unique(&self) -> bool {
self.inner.iter().all(|e| e.1 != '\n' && self.inner.iter().filter(|e2| e.1 == e2.1).count() == 1)
}
}

fn main() -> Result<(), Box<dyn Error>> {
let mut file = File::open("input_6.txt")?;
let mut contents = String::new();
let mut recents: Buffer = Buffer::new();
let pos = contents.chars().enumerate().take_while(|(idx, c)| {
!recents.unique()
}).count() + 1;
println!("{pos}");
Ok(())
}
``````
Part 2
``````use std::error::Error;
use std::fs::File;

struct Buffer {
inner: [(usize, char); 14],
}

impl Buffer {
fn new() -> Buffer {
Buffer { inner: [(0, '\n'); 14] }
}

fn add(&mut self, new_elem: (usize, char)) {
let least_recent = self.inner.iter().enumerate().min_by(|x, y| x.1.0.cmp(&y.1.0)).unwrap();
self.inner[least_recent.0] = new_elem;
}

fn unique(&self) -> bool {
self.inner.iter().all(|e| e.1 != '\n' && self.inner.iter().filter(|e2| e.1 == e2.1).count() == 1)
}
}

fn main() -> Result<(), Box<dyn Error>> {
let mut file = File::open("input_6.txt")?;
let mut contents = String::new();
let mut recents: Buffer = Buffer::new();
let pos = contents.chars().enumerate().take_while(|(idx, c)| {
!recents.unique()
}).count() + 1;
println!("{pos}");
Ok(())
}
``````
16. soks_n_sandals
Both of today's parts in bash. Part 1+2 There's probably a more elegant way than deleting matching letters from a stream of 4 characters then checking that 3 are still left to determine...

Both of today's parts in bash.

Part 1+2 There's probably a more elegant way than deleting matching letters from a stream of 4 characters then checking that 3 are still left to determine uniqueness.
``````#!/usr/bin/env bash

file=day6.dat
part=1

if [[ \${part} -eq 1 ]]; then
# /////////////////////////////////////////////////////////////////////////////
#part 1 // 0.08s // 1300 dbpw
searchWidth=4 #width of character subset to check
else
#part 2 // 0.26s // 3986 lcfjqpdwznsbrh
searchWidth=14 #width of character subset to check
fi

mapfile -t stream < \$file
charLength=\${#stream}
i=0 #counter for outer loop
while [[ \$i -lt \$charLength ]]; do

#   -- extract subset of letters from bit stream
currentFour=\${stream:i:searchWidth}

j=0 #counter for inner loop
count=0 #number of unique letters in subset

#   -- extract one letter from our subset
#   -- delete matches of extracted letter
#   -- if only 1 letter is matched, look at the next letter, otherwise just start again
#   -- if we have four unique letters, print the spot and quit
while [[ \$j -lt \$searchWidth ]]; do
check=\${currentFour:\$j:1}
removed=\${currentFour//[\$check]/}
length=\${#removed}
if [[ length -eq \$((\$searchWidth - 1)) ]]; then
((count = count + 1))
(( j = j + 1))
else
break
fi
done

#   -- quit searching after the first set of unique letters
if [[ \$count -eq \$searchWidth ]]; then
break 1
fi
(( i = i + 1))
done

echo Position of stream for part \${part}: \$((\$i + \$searchWidth))
echo Unique letters: \$currentFour
``````
1 vote
17. Gyrfalcon
Well after yesterday saying that I had never done regular expressions in Python I saw a text matching challenge and tried it and then figured out that this is not, in fact, the sort of task that...

Well after yesterday saying that I had never done regular expressions in Python I saw a text matching challenge and tried it and then figured out that this is not, in fact, the sort of task that regular expressions make easy. I ended up doing this a little differently than the other Python solutions I see so far today, not using either queues or sets, but getting to test drive `for else` syntax, which was neat. I also did it kind of a clunky, single use way for part one, and then wrote part 2 generally so I could replace my part 1 function, though I left it for posterity. I do think my solution has a useful benefit, in that if it finds, say that the last two characters in a long search window are the same, it will skip forward such that the window starts with what was previously the last character, since we know that all windows that include those two characters at the end will not be what we are looking for.

Parts 1 and 2, Python
``````def find_packet_marker(message: str) -> int:
end = 3
while end < len(message):
if message[end - 3] in message[end - 2 : end + 1]:
end += 1
continue

if message[end - 2] in message[end - 1 : end + 1]:
end += 2
continue

if message[end - 1] == message[end]:
end += 3
continue

return end + 1

return -1

def find_marker(message: str, marker_size: int) -> int:

end = marker_size - 1
while end < len(message):
for offset in range(marker_size - 1, 0, -1):
if message[end - offset] in message[end - (offset - 1) : end + 1]:
end += marker_size - offset
break
else:
return end + 1

return -1

def main(filepath: str) -> Tuple[int, int]:

return (find_marker(message, 4), find_marker(message, 14))
``````
1 vote
18. balooga
(edited )
Here's my TypeScript solution. Seconding what others have said that today's was refreshingly easy. type InputData = string; export function run(input: string): string[] { Parts 1 and 2 const...
Here's my TypeScript solution. Seconding what others have said that today's was refreshingly easy.
``````type InputData = string;

export function run(input: string): string[] {
``````
Parts 1 and 2
``````  const findMarker = (stream: InputData, numberOfCharacters: number): number => {
const previousLetters = [] as string[];
for (let i = 0; i < stream.length; i++) {
previousLetters.push(stream[i]);
if (previousLetters.length <= numberOfCharacters) {
continue;
}
previousLetters.shift();
if (new Set(previousLetters).size === numberOfCharacters) {
return i + 1;
}
}
return -1;
};
``````
``````  return [`\${findMarker(input, 4)}`, `\${findMarker(input, 14)}`];
}
``````

Edit: Renamed a variable that still had a name specific to part 1 even though it was used for both parts.

1 vote