↤ go back, or return home

jack's advent of code 2022 ramblings

day 6

a calm (before the storm)

much easier parsing today, no need to even bother reading seperate lines!

clean solutions galore as well

lets get on with it


click to view my solution

given the sample input:

mjqjpqmgbljsphdztnvjfqwrcgsmlb

assuming input is the above as one big string,

packets = input |> String.graphemes()

split input into its characters

i say characters, but the [underlying function] is named graphemes, since it is splitting on unicode graphemes

["m", "j", "q", "j", "p", "q", "m", "g", "b", "l", "j", "s", "p", "h", "d", "z", "t", "n", "v", "j",
 "f", "q", "w", "r", "c", "g", "s", "m", "l", "b"]

we are left with list of… i’m gonna call them charcaters again its easier to write

defmodule CommunicationDevice do
  def find_first_duplicate(packets, chunk_size) do
    index =
      packets
      |> Enum.chunk_every(chunk_size, 1, :discard)
      |> Enum.map(&MapSet.new(&1))
      |> Enum.with_index()
      |> Enum.find(fn {set, _index} -> MapSet.size(set) == chunk_size end)
      |> elem(1)

    index + chunk_size
  end
end

nice little single function module here!

find_first_duplicate/2 accepts our list of packets, and a chunk_size parameter

# ...
packets
|> Enum.chunk_every(chunk_size, 1, :discard)
# ...

this solution relies on [Enum.chunk_every/4] quite a bit, it basically acts as a sliding window


say i was given the list [1,2,3,4], and used this chunk_every function with the firt argument the list, the second the chunk size (2), and the third being the step, (with the :discard atom), we would get the following enumerable:

[[1,2], [2,3], [3,4]]

(the :discard atom is used to ensure we don’t get a [4] show up in this list, if any returned enumerable is less than the size of the chunk, it is discarded)


back to the function,

# ...
|> Enum.map(&MapSet.new(&1))
|> Enum.with_index()
# ...

then, we map over each one of these chunks into MapSets

and we include the index (what step we are on) by mapping the resulting MapSets enumerable with Enum.with_index

[
  {MapSet.new(["j", "m", "q"]), 0},
  {MapSet.new(["j", "p", "q"]), 1},
  {MapSet.new(["j", "p", "q"]), 2},
  {MapSet.new(["j", "m", "p", "q"]), 3},
  {MapSet.new(["g", "m", "p", "q"]), 4},
  # ...
]

we are left with this, the first three MapSets with a length less than 4 characters, even though 4 characters (we are using part 1 as the example here) were used to generate them, but the 4th item in this list having a MapSet with a size of 4, implies no duplicates in the characters used to produce this one!

# ...
|> Enum.find(fn {set, _index} -> MapSet.size(set) == chunk_size end)
|> elem(1)
# ...

pluck out the first tuple with a MapSet the size of our chunk size, and pluck the second item out of the tuple, since we are concerned with the index and not the actual MapSet itself

# ...

index + chunk_size

then, with this index, return it plus the chunk_size, since the value on the end of the window would be the first non-duplicate we run into in the devices stream, and if we just returned the index, it would be incorrectly offset

part 1

CommunicationDevice.find_first_duplicate(packets, 4) # -> 7

with our new fangled device module, use it, with a chunk size of 4

part 2

CommunicationDevice.find_first_duplicate(packets, 14) # -> 19

and, do it again, but with a chunk size of 14

nice

the full solution can be found [here]



others

there’s going to be lots of inline code today

[Mudkip/AdventOfCode] python src/data/aoc/2022/data
def solve(n):
  input = open("6.in", "r").read().strip()
  return next(i+n for i in range(len(input)) if len(set(input[i:i+n])) == n)
print(f"Part 1: {solve(4)}")
print(f"Part 2: {solve(14)}")

super clean, but also not crazy busy? maybe i’ve just read too many of your list comprehensions and grown to not hate them :D

i really like the usage of next here to find the first valid item that matches the conditonal bit of the list comp.

as usual, compact and epic

[briannamcdonald/advent-of-code-2022] python src/data/aoc/2022/data

a solution, could probably be compacted quite a bit though

chars_unique could early return false instead of continually iterating after setting unique to false

[krbarter/Advent-Of-Code-2022] python src/data/aoc/2022/data
line  = open("input.txt", "r").readlines()[0]

def solve(line, length):
    for x in range(0,  len(line) - (length - 1)):
        if len(set([line[x + y] for y in range(0, length)])) == length:
            return (x + length)
print("Part1: ", solve(line, 4), "Part2: ", solve(line, 14))

nice

a compact python solution

yeah

[nint8835/AdventOfCode2022] f# & python src/data/aoc/2022/data
let inputData =
    (System.IO.File.ReadAllText "Day6/input.txt")

let findMarker (size: int) (input: string) : int =
    input
    |> Array.ofSeq
    |> Array.windowed size
    |> Array.map (fun window -> (window |> Set.ofArray |> Set.count))
    |> Array.findIndex (fun uniqueCount -> uniqueCount = size)
    |> (+) size

printfn $"%A{findMarker 4 inputData}"
printfn $"%A{findMarker 14 inputData}"

first riley solution included fully inline, and its clean

quite similar conceptually to my solution, but i do like converting the array to a set, and then just counting the number of values in the set, since the find statement is then just comparing between the length of the chunks and how many items were in the set

also the (+) size is nice, i should look to see how i would do this in elixir :)

[hamzahap/AdventOfCode2022] sheets src/data/aoc/2022/data
=IF(COUNTUNIQUE(B1427:B1430)=4,"You reached my guy","You no reach noob")

you reached my guy

