/r/adventofcode

Photograph via snooOG

Advent of Code is an annual 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.

🎄 Advent of Code 🎄

Advent of Code is an annual 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.


Rules + More Info in

our community wiki


BEFORE YOU POST
If your post is even tangentially related to a daily puzzle, use our
STANDARDIZED POST TITLE FORMAT

Solution Megathreads

December 2023

Su M T W R F Sa
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Previous years:
2022 | 2021 | 2020 | 2019 | 2018 | 2017 | 2016 | 2015

Quick Search by Flair

Because you're lazy and we like making things easy for you. Except AoC.

Are you enjoying AoC?

Code should be fun, because otherwise it's just a job. If you'd like to support Advent of Code, please share it with all your friends, even the ones that are just learning to code! AoC is a fun, non-threatening way to work at your own pace to figure out how to apply problem-solving first, then work within a language's constraints.

If you really want to show your appreciation, donations are always appreciated. Any instances of currency will go to, in no particular order:

  • Server maintenance (hosting, bandwidth, etc.)
  • Bribes to Santa
  • Beer and sushi
  • Paper bags for /u/topaz2078 to breathe into so he doesn't hyperventilate onto another plane of (non-)existence

Support AoC

Thank you very much, and enjoy your month of code!

/r/adventofcode

120,560 Subscribers

2

[2016 Day 17 (Part 2)] Python - Code works for all examples but answer is wrong?

I'm going back through previous years and for some reason I can't figure out why I'm getting a wrong answer on this one. I've tested all 3 of the example inputs and get a correct answer for those, but when testing for my puzzle input it says my answer is too low. Any hints or pushes in the right direction would be great, thanks!

Here is the code:

import hashlib

inp = 'ioramepc'
len_shortest_path = float('inf')
shortest_path = ''
len_longest_path = 0
def possible_options(cur_hash):
    hash_set = hashlib.md5(cur_hash.encode()).hexdigest()[:4]
    good_codes = 'bcdef'
    possibles = []
    # Up
    if hash_set[0] in good_codes:
        possibles.append(('U', 0, -1))
    # Down
    if hash_set[1] in good_codes:
        possibles.append(('D', 0, 1))
    # Left
    if hash_set[2] in good_codes:
        possibles.append(('L', -1, 0))
    # Right
    if hash_set[3] in good_codes:
        possibles.append(('R', 1, 0))
    return possibles


def traverse(cur_loc, cur_path):
    global len_shortest_path
    global shortest_path
    global len_longest_path
    possibles = possible_options(inp + cur_path)
    if len(possibles) == 0:
        return False, []

    found_end = False
    paths = []
    for direction, x, y in possibles:
        if cur_loc[0] + x < 0 or cur_loc[0] + x >= 4 or cur_loc[1] + y < 0 or cur_loc[1] + y >= 4:
            continue
        if (cur_loc[0] + x, cur_loc[1] + y) == (3, 3):
            found_end, possible_path = True, cur_path + direction
            paths.append(possible_path)
        else:
            found_end, paths = traverse((cur_loc[0] + x, cur_loc[1] + y), cur_path + direction)

    if found_end:
        my_shortest_path = min(paths, key=len)
        my_longest_path = max(paths, key=len)
        if len(my_shortest_path) < len_shortest_path:
            len_shortest_path = len(my_shortest_path)
            shortest_path = my_shortest_path
        if len(my_longest_path) > len_longest_path:
            len_longest_path = len(my_longest_path)
        return True, paths
    else:
        return False, []


traverse((0, 0), '')
print(shortest_path)
print(len_longest_path)
3 Comments
2024/11/02
07:07 UTC

12

How to train for Advent of Code?

Hello Folks,

I recently discovered Advent of Code and based of all discussion I have read here, it seems like this place is not people who are new to problem solving in general. However, I want to learn/train to be able to solve these questions.

If possible, I would love any insights or guidance on this one! It is November 1 so is it a decent time to start training still? I am able to do even a few AoC problems I will be happy.

Thank You

34 Comments
2024/11/01
19:53 UTC

26

Are you already training for this year?

Well, just curious about how do you plan for AoC, if case you plan anything at all.

As I do it in F# as is not my daily programming language, I use it mostly for side projects when I have some time and for AoC, I already started to do some excercises from previous years, to get used again to the text parsing, regex, basic stuff...

37 Comments
2024/11/01
11:14 UTC

2

[2018 Day 21] How is the bitwise verification done?

How do I verify `bani`? All inputs for the operations are numbers. So how could it be not a 'numeric bitwise'? I'm probably lacking understanding of bitwise in general or I completely missed something.

4 Comments
2024/11/01
10:18 UTC

0

[2023 day 5 (part 2)] need help with the code

https://pastebin.com/9t045ZFA

i dont understand what im doing wrong

could smone please help

11 Comments
2024/10/31
14:29 UTC

2

[2023 day 5 (part 2)]i am an idiot smone pls let me know what im missing

seeds: 79 14 55 13

seed-to-soil map:
50 98 2
52 50 48

