Commit graph

108 commits

Author SHA1 Message Date
81c4073f32 Solve 2017:25 "The Halting Problem" 2025-05-06 23:53:56 +02:00
8b6d89fec5 Solve 2017:24 "Electromagnetic Moat" 2025-05-06 23:06:16 +02:00
4b1fa6bd65 Solve 2017:23 "Coprocessor Conflagration" 2025-05-06 20:15:16 +02:00
5b754381b0 Format files 2025-05-06 20:14:58 +02:00
fcbeb4bfdd Solve 2024:24 pt2 "Code Chronicle"
To solve this, it was easier to visualize the
graph and spot errors. This code is kept for
reference.

To learn the mechanics, These subreddit threads
are helpful:

- https://www.reddit.com/r/adventofcode/comments/1hla5ql/2024_day_24_part_2_a_guide_on_the_idea_behind_the/
- https://www.reddit.com/r/adventofcode/comments/1hneuf0/2024_day_24_part_2_finally_solved_it/
2025-01-05 00:06:18 +01:00
d7d5312786 Solve 2024:21 pt2 "Keypad Conundrum"
Turns out the initial trial of using
Manhattan distance was required to
solve part 2, since the BFS
implementation is impossible to
scale up from 2 robots to 25.

Recursion and memoization makes the
execution time acceptable.

Line 53 makes all the difference here.
The order of `<|v|^|>` matters when
constructing a sequence. Many
hours was spent trying to find the correct
priority. For the example input, especially
456A and 379A were volatile.
2025-01-05 00:06:18 +01:00
3a9a7d4994 Solve 2024:21 p1 "Keypad Conundrum"
Early versions of the code used Manhattan distance
instead of BFS to find the movements. Turns out this
was covering about 80% of all cases.
2025-01-05 00:06:18 +01:00
72574e753f Solve 2024:24 pt1 "Crossed Wires"
No idea how to solve pt2, so it will rest for now.
2025-01-05 00:06:18 +01:00
1b7b30e296 Solve 2024:25 pt 1 "Code Chronicle"
Merry XMAS!
2025-01-05 00:06:18 +01:00
2c2379788d Solve 2024:23 p1-2 "LAN Party"
Part 1 uses the excellent itertools.combinations().

Part 2 introduces Bron-Kerbosch algorithm to the
util library!
2025-01-05 00:06:18 +01:00
096c3d3e5d Solve 2024:22 p1-2 "Monkey Market"
Part 1 was relatively easy, 2 was harder.

> So, by asking the monkey to sell the *first time*
> each buyer's prices go down 2, then up 1, then
> down 1, then up 3, you would get 23 (7 + 7 + 9)
> bananas!

Emphazis mine. Earlier versions of the code missed
this fact, and added all occourences of the sequence.
providing a answer that is too high.
2025-01-05 00:06:18 +01:00
0500ac41ab Solve 2024:20 p1-2 "Race Condition"
BFS to get the path from start to end.

pt 1 took some time to wrap around, and initial
versions of the code used defaultdict() to keep
counts of all cheats to check if the example
puzzle input gace the right counts for the cheats.

But since only 100 or more was requested, a counter
do the job in the final version of the code.

For pt 2, a permutation is used.
2025-01-05 00:06:18 +01:00
14520a4625 Solve 2024:17 p1-2 "Chronospatial Computer"
Slow burner.

First part was a straightforward implementation
of a runner, the code is extracted to `org_version()`.

Part 2 was way more tricky. Like many others, trying
to understand the program felt necessary. This
intepretation is this:

    """Python version of puzzle input program."""
    a = <unknown>
    b, c = 0, 0
    while a:
        b = (a % 8) ^ 1
        c = a // (2**b)
        b = (b ^ 5) ^ c
        a = a // (2**3)
        print(b % 8)

Some clarification here:

- the value is octagonal. 1-8 is the key.
- The value of reg a is _high_. It is not meant to
be brute forced.

The idea, which is not originally mine, is to go
from right to left. This code can be used to try
out some patterns:

    while True:
        python_version(input("Provide A:"))

Here, it was apparent a=4 gives the last digit of
my puzzle input. a=37 (4 * 8 + 3) gives the last
2 digits. a=222 (37 * 8 + 6) gives the last 3
digits, and so on.

Knowing the program could be reconstructed like
this, the first code halted at wrong values. Turns
out some steps give more than 1 possible scenario.