[TheCrypticCanadian/advent-of-code-2022] python src/data/aoc/2022/data

ok so to begin with, how dare you [change your folder naming structure] without consulting me first

i kid, i have [the tools] to update this in one spot, and have every link from here to your solution automagically update

your solution though, is nice, although you could have defined a cell above with a function to make your part 1 & 2 reusable :)

good job gump

[STollenaar/AdventOfCode2022] golang src/data/aoc/2022/data

clean go

not compact enough to include inline, but i don’t think a go solution will ever be that? it feels like it goes against the language design if it does

but still, clean go

[emilydormody/advent-of-code] src/data/aoc/2022/data

woooaaahhh a little queue

this is nice, fill up the queue, check for dups, and if dupes move on, but always be poppin’ one off of the queue to keep it with a length of 4 / 14

nice

you could probably do your part 1 & 2 in one file since, like most, the only thing seperating them is putting a 1 infront of the 4 in part one to make it 14

[zcvaters/adventofcode2022] swift src/data/aoc/2022/data

nice

this also gives the vibes of emilys queue solution, but uses a set to do the duplication finding, therefore no need for a utility function

nice

[chadmroberts88/advent-of-code-2022] typescript src/data/aoc/2022/data

interesting solution here, reaching for a regular expression

/(.).*\1/.

i put this into [regexr.com] to get a better understanding of it (since my regex-fu is lacking)

i sort of get it, but i don’t really understand the magic going on with capture group backreferencing here

Chad Roberts: Love it when you can use one function to solve both parts! (Full Disclosure: I Googled the RegEx!)

i feel like this is the response of most people who say “where did you get this regex?”

still neat to think of this as a possible solution method!

[devthedevel/advent_of_code] typescript src/data/aoc/2022/data

dev from the clouds, has duplicated code between part 1 and 2

are the clouds to be trusted?

i thought i should ask lord poseidon about this, via [ChatGPT], here is his response:

Dear Devin,

I, Lord Poseidon, have noticed that your code is quite impressive. However, I must point out that you have included duplicated code in your solutions. As a wise programmer, you should know that it is best practice to break out your code into utility functions to avoid repetition and make your code more organized and efficient.

Please consider this advice and continue to strive for excellence in your coding endeavors.

Best regards,

Lord Poseidon

[mathieuboudreau/advent] python notebook src/data/aoc/2022/data

nice

could probably cut out num_chars by iterating over a range and then breaking once you get to the value

and because python will keep the value you iterate over in-scope you can just print it at the end

for x in range(5):
  if x == 3:
    break

print(x) # -> 3

^ an example of what i’m talking about, a sneaky pythonism

[ajhynes7/advent-of-code-2022] julia src/data/aoc/2022/data

nice, very nice

the usage of [CircularDeque] is cool, a more sensible data structure to use since yeah the only operation you need to do if you are doing it the listy way is enqueue and dequeue

and also the function here acting directly on the file, but still remaining super clean

also allunique being a top-level function???

julia is good for this stuff wow

[RyanBrushett/adventofcode2022] ruby src/data/aoc/2022/data

[overengineer it, why not]

test cases! nice

def run
  input_data.each_char.with_index do |x, i|
    if packet.length < signal_length
      packet << x
      next
    end
    return i if packet & packet == packet

    (packet << x).shift
  end
end

clean, i always like seeing & being used for set operations

[joel1842/advent-of-code-2022] python src/data/aoc/2022/data

i can tell by your file path you are on linux, nice

but, this is because your full fat file path is in the file :P

stop that

interesting approach though, basically calculating both at the same time

it would technically add a line, but i would break from the for loop when startOfPacket and startOfMessage are both defined

also, [preferably you’d be using snake_case] instead of camelCase

[canetoads.ca] javascript src/data/aoc/2022/data

i don’t think there will ever be a nathan solution without a horizontal scroll bar :P

console.log(
  fs
    .readFileSync(io)
    .toString()
    .split("")
    .map((x, i, a) => new Set(a.slice(i - 14, i)))
    .map(function (x, i) {
      if (x.size == 14) return { x, i };
    })
    .filter((x) => x)
    .map((x) => x.i)
);

now, i know this isn’t as compact, but this is a bit nicer to grok

also this is technically only a part 2 solution since 14 is hard coded, could be broken out into a util function and invoked twice below to get 1 & 2

but hey, i am not your mum

[apreynolds1989/AdventOfCode2022] typescript src/data/aoc/2022/data

REDUCER

even i didn’t pull out a reducer today, nice

good set usage as well

epic

[EthanDenny/AdventOfCode2022] c++ src/data/aoc/2022/data

a c++ solution

pretty nice and simple

yeah

[lilmert/aoc] rust src/data/aoc/2022/data

:clean:

itertools usage with windowing and unique counting

but whats this

unwrap usage

marty please, think of the children

[bjbemister19/AdventOfCode] rust src/data/aoc/2022/data

no unwraps in this rust code, phew

feels quite similar logically to the c++ solution, but more crustacean-like

[M-ArafatZaman/AdventOfCode] python & c++ src/data/aoc/2022/data

nice c++ solution

you read the input twice though, could read once and pass to both solve calls, or just put it in a global variable because there are no rules

[SheldonT/AdventOfCode2022] java src/data/aoc/2022/data

a java solution!

quite decent

this is a nitpiq, but i’d run your code through the [google-java-format] utility (or some other java formatter) to clean it up a bit, a little too much in the way of newlines here


if you want to have your repo added for me to make a note of / talk about here (or have you repo removed), reach out:

email -> me@jackharrhy.com

discord -> <i>jack arthur null</i>#7539