Giter Club home page Giter Club logo

aoc's Introduction

Advent of Code

Personal repository of Advent of Code solutions.

Quick links

About Advent of Code

Advent of Code is an Advent calendar of small programming puzzles for a variety of skill sets and skill levels that can be solved in any programming language you like. One programming puzzle a day is released from 1st to 25th December, divided in two parts (the second of which is unlocked after solving the first). Advent of Code is created by Eric Wastl, and is 100% free. If you like Advent Of Code and want to support its creator, you can donate to him here. If you want to hang out with other fellow coders, discuss about puzzles and solutions, or just have a look around, you can join the official subreddit: r/adventofcode, or the unofficial IRC channel: #adventofcode on irc.libera.chat, where you can also find me at the right time of the year.

About this repository

I discovered Advent of Code in 2017, and played my first edition in 2018. In this repository you can find my solutions and walkthroughs for the puzzles as well as other miscellaneus stuff like visualizations and other scripts.

In each year's directory you will find:

  • README.md: an in depth walkthrough of my (clean) solutions for the puzzle, day by day, with references to used algorithms and data structures and sometimes also comments/reflections.

  • solutions/: clean solutions for the puzzles. I usually rewrite, polish and optimize my original solutions whenever I have time after my first solve, along with a detailed walkthrough.

  • original_solutions/: my almost unedited original solutions for the puzzles, written as fast as I could while trying to solve puzzles for the first time. These solutions may use helpers I defined in my own utils module, as well as other external modules to make things easier. Do not expect the code in here to be sane/readable/fast[1].

  • lib/: small library of utilities written for this specific year. There are recurring concepts and problems each year. If needed, this directory will hold common code used by multiple solutions.

  • misc/: anything else interesting. This includes image/video visualizations of puzzles, additional interesting scripts, alternative solutions, and so on.

    • full_leaderboard.md: a complete leaderboard of all participants of Advent of Code for the year, including those who did not make it to the top 100, built by scraping each day's leaderboard.
    • calendar.gif: a GIF of the animated complete calendar for the year. That is, if I managed to finish all puzzles.

[1] I chose to upload "original" versions of solutions for two reasons: they are a good and fun way to see how I code, and they can be uploaded as soon as the leaderboard for the day is complete, as I often don't have time to rewrite them more cleanly right away.

How to run my solutions

Provide your input from standard input:

2022/solutions/day01.py
# Paste input here and type CTRL+D when done...

Save your input to file and pass its path as argument:

2022/solutions/day01.py path/to/your/input.txt

Directly download your input from the AoC website (you will need to extract your session cookie from your browser and replace VALUE below with the real value, please only do this if you understand what you are doing):

curl -s --cookie 'session=VALUE' 'https://adventofcode.com/2022/day/1/input' | 2022/solutions/day01.py

Contributing

If you have question or spotted a typo/bug/mistake, you are most welcome to submit a new issue. For pull reqeusts and other kinds of contributions, please read CONTRIBUTING.md.

Licensing

The content of this repository, with the exception of walkthroughs (as defined in and linked at the top of this document), is licensed under the Apache License 2.0 license, which you can find in the file LICENSE.Apache-2.0. Walkthroughs are licensed under the Creative Commons BY-NC-SA 4.0 license, which you can find in the file LICENSE.CC-BY-NC-SA-4.0.


Copyright ยฉ 2018-2023 Marco Bonelli.

aoc's People

Contributors

mebeim avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aoc's Issues

Typo in y2023 d16 walkthrough

First version of travel function in walkthrough looks follows:

...

while 1:
    # Are we out of bounds?
    if 0 <= r < height and 0 <= c < width:
        # Can't possibly continue!
        break

    # Dif we already get here while also going in the same direction?
    if (r, c, dr, dc) not in seen:
        # This is a loop!
        break

    ...

But these conditions must be inverted:

 while 1:
     # Are we out of bounds?
-    if 0 <= r < height and 0 <= c < width:
+    if not (0 <= r < height and 0 <= c < width):
         # Can't possibly continue!
         break

     # Dif we already get here while also going in the same direction?
-    if (r, c, dr, dc) not in seen:
+    if (r, c, dr, dc) in seen:
         # This is a loop!
         break