The code was therefore in need of a queue.
2025-01-05 00:06:18 +01:00
ded5c4f28c Solve 2024:19 p1-2 "Linen Layout"
Initial tries to use a while loop instead of
recursion gave a classic AoC situation: test cases
worked, but not actual AoC puzzle input.

Turns out I only considererd removing the longest
pattern form the design, rather than consider all
possible removals.

Some Python goodies in here:

- `"abcdefgh".startswith("abc")` instead of regexp.
- removeprefix() is nice, and in some cases more
readable. `"abcdefgh".removeprefix("abc")` vs
`"abcdefgh[3:]"
- To speed things up for pt 2, functools is used
which requires a dict to be hashed as a tuple.

If one wish to solve this without recursion, a
BFS solution is most likely the way to go.

def ispossible(design, patterns):
    Q = [design]
    possible = 0
    while Q:
        remaining = Q.pop(0)
        if not remaining:
            possible += 1
            continue
        for pattern in patterns[remaining[0]]:
            if remaining.startswith(pattern):
                Q.append(remaining.removeprefix(pattern))
    return possible
2025-01-05 00:06:18 +01:00
9dc3f16766 Solve 2024:18 p1-2 "RAM Run"
BFS baby.

FIRST_BLOCKED was found manually using code from pt 1
to perform a binary search.
2025-01-05 00:06:18 +01:00
f5c3ee938a Refactor 2024:15
Solution is still 100 lines, but now it is based
on a singular BFS oriented box push algorithm.
2025-01-05 00:06:18 +01:00
7688ddb763 Solve 2024:15 p2 "Warehouse Woes"
Glad this one is over. 150 lines of pure mayhem.
2025-01-05 00:06:18 +01:00
7c2b4c835a Solve 2024:16 pt2 "Reindeer Maze"
Part 1 was easily solved by Dijkstras (using heapq).
Tricky part was to find the way to serialize the
queue items for the heappush and heappop to behave
as required.

Part 2 was incredible hard to figure out, and I
could not do it by myself. From the subreddit, it
is hinted that a traditional set of visited nodes
to determine algorithm exit would not work.

After some laboration and readin some hints, I
managed to find a solution where the code keeps
tracks using a defaultdict.
2025-01-05 00:06:18 +01:00
fbe6994e3a Solve 2024:16 pt1 "Reindeer Maze" 2025-01-05 00:06:18 +01:00
2af9dc566a Solve 2024:15 p1 "Warehouse Woes" 2025-01-05 00:06:18 +01:00
e6307795a4 Solve 2024:14 p1-2 "Restroom Redoubt"
After working overtime to solve day 12, this brief
task was a much welcome change.

For pt 1, the code uses integer division and
modulus to update all positions. The tricky part
was to determine which quadrant got the middle
column and row (since dimensions was odd numbers,
and either left or right quandrants is +1 longer),
which was straightforward to verify by the test
cases.

For pt 2, the remains of the code used to visually
identify the tree is left under the `find_easter_egg`
toggle.

Basically, the code prints the grid with
all robots marked as a `#`, and free space as `.`.`

This wording of the puzzle is important:

> very rarely, _most of the robots_ should arrange
> themselves into a picture of a Christmas tree.

"most of the robots" means the tree will be quite
visible, which also means it is safe to asume a
significant cluster of "#" would appear over time.

By keeping track of the counter (seconds the robots
has traveled), it was evident that the cluster of `#`
occoured th first time at i=64 and every 103th
time forward.

In other words, `i % 103 == 64` will most likely
give a tree. The print statement is therefore
limited to those i's, and at `i == easter_egg_appearance`
the tree is visible.

So, to be extra clear: 64, 103 and pt2 answer is
unique to my puzzle input. If this code is used
with any other puzzle input, these numbers will
most likely vary.

For the fun, the code also contains the `display_easter_egg`
flag to actually print the tree. This is provided
to indicate how big the actual tree is: 33*36 chars.

Also, the `sints` utility function was added to
extract all signed ints from a string.
2025-01-05 00:06:18 +01:00
9a7a9c878b Solve 2024:12 p2 "Garden Groups"
Funny that original 2023 day 5 also was a PITA
to figure out.

Pt 1 was solved using BFS to flood-fill. After
trying some different methods for pt 2, including:

- wallcrawling,
- side couting,
- corner counting

I never produced code to get past the test cases.