In the above example, the lowest location number can be obtained from seed number 82, which corresponds to soil 84, fertilizer 84, water 84, light 77, temperature 45, humidity 46, and location 46. So, the lowest location number is 46.

doesnt the 82nd seed in the example correspond to the 80th soil.

cause (82 - 52) + 50 which is equal to 80 but it says 84

what did i not understand right

10 Comments
2024/10/31
07:45 UTC

2

[2015 Day 2 Part 2] [C] What am I doing wrong???

int getRibbon(char stuff[]){
  int l, w, h, ribbon, slack, side;
  sscanf(stuff, "%dx%dx%d", &l, &w, &h);
  printf("\nlength: %d\nwidth: %d\nheight: %d", l, w, h);
  side = l;
  if (side < w){
    side = w;
  } 
  if (side < h){
    side = h;
  }
  printf("\nlongest side: %d", side);
  if (l != side){
    slack += l*2;
  }
  if (w != side){
    slack += w*2;
  }
  if (h != side){
    slack += h*2;
  }
  printf("\ngift volume: %d", l*w*h);
  printf("\nextra ribbon: %d", slack);
  ribbon = l*w*h;
  ribbon += slack;
  printf("\nall ribbon: %d", ribbon);
  return ribbon;
}

int main() {
  int allPaper;
  int allRibbon;
  FILE *input;
  input = fopen("input.txt", "r");
  char get[20];
  if(input != NULL) {
    while(fgets(get, 20, input)) {
      allRibbon += getRibbon(get);
    }
  } else {
    printf("dookie");
  }
  fclose(input);
  printf("\n%d", allRibbon);
}

I genuinely don't know what's wrong with this, it's my 9th incorrect input, and I'm struggling to find out how my code is incorrect.

9 Comments
2024/10/30
20:44 UTC

1

[2018 Day 24 Part 1] What am I missing?

Link to the puzzle

Link to my code (Perl)

I've been on this one for several days. I keep getting the wrong answer and I am really not sure why. Every time I rewrote my code it all worked fine for the example input, but for the actual input it just says I get the wrong result.

It's probably a problem with ties, but I think I have taken them into account.

This is how I understand the logic:

- Target selection order:

-- Groups choose based on units*dmg, descending (not counting ties). Group A will select a target before group B/C/X/Y/Z because it has the highest units*dmg.

-- If group B and group C have the same units*dmg, the group with the higher initiative will choose first

-- Groups with 0 unit will not choose a target

- Target selection phase:

-- Group A selects its target based on how much damage it deals them, counting weaknesses and immunities

-- If Group A deals the same damage to X and group Y, it will favour group X because it has the higher units*dmg (immunities and weaknesses are ignored for this tie breaker)

-- If Group A deals the same damage to group X and group Z and they also have the same units*dmg, group A will select the group with the higher initiative, let's say group Z.

-- Group Z cannot be targetted by anyone else

- Attack phase

-- Groups attack in order of initiative, descending

-- Groups with 0 unit do not attack (they do not have a target anyway)

-- Attack damage is dealt to the defender, units are killed, a partially harmed unit is considered not damaged. Unit count is updated for the defender.

This is all the logic I can think of, and I am pretty sure that I implemented it all. What am I missing?

Sincere thanks in advance.

Edit: found a mistake in my code where effective power was calculated with hp*dmg instead of quantity*dmg, but it is still not giving the right solution. Updated the link.

Edit2: found the problem! My eyes completely glossed over the sentence in bold for the three times I wrote the code from scratch:

If an attacking group is considering two defending groups to which it would deal equal damage, it chooses to target the defending group with the largest effective power; if there is still a tie, it chooses the defending group with the highest initiative. If it cannot deal any defending groups damage, it does not choose a target. Defending groups can only be chosen as a target by one attacking group.

In my logic, dealing 0 to every target still made the group select the target based on tie breakers. Once I implemented "If damage is 0, don't consider this target", it worked.

7 Comments
2024/10/30
12:38 UTC

2

[2015 Day 6 (Part 2)] [C#] Confused what I'm doing wrong

I'm a bit stuck on this one. I feel like my code should be right, but it's saying my answer is too low. Any pointers in the right direction is appreciated.

Here's my code (probably not the most effiecient, but I'm going for readability and reusability over efficiency):

public override int Execute2()
{
    using var percentageReporting = new PercentageReporting("Day 6.2");

    var count = 0;
    var grid = new Grid<Light>(1000, 1000, (x, y) => new Light(x, y));

    foreach (var line in Lines)
    {
        if (line.StartsWith("turn on"))
        {
            _executeCommand(grid, line, "turn on", light => light.Brightness += 1);
        }
        else if (line.StartsWith("toggle"))
        {
            _executeCommand(grid, line, "toggle", light => light.Brightness += 2);
        }
        else if (line.StartsWith("turn off"))
        {
            _executeCommand(grid, line, "turn off", light =>
            {
                light.Brightness -= 1;
                Math.Max(light.Brightness, 0);
            });
        }
        else
        {
            throw new Exception("Unknown command");
        }

        count++;
        percentageReporting.SetPercentage((double)count / Lines.Count * 100);
    }

    return grid.List.Sum(l => l.Brightness);
}