optimize iterations in day24 part 2

hello @mebeim ๐Ÿ‘‹ ,

In today's puzzle part2, I noticed that for the rule

Any white tile with exactly 2 black tiles immediately adjacent to it is flipped to black.

you iterate over much more tiles than you could :

def bounds(grid):

you could restrict your iteration over the neighbors of the neighbors of your black tiles, cf my implem here :

https://github.com/edelans/aoc2020/blob/933ae61307ad48b38b3aacdbc1e211d4f33b1937/day24.py#L73,L79

thanks again for your clean walkthrough, and buon Natale !

Day 10 - Adapter Array Part 1: Problem with the variables initialization

Hi,

First of all, I would like to thank you for your solutions to AoC, it's amazing to have this resource, I am checking my own solutions against your code constantly and learning a lot.

I think there might be a small issue with 2020 Day 10 Part 1, particularly this sentence:

Beware though: the first time we find a match (for distance 1 and 3) it means we actually have two numbers matching.

I'm not sure what you meant by that, but I don't think that's right.

I think you are supposed to initialize the counters at zero, and that the reason your code happens to work because in your input, by chance, the first adapter has a value of 1.
See, since you didn't add the charging outlet (joltage == 0), nor the built-in joltage adapter (joltage == max(input) +3), to your nums (You did it in part 2, but you were also supposed to do it in part 1), you are missing a count of 1 and a count of 3. (Which you hard coded in your counter variables by initializing them with 1)

I really hope I didn't make a mistake, and thank you again for this repo, I'm not exaggerating when I say that I've been using it daily for the past month. Cheers

typo "as weel"

I'm not farming internet points, just thought I'd point it out if it was helpful.

top and at the bottom of the grid, as weel as two columns of empty cells on the

Day 19 walkthrough explanation is different than rule

In the walkthrough for Day 19, the example rule 0 is 1 2 | 2 3. But in the second paragraph after the example, it starts treating it as 1 2 | 1 3:

this second option of rule 0 means "match a followed by b followed by a"

This should be "match b followed by b followed by a"

Also, the tree shows 1 2 | 1 3.

Enhanced? Solution for 2021/10

In Part2 you iterate over the stack to get a value for result.
You can cast the stack as an integer, like following:

int(''.join(stack).translate(str.maketrans(')]}>', '1234'))[::-1], 5)

maybe its not good readable, so it not might be enhanced

Method name is incorrect in 2019 day 18 write-up.

After "Here's the updated function:" in the 2019 Day 18 write-up, the method name is still minimum_steps but should be explore.

Thanks so much for doing these write-ups. They are a generous contribution to the AoC community. When I get stuck on an advanced problem I always know I'll learn something by coming here.

Typo in y2023 d17 walkthrough

In y2023 d17 pt2 walkthrough should be

-    for _ in range(1, 3 + 1):
+    for i in range(1, stop + 1):

instead of

-    for _ in range(1, 3 + 1):
+    for i in range(start, stop + 1):

day3, answer 2 - missing sum

answer2, day 3 - Is the condensed version missing a sum?

answer2 = map(prod, filter(lambda x: len(x) == 2, gears.values())))
print('Part 2:', answer2)
- answer2 = map(prod, filter(lambda x: len(x) == 2, gears.values())))
+ answer2 = sum(map(prod, filter(lambda x: len(x) == 2, gears.values()))))
print('Part 2:', answer2)

Love going through your solutions after I attempt mine!

Typo in 24/2022 solution

Noticed a typo here: the second bfs stores the updated blizzard as blitz instead of bliz, so it is not passed to the third bfs.

2021 Day 22 code

I tried to implement this code below for Part2 and found it did not work for me. I had to compute the intersections for both positive and negative without mutating the lists in the middle of the loop(i.e. by keeping new_positive and new_negative lists and appending them to positive and negative at the bottom of the main loop). I apologize if I have misunderstood your code/Python and thanks so much for your excellent walkthroughs.

positive = []
negative = []