- Wall crawling are hard due to overlapping
regions.
- corner couting and side counting are both hard,
but will act as equally good solutions (since side
count equals corner count).
- Concave corners are hard, convex corners are
easy.

The final code is based on the posts on the
solutions megathread. Changes:

- Keep all areas in a set, defining a region.
- find all convex and concave corners in each
region.

A new helper got introduced: Di, storing all
diagonal neighbors for grid traversing.

Convex corners:

..  R.  .R  ..
R.  ..  ..  .R

Concave corners:

RR  .R  R.  RR
.R  RR  RR  R.
2025-01-05 00:06:18 +01:00
1e807b5daf Solve 2024:13 p1-2 "Claw Contraption"
Initial version of the code tried to solve pt 1
using BFS, which took way too long even for the
test data.

After some fiddling with algebra with pen and paper,
I realized this 2 formulaes (using first example):

94 * b1 + 22 * b2 == 840
34 * b1 + 67 * b2 == 540

*b1 = button A presses
*b2 = button B presses

... could be rewritten to this single expression:

(94 + 34) * b1 + (22 + 67) * b2 = 840 * 540

I failed to remember the algebra for solving x than
y though, that I had to learn from the subreddit.
In the code, this is the ratio part.

Also, this solution using fractions is SICK.
https://www.reddit.com/r/adventofcode/comments/1hd4wda/comment/m1tz3nf/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
2025-01-05 00:06:18 +01:00
19aee1363a Solve 2024:12 p1 "Garden Groups"
Loooong time overdue. First drafts of the code
kept track of every id separately in a defaultdict.

This was not sustainable since the code examples
had some recurring ids, and after managing to
support the test cases the code was eay off for
the real puzzle input.

In the end, the whole code was deleted and replaced
by a BFS solution that expands the current regions
until it finds no more areas.

Got the trick to count all perimiters in an else clause
from a leaderboard placed youtuber.
2025-01-05 00:06:18 +01:00
0eb961d31c Solve 2024:11 p1-2 "Plutonian Pebbles"
First part was solved using a list to store stones,
since I misinterpreted this paragraph:

> No matter how the stones change, their order is
> preserved, and they stay on their perfectly
> straight line.

But since the puzzle question do not require the
stones in the correct order, a list (or an OrderedDict)
is not required.

The pt 1 solution code got killed for eating all
RAM, so valuable minutes was lost trying to create
a generator instead. It failed. When searching for
clues, I ran across multiple people instead
utilizing dicts to count occourences. "but what of
the order?", I asked, and realized only the counts
was relevant.
2025-01-05 00:06:18 +01:00
0a812572db Solve 2024:10 p1-2 "Hoof It"
A bug in a draft version of the code accidentically
gave the answer to part 2. That's a first! :D
2025-01-05 00:06:18 +01:00
1b6502df7a Solve 2024:9 p1-2 "Disk Fragmenter"
Hard one. Comparing to earlier years, the
difficulty level seems higher than usual. I blame
the LLM hipsters.

This one I asumed, but missed when I tried to
find it:
> "If a block contains free space, skip it instead."

Lucky me.
2025-01-05 00:06:18 +01:00
dc44be89bf Solve 2024:8 p1-2 "Resonant Collinearity"
As many have said, the puzzle text this day
was a bit challenging to parse and understand.

Especially this part of pt 2 was easy to miss:

> In fact, the three T-frequency *antennas* are all
> exactly in line with two antennas,
> so *they are all also antinodes*!

not including the antennas in pt 2 gave an slightly
too low answer.
2025-01-05 00:06:18 +01:00
81fe14a407 Solve 2024:7 p1-2 "Bridge Repair"
Got thrown of big time at pt 1 since there is a
duplicate test value in my puzzle input. The code
initially asumed that all test values should be
distinct. Biased from seeing "test" in the
termology, most likely.

Earlier editions of the code also tried to create
all combinations using binary strings, but it fell
short on pt 2 when a third operation was introduced.

From some inspiration in the solutions mega
thread on Reddit, the final code is queue-based
instead. Apparently, I also learned this kind of
problem is usually well suited for DFS search, and
apparently the final code very much is _in deed_
a DFS.
2025-01-05 00:06:18 +01:00
7b2b101b8b Solve 2024:6 p1-2 "Guard Gallivant"
Pt 1 was easy, Pt 2 was pure horror.