private static void _executeCommand(Grid<Light> grid, string line, string command, Action<Light> action)
{
    var trimmedLine = line.Replace(command, "").Trim();
    var parts = trimmedLine.Split("through");
    var from = parts[0].Trim();
    var to = parts[1].Trim();

    var fromParts = from.Split(',');
    var toParts = to.Split(",");

    var startX = int.Parse(fromParts[0].Trim());
    var startY = int.Parse(fromParts[1].Trim());
    var endX = int.Parse(toParts[0].Trim());
    var endY = int.Parse(toParts[1].Trim());

    var lights = grid.GetTilesIn(startX, startY, endX, endY, inclusive: true);

    foreach (var light in lights)
    {
        action(light);
    }
}

private class Light(int x, int y) : ITile
{
    public int X { get; } = x;

    public int Y { get; } = y;

    public bool IsOn { get; set; } = false;

    public int Brightness { get; set; } = 0;
}

The relevant parts of my Grid class:

public class Grid<T>
    where T : ITile
{
    public List<T> List { get; } = [];
    
    public Grid(int width, int height, Func<int, int, T> tileCreator)
    {
        for (var x = 0; x < width; x++)
        {
            for (var y = 0; y < height; y++)
            {
                List.Add(tileCreator(x, y));
            }
        }
    }
    
    public ICollection<T> GetTilesIn(int startX, int startY, int endX, int endY, bool inclusive)
    {
        return List
            .Where(t => t.X >= startX)
            .Where(t => t.Y >= startY)
            .Where(t => t.X < endX || (inclusive && t.X <= endX))
            .Where(t => t.Y < endY || (inclusive && t.Y <= endY))
            .ToList();
    }
}

5 Comments
2024/10/30
09:58 UTC

1

2015 Day 7 Part 1 [python]

Im getting the wrong answer for part 1.

Here is my code:

from numpy import int16

with open("input", "r") as inputText:
    instructions = inputText.readlines()

circuit: dict = {}
processed: list[str] = []
backlog: list[str] = []
while processed != instructions:

    for instruction in instructions:
        if instruction not in processed and ((instruction not in backlog) and (backlog + processed != instructions)):

            connections: list[str] = instruction.split(" -> ")
            target: str = connections[1].rstrip()
            source: str = connections[0]

            try:

                if "AND" in source:
                    operands = source.split(" AND ")
                    try:
                        operands[0] = int16(operands[0])
                        circuit[target] = int16(operands[0] * circuit[operands[1]])
                    except ValueError:
                        circuit[target] = int16(circuit[operands[0]] & circuit[operands[1]])

                elif "OR" in source:
                    operands = source.split(" OR ")
                    circuit[target] = int16(circuit[operands[0]] | circuit[operands[1]])

                elif "NOT" in source:
                    circuit[target] = int16(~ circuit[source.split(" ")[1]])

                elif "LSHIFT" in source:
                    operands = source.split(" LSHIFT ")
                    try:
                        operands[1] = int16(operands[1])
                        circuit[target] = int16(circuit[operands[0]] << operands[1])
                    except ValueError:
                        circuit[target] = int16(circuit[operands[0]] << circuit[operands[1]])

                elif "RSHIFT" in source:
                    operands = source.split(" RSHIFT ")
                    try:
                        operands[1] = int16(operands[1])
                        circuit[target] = int16(circuit[operands[0]] >> operands[1])
                    except ValueError:
                        circuit[target] = int16(circuit[operands[0]] >> circuit[operands[1]])

                else:
                    try:
                        source = int16(source)
                        circuit[target] = source
                    except ValueError: circuit[target] = int16(circuit[source])

            except KeyError: continue

    print(circuit)
11 Comments
2024/10/29
11:44 UTC

3

Question about third-party code

Are contestants allowed to use third-party code, such as third-party libraries in Python and algorithm source code on GitHub?

13 Comments
2024/10/29
00:46 UTC

133

450 Stars: A Categorization and Mega-Guide

I'm making a list,
And checking it twice;
Gonna tell you which problems are naughty and nice.
Advent of Code is coming to town.

 

In previous years, I posted a categorization and guide to the then-extant problems. The 2024 AoC has been announced, so once again I'm back with another update to help you prepare.

As before, I have two purposes here. If you haven't finished all the previous problems from past AoC events, then maybe this will help motivate you to find some good problems to practice on a particular topic. And if you have completed all the problems, this will serve as a handy reference to look up your previous solutions, given the total of 225 days of problems. (Whew!)

Looking over the AoC 2023 problems, I noticed that we didn't really have any major BFS, logic/constraint, or VM type puzzles last year. I expect we may be due for some this year.

I'll list each category with a description of my rubric and a set of problems in increasing order of difficulty by Part Two leaderboard close-time.