for on, cuboid in commands:
    for other in positive:
        inter = intersection(cuboid, other)
        if inter is None:
            continue

        negative.append(inter)

    for other in negative:
        inter = intersection(cuboid, other)
        if inter is None:
            continue

        positive.append(inter)

    if on:
        positive.append(cuboid)

keep it up !

Hello @mebeim ,

Your repo has become my go to place once I complete my challenge of the day (it used to be reddit, then I saw your repo there, and I switched my habbit instantly : I โค๏ธ your walkthrough, you manage to add a lot of value to the code, with plenty of references (docs, wikipedia, general knowledge...) that help me expand my knowledge more efficiently than reading dry code lines on reddit.

I was surprised not to find your solution today, so I though I would send you some thankfulness =) : just in case you are wondering if the efforts your are putting in on a daily basis are worth it, I can tell you that there is at least one person who cares =). I have that (working) ugly part2 that needs fixing https://github.com/edelans/aoc2020/blob/master/day16.py : I'm looking forward to read yours.

Keep it up !

Day 23, build_list , index out of bounds error

Hi Marco,This is my first time participating in the AOC and I'm learning how to code. I found your problem walkthroughs immensely helpful. I like how you explain the logic and the code simultaneously.

Issue with the build_list function in the line below:

next_cup = [None] * len(cups)

This initializes a list of the size of cups (9 in our case). This means next_cup has indices going from 0 to 8. This gives the _index out of bounds _ error on line 9 of the day23.py script.

When the input is 123487596, the loop below

for prev, cur in zip(cups, cups[1:]):
		next_cup[prev] = cur

has next_cup[9] = 6. But since next_cup has indices only till 8, we get an index out of bounds error. I have found a small work around for this issue in the code snippet below.

def build_list(cups, n_nums = None):
    next_cup = [None]*(max(cups) + 1) #I add the +1 so that we dont have to use the 0 index
    for prev,cur in zip(cups, cups[1:]):
        next_cup[prev] = cur
    if n_nums is not None:
        #Below two lines add the extra, consecutive cups
        next_cup[cups[-1]] = len(next_cup) 
        next_cup += list(range(len(next_cup)+1, n_nums+2))
        next_cup[n_nums] = cups[0] #This line makes sure that the 'clockwise arrangement' rule is obeyed
        return next_cup
    next_cup[cups[-1]] = cups[0] #This line makes sure that the 'clockwise arrangement' rule is obeyed
    return next_cup 

I added comments where the changes have been made. This does not alter your logic, but just takes care of the above issue. It would be awesome if you can simplify the above correction ๐Ÿ‘
Please let me know if I have made a mistake in the above issue.

Thanks!
Hema

Question about Day 07

Hello,

I was wondering if you could please kindly look at my code, an attmept to solve AoC puzzle on Day 07 and maybe give me a little hint what am I doing incorrectly? I am not sure where I am making a mistake and I feel like I am close to solution and yet no there.
I would be very grateful for your help and I hope I am not violating rules on your repository with this question. Apologies if I do.

Thank you,
Ewa

Speedup of day 16

Thanks for a nice explanation of the reverse cumsum approach for part 2!

You complain about the speed, but it can if fact be speeded up even further:
Since we know we are only going to look at a small part of the whole list, we don't need to copy the input 10_000 times. With my input, I only had to copy it 806 times.
This function solves my input in 7s with standard Python:

def part2(input_string, phases=100):

    # Find the start index and convert input to list of ints
    start_index = int(input_string[:7])
    numbers = list(map(int, input_string))

    # Make sure that start index is indeed in the second half,
    # otherwise the trick won't work
    assert start_index > len(input_string)*10_000 / 2
    
    # We are only going to compute the numbers from just before start_index
    # to the end (in reverse). So we don't need to copy the input 10_000 times.
    n_repeats = (len(input_string)*10_000 - start_index ) // len(input_string) + 1
    
    # Compute new start index for this shorter list:
    start_index -= (10_000 - n_repeats)*len(input_string)
    
    numbers = numbers*n_repeats
    for _ in range(phases):
        cumsum = 0
        for i in range(len(numbers) - 1, start_index - 1, -1):
            cumsum += numbers[i]
            numbers[i] = cumsum % 10
            
    return "".join(map(str, numbers[start_index:start_index + 8]))

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.