Earlier drafts of the code tried to be way too
smart. At one point, I just came to the conclusion
to place a new obstacle (#) on the grid and just
rerun the thing to look for loops.

2 things:

- the visited positions from pt 1 can be used as a
subset for positions to consider for the extra
"#".
- The track of loops can be optimized to look at
bounces on "#"s instead of each individual y,x pos,
given that the direction is remembered.

pt 2 is familiar, the last time a puzzle required
look detection the puzzle used lazer beams and
reflectors. Not sure what Event or day it was.
2025-01-05 00:06:18 +01:00
44f6aa0f53 Solve 2024:5 p1-2 "Print Queue"
In p2, it took some tries to find a correct way
to rearrange incorrect pagesets. The code ended
up just rearranging first found incorrect order
and readding the updated pageset to queue.
2025-01-05 00:06:18 +01:00
f751b3b8d5 Solve 2024:4 p1-2 "Ceres Search"
Not gonna lie, This is not my gig skillwise. I had
much fun though!

A matrix would most likely make the code more
readable.

I relied massively on test cases here, so I share
them here instead of in the source code:

assert 1 == solve("""
    X.....
    .M....
    ..A...
    ...S..
    ..X...
    """.strip())[0]

    assert 2 == solve("""
    XS....
    .MA...
    ..AM..
    ...SX.
    ..X...
    """.strip())[0]

    assert 2 == solve("""
    ..S......
    ...A.....
    ....M....
    .....X...
    ..X...M..
    .......A.
    ........S
    """.strip())[0]

    assert 4 == solve("""
    X.SS
    M.AA
    A.MM
    S.XX
    ...M
    ...A
    ...S
    """.strip())[0]

    assert 4 == solve("""
    ...X...
    ...M...
    .X.A...
    XMASAMX
    .A.....
    .S.....
    """.strip())[0]

    assert 1 == solve("""
    ....X
    ...M.
    ..A..
    .S...
    """.strip())[0]

    assert 2 == solve("""
    ...SX
    ..AM.
    .MA..
    XS...
    """.strip())[0]

    assert 2 == solve("""
    ......X
    .....M.
    ....A..
    ...S...
    ..A....
    .M.....
    X......
    """.strip())[0]

    assert 1 == solve("""
    M.S
    .A.
    M.S
    """.strip())[1]

    assert 1 == solve("""
    M.M
    .A.
    S.S
    """.strip())[1]

    assert 1 == solve("""
    S.M
    .A.
    S.M
    """.strip())[1]

    assert 1 == solve("""
    S.S
    .A.
    M.M
    """.strip())[1]

    assert 1 == solve("""
    S.S
    .A.
    M.M
    """.strip())[1]

    assert 1 == solve("""
    .A.
    M.M
    .A.
    S.S
    """.strip())[1]

    assert 1 == solve("""
    M.M.
    .A.A
    S.S.
    """.strip())[1]

    assert 1 == solve("""
    M.M
    .A.
    S.S
    .A.
    """.strip())[1]

    assert 1 == solve("""
    .M.M
    A.A.
    .S.S
    """.strip())[1]
2025-01-05 00:06:18 +01:00
cb622409f9 Solve 2024:3 p1-2 "Mull It Over"
Felt paranoid on this one, was expecting something
much worse for pt2.

The code that solved the puzzle was _extremely_
naive:

- It asumes puzzle input only contains mul() with
1-3 chars. The versioned code have `{1,3}` as safe
guard.
- p2 asumed initial chunk does not begin with
"n't". Would have been easy to handle though.
- p2 asumed junk strings as "don", "do", "don()t"
would not exist.

In other words, I was really lucky since I did not
look that closely on puzzle input beforehand.

Might have cut 60-90 seconds further if I had just
ran pt2 immidately instead of staring dumbly on the
test data (that changed for pt2).

Also, I got reminded that \d in regular expressions
is equal to `0-9`: it does not include commas and
punctations. The code that solved the puzzle was
paranoid and instead used `0-9`.

Managed to score ~1500th somehow despite this.
2025-01-05 00:06:18 +01:00
5deb351504 Solve 2024:2 p1-2 "Red-Nosed Reports"
DDOS of adventofcode.com, did not get to open the
puzzle until 06:05 (five minutes local time).

Screwed up the zip() and lost valuable minutes by
trying to replace it with itertools, only to find
I have made a typo (did AB CD EF instead of AB BC
CD).

I also lost valuable minutes by tring to solve p1
with one nested loop. Stupid.

For part 2, I created the issafe() helper to be
able to remove items from reports and test, one
at the time.
2025-01-05 00:06:18 +01:00
81741232af Solve 2024:1 p1-2 "Historian Hysteria"
Realized afterwards I got the ints() helper, so
original code before cleanup splitted the input and
mapped all words with int(). valuable seconds lost
there.

Also, collections.Counter() was used initially since
I was too tired to remember count() method in lists.

Line 8 took the longest time to figure out. A typo
took 1-3 minutes to find for part 2.

Form: Sleep deprived, felt slow.
2025-01-05 00:06:18 +01:00
cb50d62e3f Prepare for AOC 2024
Python, again.

10th year anniverary.
2025-01-05 00:06:18 +01:00
d02f63a4ef Solve 2016:22 p2 "Grid Computing"
Solved by hand by visualizing the filesystem as
a grid, and put into a simple formula.

In Sweden, this is called a "Femtonspel".
https://sv.wikipedia.org/wiki/Femtonspel
2024-12-12 13:53:43 +01:00
8aa6363b9f Solve 2016:25 p1 "Clock Signal"
Did brute force, but earlier drafts of the code
failed to exit the while loop correcly.

By manual testing, an odd number is required in reg
a to set the first output to 0 (for my puzzle
input at least). Hence, only odd numbers are tested.
2024-12-12 13:53:43 +01:00
abaec4231f Solve 2016:24 p1-2 "Air Duct Spelunking"
BFS baby.
2024-12-12 13:53:43 +01:00
525c6aa96c Solve 2016:23 p1-2 "Safe Cracking"
Solution cide works, but is slow. According to the
subreddit, pt 2 is meant to be an exercise in
optimization.

Turns out the assembly instructions do a factorial,
i.e 7! and 12! and adds a salt (5840).

Got that spoiled. :)
2024-12-12 13:53:43 +01:00
c33bdc3f02 Solve 2016:22 p1 "Grid Computing"
Pt 2 are meant to solved by hand. Will do that
from the print I got.
2024-12-12 13:53:43 +01:00
e75670eaf2 Solve 2016:21 p1-2 "Scrambled Letters and Hash"
A good day to utilize lots of unit testing!