New to this year's update, I've added another category for warmup problems for some of the easier early days that aren't especially tricky. Most of these were previously under the math category since they just required a bit of arithmetic. I've also clarified that area and volume computations and spatial data structures fall under the spatial category. And to give an idea of relative difficulty, the lists now include the Part Two leaderboard close-times to give a better idea of the relative difficulty. Unfortunately, I've now had to move the categories down into groups within individual comments due to Reddit post size limits.

I'll also share some top-ten lists of problems across all the years, plus rankings of the years themselves by various totals. And since it's been asked for before, I'll also preemptively share my raw data in CSV form.

Finally, as before, I'll post each year with a table of data:

Best of luck with AoC 2024!

32 Comments
2024/10/28
07:08 UTC

12

[2016 D08, 2018 D10, 2019 D08+11, 2021 D13, 2022 D10] python package + CLI tool for character recognition in ASCII art outputs

I made a small tool to parse the ASCII-artsy letters which are used to represent the solutions for some of the puzzles.

It can be used from the command line by passing data via stdin to `aoc-ocr`, or it can be imported in a python script with `from aococr import aococr`. The latter works (at least in my tests) on strings, lists of lists of characters, and numpy arrays, and has no external dependencies.

There were a few similar projects out there, including this one by u/mstksg, who had collected the various ASCII-glyphs, but I couldn't find one which a) used python, b) supported the larger glyphs from 2018, and c) didn't depend on any large OCR frameworks, so I decided it would be a fun challenge to make and package in case anyone else found it helpful.

The package is on PyPi here and the source code is on Github here. Never published a package before, so feel free to point out any noobie mistakes.

3 Comments
2024/10/26
15:29 UTC

8

[2023 Day 17 (A)] Python: How to add direction restriction to A*?

Hi, I went with A* for this one but now I am struggling with the restriction of max 3 steps in one direction. I tried to keep track of the steps taken and ignored neighbours which violate this restriction and I am aware that this could lead to a suboptimal path but could not figure out yet how to keep the restriction and still find the cheapest path. Any help is appreciated!

https://github.com/Jens297/AoC/blob/main/17a.py

https://github.com/Jens297/AoC/blob/main/node.py

8 Comments
2024/10/26
13:26 UTC

4

[2023 d20 p1] wrong input O_O ?

I'm solving day 20 of aoc 2023, part 1. My test passes, but the actual input doesn't, because... it seems my input is wrong. This never happened in quite a few years I'm solving the AoC, but still...

In my input, there's a line

&ls -> rx

but a module named "rx" doesn't exist - it is never listed on the left hand side of the "->" mapping.

Am I getting something terribly wrong or is it really a bug in the input?

10 Comments
2024/10/25
19:58 UTC

122

Advent of SQL: 24 Days of PostgreSQL Challenges

I wanted to share a fun project I've been working on for this December. It's a SQL flavoured variation of advent of code - 24 SQL challenges using PostgreSQL, running from December 1st to 24th.

Here's the gist:

  • One PostgreSQL challenge per day
  • Starts December 1st, ends December 24th
  • Purely SQL-based problems (no other languages involved)
  • Designed to be fun and (hopefully) educational for various skill levels

I'm creating this because I love SQL and thought it'd be a cool way for the community to sharpen their skills or learn something new during the holiday season.

I'd also love to hear your thoughts or suggestions!

Here's the site, I hope you enjoy it!

adventofsql.com

If anyone is interested the site is built in Elixir with LiveView.

31 Comments
2024/10/24
10:07 UTC

1

[2023 Day 17 (Part 1)] [Python]

Hi, I need help for my code. When I run the test case, I get the wrong answer but I don't know what's wrong

puzzleinput=[list(row) for row in puzzleinput.split('\n')]

def getNeighbours(index):
    i1,i2=index
    if i1>0:
        yield (i1-1,i2),-1,0
    if i1<(len(puzzleinput)-1):
        yield (i1+1,i2),1,0
    if i2>0:
        yield (i1,i2-1),0,-1
    if i2<(len(puzzleinput[0])-1):
        yield (i1,i2+1),0,1


def djikstraMod():
    weights=dict.fromkeys(((row,column) for row in range(len(puzzleinput[0])) for column in range(len(puzzleinput))),inf)
    visited={(0,0),(0,1),(1,0)}
    weights[(0,0)]=0
    weights[(0,1)]=puzzleinput[0][1]
    weights[(1,0)]=puzzleinput[1][0]
    previous=dict.fromkeys(((row,column) for row in range(len(puzzleinput[0])) for column in range(len(puzzleinput))))
    previous[(0,1)]=(0,0)
    previous[(1,0)]=(0,0)
    queue=PriorityQueue()
    #queue data put in the form: (weight, removed, dr, dc, sameDirectionDistance)
    queue.put((int(puzzleinput[0][1]),(0,1),0,1,1))
    queue.put((int(puzzleinput[1][0]),(1,0),1,0,1))

    
    
    while not queue.empty():
        weight,removed,dr,dc,sameDirectionDistance=queue.get()
        for dst,newdr,newdc in getNeighbours(removed):
            if dst in visited:
                continue
            if (newdr,newdc)==(dr,dc):
                newSameDirectionDistance=sameDirectionDistance+1
            else:
                newSameDirectionDistance=1
            if newSameDirectionDistance>3:
                continue
            newWeight=weight+int(puzzleinput[removed[0]][removed[1]])
            if newWeight < weights[dst]:
                weights[dst]=newWeight
                previous[dst]=removed
                queue.put((newWeight,dst,newdr,newdc,newSameDirectionDistance))
    return previous
                
def previousToList(previous,dst):
    path=deque()
    path.append(dst)
    while dst!=(0,0):
        path.appendleft(previous[dst])
        dst=previous[dst]
    return list(path)
print(sum(map(lambda x :int(puzzleinput[x[0]][x[1]]),previousToList(djikstraMod(),(12,12))[1:])))
4 Comments
2024/10/23
15:42 UTC

131

I love solving an AoC problem, only to look online and find someone who did it 10x better than me

I'm working on AoC 2015 right now, I just finished my solution to day 9 (the TSP-esque problem) in Go. I thought I found an elegant and simple solution to it. I then looked on GitHub to see other people's solutions and someone solved it in 1/3 the amount of code and using a much smarter DFS algorithm.

I love AoC but the imposter syndrome it gives me is insane.

Edit:

I think a lot of the comments are interpreting this as me feeling like a failure or I'm doing something wrong. I'd like to clarify, that I feel good whenever I can solve a question, be it efficient or just brute force. I look at other solutions as a learning experience and I understand there will always be a bigger fish, so to speak.

That said, I think it is still fair to feel a bit of imposter syndrome with any community-based coding exercises, be it LeetCode or AoC or whatever else. I know it is all psychological and the fact that someone out there found a "more eloquent" solution doesn't make me a worse engineer.

Anyway, thank you all for the words of encouragement and different perspectives. <3

44 Comments
2024/10/23
06:09 UTC

1

[2020] day 5 part two help