For pt 2, the code initially tried to reverse
the scramble algorithm. The final code however
got the unscrambled version by the traditional
method most password crackers would resolve to:
basic brute forcing with permutations as a list
of candidates.
2024-12-12 13:53:43 +01:00
63da79b2a4 Solve 2016:20 p1-2 "Firewall Rules"
The code at one time used cached responses for
in range bools, but it seems that does not improve
performance.

Some IP addresses are allowed multiple times, so
min() and set() are used to find the distinct
values.
2024-12-12 13:53:43 +01:00
39e09dd36e Solve 2016:19 p1-2 "An Elephant Named Joseph"
Learned a lot about the Josephus' Problem today!

Solved part 1 by using a dict, but eventually
ended up just adding the mathematical shortcut
and rewriting both parts to use deque() for
performance.

Part 2 was tricky, since k (the elf to remove
after all presents were stolen from them) is a
index that changes over time. No tries for a
solution that was performant enough using lists
and dicts were succesfull, so by inspiration from
the subreddit the final solution code is based on
2 deque() that pops and appends between them.

There are 2 part 1 solutions.

- A correct implementation of the Josephus' Problem,
  using deque(). Recursion would have worked as well,
  but Python do not like recursions.
- The mathematical superior version, with a link
  to the Youtube video were it is introduced.
2024-12-12 13:53:43 +01:00
ae942ce803 Solve 2016:18 p1-2 "Like a Rogue"
Figured out that the center position did not matter,
as long as left hand side tile and right hand side
tile on previous row are not equal.

Also tried to find a recurring pattern to speed
p2 up a bit, but it seems it does not have a
recurring pattern in the 400 000s first rows.
2024-12-12 13:53:43 +01:00
ffc5088813 Improve aoc helper script 2024-12-12 13:53:43 +01:00
3170846595 Solve 2016:17 p1-2 "Two Steps Forward"
Generators baby.
2024-12-12 13:53:43 +01:00
63a7ccd0e2 Simplify scaffold code 2024-12-12 13:53:43 +01:00
cdd5f63be4 Solve 2016:16 p1-2 "Dragon Checksum" 2024-12-12 13:53:43 +01:00
623253ac9d Solve 2016:15 p1-2 "Timing is Everything"
Good TIME to be a Python programmer!
2024-12-12 13:53:43 +01:00