its not about code or smt. i just dont understand what i need to find... from what i should use those +1 -1...
also is my code readable? (C#)

using System.ComponentModel.Design;

namespace AoC_2020_quest_5
{
    internal class Program
    {
        //-----------------------------------------------------------------------------
        public static int SeatId(string input)
        {
            int id = 0;
            int row = 0;
            int Lenght = 128;
            int column = 0;
            for (int t = 0; t < 7; t++)
            {
                if (input[t] == 'B') row +=Lenght/2;
                Lenght /= 2;

            }
            id = row * 8;
            Lenght = 8;
            for (int t = 7; t <= 9; t++)
            {
                if (input[t] == 'R') column += Lenght / 2;
                Lenght /= 2;

            }
            id+=column;
            return id;
        }
        //-----------------------------------------------------------------------------
        public static void InputHandler(List<string> inputs)
        {
            string n = Console.ReadLine();
            do
            {
                inputs.Add(n);
                n = Console.ReadLine();
            } while (n != "");

        }
        //-----------------------------------------------------------------------------
         public static void MaxIdForQuest5_5Finder(List<int> ids)
        {
            int maxId = 0;
            foreach (int id in ids)
            {
                if (id > maxId) maxId = id;
            }
            Console.WriteLine(maxId);
        }
        //-----------------------------------------------------------------------------
        static void Main(string[] args)
        {
           List<string> inputs = new List<string>();
            List<int> seatIdList = new List<int>();
            InputHandler(inputs);
            for (int t = 0; t < inputs.Count; t++)
            {
               seatIdList.Add(SeatId(inputs[t]));
            }
            MaxIdForQuest5_5Finder(seatIdList);
            Console.ReadKey();  

            }
            //-------------------------------------------------------------------------
        }
    }
3 Comments
2024/10/22
15:34 UTC

4

[2023 Day 3 (Part 2)][TypeScript] Do you think my code is readable? How can I improve?

I first tried a more classical approach, but the program reached over 100 lines. I found it confusing and I couldn't break methods down in a satisfying way - it turned into one method calling another, until the last one was loaded with operations. So I decided to leave OOP for when I learn C#, since I'll be forced to use it. Then I decided to try a more functional approach.

I'm not really a competitive person, so I strive to make my code as readable as possible rather than performant. I just think this look hideous. I read someone say "the complexity has got to live somewhere", and I think I moved it to a giant block of function definitions. At least most of them are independent of each other, I guess?

const numberPattern = /\d+/g;
const asteriskPattern = /\*/g;
const hasTwoNumbersAround = (arr: Array<number>) => arr.length === 2;
const isAroundAsterisk = (match: RegExpExecArray, index: number) =>
    match.index <= index + 1 && match.index + match[0].length - 1 >= index - 1;
const toIndex = (match: RegExpExecArray) => match.index;
const toNumber = (match: RegExpExecArray) => Number(match[0]);
const toRatio = (arr: Array<number>) => arr[0] * arr[1];
const toNumbersArround = (row: number) => (index: number) =>
    [lines[row - 1], lines[row + 1], lines[row]]
        .flatMap(line => line?.matchAll(numberPattern).toArray())
        .filter(match => match && isAroundAsterisk(match, index))
        .map(toNumber);

const part2 = input.split("\n").flatMap((line, row) =>
    line.matchAll(asteriskPattern)
        .toArray()
        .map(toIndex)
        .map(toNumbersArround(row))
        .filter(hasTwoNumbersAround)
        .map(toRatio))
    .reduce((sum, ratio) => sum + ratio, 0);

This is what it looks like without extracting the callbacks:

const part2 = input.split("\n").flatMap((line, row) =>
    line.matchAll(/\*/g)
        .toArray()
        .map(match => match.index)
        .map(index => [lines[row - 1], lines[row + 1], lines[row]]
            .flatMap(line => line?.matchAll(/\d+/g).toArray())
            .filter(match => match && match.index <= index + 1 && match.index + match[0].length - 1 >= index - 1)
            .map(match => match[0]))
        .filter(numbers => numbers.length === 2)
        .map(numbers => numbers[0] * numbers[1]))
    .reduce((sum, ratio) => sum + ratio, 0);

Edit: Full solution with some differences from the post: https://github.com/arzcbnh/advent-of-code/blob/master/2023/days/3.ts

14 Comments
2024/10/21
02:18 UTC

1

[Day one] 2023 on python

I know there are easier ways to do this, but I am trying a more data-comprehensive method.

I want to change each line using the replace() method. I do it in almost numerical order "avoiding" the special case where "eightwo" messed the results up. Is there a special case I am not seeing or is this strategy plain wrong?

def show_real_nums(fichierTexte) :

texte = list()

for line in fichierTexte :

ligne = line

if "two" in ligne and "eightwo" not in ligne:

ligne = ligne.replace("two", "2")

else :

ligne = ligne.replace("eight", "8")

if "eight" in ligne:

ligne = ligne.replace("eight", "8")

if "one" in ligne :

ligne = ligne.replace("one", "1")

if "three" in ligne:

ligne = ligne.replace("three", "3")

if "four" in ligne :

ligne = ligne.replace("four", "4")

if "five" in ligne :

ligne = ligne.replace("five", "5")

if "six" in ligne :

ligne = ligne.replace("six", "6")

if "seven" in ligne :

ligne = ligne.replace("seven", "7")

if "nine" in ligne :

ligne = ligne.replace("nine", "9")

texte.append(ligne)

return(texte)

I'd be open to any help or more general tips too, I am not used to python. Thank you!

13 Comments
2024/10/19
22:58 UTC

2

Laravel scaffolding package

Hi everyone!

I’ve been programming for over 11 years, but this is actually my first time creating a Laravel package. I built it specifically for Advent of Code, and I wanted to share it with the community!

The package: https://packagist.org/packages/mjderoode/advent_of_code_helper

This Laravel package helps set up controllers (based on a stub) for your solutions and downloads the puzzle input for each day. The stub is customizable, so you can tailor it to fit your coding style. Hopefully, it makes your Advent of Code experience a bit smoother. I’d love any feedback you have, and I hope it helps!

Happy coding, and if you have any feedback, let me know!

6 Comments
2024/10/15
20:01 UTC

0

[2022 Day 12 part 1] My A* works with small data but not big

https://preview.redd.it/r442beq3djvd1.png?width=739&format=png&auto=webp&s=63b763e4f018ce69ed7fce2a6b2eb2be853c3568

I seem to be close, but not quite there yet. I even wrote a small program that visualizes the route.

Code is below

const f = require("fs");

class Node {
  constructor(row, col, data, g, h, parent) {
    (
this
.row = row), (
this
.col = col), (
this
.data = data), (
this
.g = g);
    
this
.h = h;
    
this
.f = g + h;
    
this
.parent = parent;
  }

  update_h(h) {
    
this
.h = h;
    
this
.f = h + 
this
.g;
  }

  update_g(g) {
    
this
.g = g;
    
this
.f = g + 
this
.h;
  }
}

let data = [];

// read the data
const dataRaw = f.readFileSync("data/12-data.txt", "utf-8");
dataRaw.split(/\r?\n/).forEach((line) => {
  data.push(line.split("").map((c) => c.charCodeAt(0) - 97));
});

const WIDTH = data[0].length;
const HEIGHT = data.length;
const DATA_PLAIN = dataRaw.split(/\r?\n/).join("");
const START_IDX = DATA_PLAIN.indexOf("S");
const TARGET_IDX = DATA_PLAIN.indexOf("E");

// Get the highest value (char -> int) in the data
const MAX_VALUE = Math.max(...data.map((row) => Math.max(...row)));

const START_POS = [START_IDX / WIDTH, START_IDX % WIDTH];
data[START_POS[0]][START_POS[1]] = -1;
const TARGET_POS = [Math.floor(TARGET_IDX / WIDTH), TARGET_IDX % WIDTH];

const generateEmptyArray = (width, height, content = 0) => {
  let array = Array(height)
    .fill()
    .map((a) => [...Array(width)])
    .map((a) => a.fill(content));
  return array;
};

const generateNodes = (width, height, startPos) => {
  let nodes = [];
  for (let iy = 0; iy < height; iy++) {
    let row = [];
    for (let ix = 0; ix < width; ix++) {
      const node = new Node(
        iy,
        ix,
        data[iy][ix],
        Number.MAX_SAFE_INTEGER,
        Number.MAX_SAFE_INTEGER
      );
      row.push(node);
    }
    nodes.push(row);
  }
  nodes[startPos[0]][startPos[1]].update_h(0);
  nodes[startPos[0]][startPos[1]].update_g(0);
  return nodes;
};

const manhattanDist = (pos, target) => {
  const dy = Math.abs(pos[0] - target[0]);
  const dx = Math.abs(pos[1] - target[1]);
  return dy + dx;
};

let nodes = generateNodes(WIDTH, HEIGHT, START_POS);
let open = [];
let closed = generateEmptyArray(WIDTH, HEIGHT, 0);
open.push(START_POS);

let i = 0;
while (true) {
  
// find node in open list with the lowest f_cost
  const currentPos = open.reduce(
    (acc, curr) =>
      nodes[curr[0]][curr[1]].f <= nodes[acc[0]][acc[1]].f ? curr : acc,
    open[0]
  );

  const currNode = nodes[currentPos[0]][currentPos[1]];

  
// if current is the target node, path has been found
  if (
    currNode.row === TARGET_POS[0] &&
    currNode.col === TARGET_POS[1] &&
    currNode.parent.data === MAX_VALUE
  )
    break;

  
// console.log("currentPos", currentPos);
  const currentNode = nodes[currentPos[0]][currentPos[1]];

  
// remove current from open
  open = open.filter(
    (p) => !(p[0] === currentPos[0] && p[1] === currentPos[1])
  );

  
// add current to closed
  closed[currentPos[0]][currentPos[1]] = 1;

  
// Find out all neighbours that are traversable
  
// and NOT closed.
  let neighbours = [];
  const directions = [
    [-1, 0], 
// down
    [0, 1], 
// right
    [1, 0], 
// up
    [0, -1], 
// left
  ];

  directions.forEach(([dy, dx]) => {
    const [newY, newX] = [currentPos[0] + dy, currentPos[1] + dx];
    if (
      newY >= 0 &&
      newY < HEIGHT &&
      newX >= 0 &&
      newX < WIDTH &&
      closed[newY][newX] === 0 &&
      data[currentPos[0]][currentPos[1]] + 1 >= data[newY][newX]
    ) {
      
// if new position is the target position but
      
// the value is not the highest, then skip
      if (newY === TARGET_POS[0] && newX === TARGET_POS[1]) {
        if (data[currentPos[0]][currentPos[1]] !== MAX_VALUE) return;
      }

      neighbours.push([newY, newX]);
    }
  });

  neighbours.forEach((neighbourPos) => {
    const neighbourNode = nodes[neighbourPos[0]][neighbourPos[1]];
    const g = currentNode.g + 1;
    const h = manhattanDist(neighbourPos, TARGET_POS);
    
// if new path to neighbour is shorter OR neighbour is not in open
    const neighbourInOpen =
      open.filter(
        (pos) => pos[0] === neighbourPos[0] && pos[1] === neighbourPos[1]
      ).length > 0;
    if (!neighbourInOpen || g + h < neighbourNode.h) {
      
// set f cost to neighbour
      neighbourNode.update_g(g);
      neighbourNode.update_h(h);

      
// set parent of neighbour to current
      neighbourNode.parent = currentNode;

      
// if neighbour is not in open, add neighbour to open
      if (!neighbourInOpen) open.push(neighbourPos);
    }
  });

  i++;
}

const flatten = (node) => {
  if (node.parent === undefined) return [];
  return [
    flatten(node.parent),
    "[" + node.parent.row + "," + node.parent.col + "]",
  ].flat();
};

const flattened = flatten(nodes[TARGET_POS[0]][TARGET_POS[1]]);
console.log("Coords from start to finish", flattened);
6 Comments
2024/10/15
11:15 UTC

3

HELP [2023 Day 07 (part 1)][python] Returning to AoC and Struggling

Hi All, trying to strengthen my coding skills with some AoC and getting warmed up for the upcoming round in December, but currently I am fairly frustrated with this problem as I do like my approach and everything seems to be working as I have intended it to and it does work for the test input.

Was wondering if anyone could point out my lack of understanding here:

My code:

#!/usr/bin/env python3
# coding: utf-8

from collections import Counter
from itertools import chain

with(open("./dat/input_07.txt")) as f:
   input_lines = f.readlines()

# with(open("./dat/test_07.txt")) as f:
#    input_lines = f.readlines()

records = [{"list_cards": list(cards), "bet": bet} for cards, bet in [i.replace("\n", "").split() for i in input_lines]]

alpha_map = {card: alpha for card, alpha in \
             zip(["A", "K", "Q", "J", "T", "9", "8", "7", "6", "5", "4", "3", "2"], list("ABCDEFGHIJKLM"))}
ranking_lists = [[] for _ in range(7)]

check_cnts = []

for ind, r in enumerate(records):
    tmp_cnts = sorted(Counter(r["list_cards"]).values(), reverse = True)
    check_cnts.append(tmp_cnts) 
    if tmp_cnts == [5]: # 5 of a kind
        ranking_lists[0].append((ind, "".join([alpha_map[c] for c in r["list_cards"]]), r["list_cards"]))
        continue
    if tmp_cnts == [4, 1]: # 4 of a kind
        ranking_lists[1].append((ind, "".join([alpha_map[c] for c in r["list_cards"]]), r["list_cards"]))
        continue
    if tmp_cnts == [3, 2]: # full-house
        ranking_lists[2].append((ind, "".join([alpha_map[c] for c in r["list_cards"]]), r["list_cards"]))
        continue
    if tmp_cnts == [3, 1, 1]: # 3 of a kind
        ranking_lists[3].append((ind, "".join([alpha_map[c] for c in r["list_cards"]]), r["list_cards"]))
        continue
    if tmp_cnts == [2, 2, 1]: # two pair
        ranking_lists[4].append((ind, "".join([alpha_map[c] for c in r["list_cards"]]), r["list_cards"]))
        continue
    if tmp_cnts == [2, 1, 1, 1]: # pair
        ranking_lists[5].append((ind, "".join([alpha_map[c] for c in r["list_cards"]]), r["list_cards"]))
        continue
    if tmp_cnts == [1, 1, 1, 1, 1]: # high card
        ranking_lists[6].append((ind, "".join([alpha_map[c] for c in r["list_cards"]]), r["list_cards"]))

rankings = [(i[0], "".join(i[2])) for i in chain.from_iterable(map(lambda y: sorted(y, key = lambda x: x[1]), ranking_lists))]

ans = []

for ind, r in enumerate(rankings, 1):
    ans.append(ind*int(records[r[0]]["bet"]))


print(sum(ans))

Sample of rankings (list where first item is pos. in records, second is card string for proofing):

[(177, 'JJJJJ'), # 5 of a kind
 (770, 'AAAKA'), # 4 of a kind
 (310, 'AAA8A'),
 (194, 'AAQAA'),
 (207, 'AATAA'),
 (619, 'AA9AA'),
 (98, 'AJAAA'),
 (283, 'A5AAA'),
 (734, 'A3AAA'),
 (893, 'KKKK2'),
…
 (649, 'AAKAK'), # First full house
 (570, 'AA6A6'),
 (692, 'AKKKA'),
 (414, 'A8AA8'),
 (907, 'A666A'),
 (28, 'A5A5A'),
…
 (636, 'AAAT5'), # First 3 of a kind
 (717, 'AAA9J'),
 (382, 'AAA6J'),
 (793, 'AAA48'),
 (426, 'AAQA9'),
 (99, 'AAQA3'),
 (881, 'AA4AJ'),
…
 (232, 'AAKJK'), # First two pair
 (725, 'AAK3K'),
 (739, 'AA77J'),
…
 (748, 'AAKTQ'), # First pair
 (744, 'AA2QK'),
 (812, 'AKA7Q'),
…
 (765, 'AK537'), # High card
 (105, 'AJT92'),
 (128, 'AJ6KQ'),
…
 (597, '276Q5'), # end of list
 (705, '274Q5'),
 (943, '254KA'),
 (763, '254JK')]
5 Comments
2024/10/13
17:24 UTC

0

Part 2, Day 7 of 2023 in rust

I've been practicing with the 2023 puzzles for the upcoming AOC, but I've hit a snag on day 7, part 2. The current solution I've written is here: github. It solves the example input correctly, but gives me the wrong final answer. I don't really have any extra example input, so I don't really know how to continue. Is there anyone that could take a look at my code and push me in the right direction or just give me some larger example input so I could figure it out myself?

6 Comments
2024/10/12
15:43 UTC

32

What are your favourite YouTube channels that solve Advent of Code problems?

16 Comments
2024/10/12
08:49 UTC

0

[2023 Day 14] Part B: I know what to do, but somehow...

Hi, I was pretty sure that there would be a cycle at one point and looking in all of these threads confirmed that, so the theory is clear. The big problem is that I can't find a cycle, not even in the small test input. Here is my implementation (only the cycle detecting part), I somehow think that I did a very naive error...

def doCycles(grid,n):
    states = []

    for x in range(1,n):
        rock_keys_of_current_state = getRockKeys(grid)
        states.append(rock_keys_of_current_state)
        grid = fullcycle(grid)
        rock_keys_after_fullcycle = getRockKeys(grid)
        for state in states:
            if rock_keys_of_current_state  == rock_keys_after_fullcycle:
                first_occurence = states.index(state)
                return("pattern", first_occurence, "repeated after",n,"steps")
    return("no cycle")

print(doCycles(grid, 1000))
7 Comments
2024/10/07
16:49 UTC

0

AdventOfCode 2024???

Will there be a AoC 2024?

8 Comments
2024/10/07
14:13 UTC

Back To Top