35 votes

Advent of Code 2019

31 comments

  1. [2]
    Deimos
    (edited )
    Link
    Edit: I've created a sub-group for this now. Please subscribe, and if you'd like to move your solutions from comments in here into the new threads I've posted for the first 3 days, that would...

    Edit: I've created a sub-group for this now. Please subscribe, and if you'd like to move your solutions from comments in here into the new threads I've posted for the first 3 days, that would probably be good. That way if anyone gets involved later or wants to comment on them, it'll be more nicely organized based on the problem.

    Original comment that was here

    Meta question: if there are going to be a decent number of people participating in this, should we have a daily thread so that each day's solutions/discussion can be separated out more easily? It will be a lot of posts, but if people aren't interested in them they can easily avoid them by either unsubscribing from ~comp or filtering out the "advent of code" tag.

    Alternatively, we could even create a (temporary) sub-group just for these topics, making it even easier.

    I won't do it just yet, but I can set up daily posts starting from Day 4 if people think it would be a good idea. I think it might be a good plan, especially if some people aren't keeping up with the schedule. Having it all in one topic is probably going to get overwhelming very quickly.

    13 votes
    1. unknown user
      Link Parent
      Perhaps we should do recurring threads. But then I worry that people who post their solutions a day or so late will not get theirs seen. I think that this will only be needed if lots more people...

      Perhaps we should do recurring threads. But then I worry that people who post their solutions a day or so late will not get theirs seen. I think that this will only be needed if lots more people start posting their solutions.

      If we don't do recurring threads, and we just keep this one, then would it be possible for you to pin it to the top of ~comp until the even is over?

      Perhaps the pin could be combined with you making 25 comments in this thread, one for each day and then people reply to those comments with their solutions? Sorting would be a nightmare.

      Perhaps the sub-group idea with a post for each day makes the most sense and then at the end of the event, all the posts can be merged back into ~comp. Again though, the sub group would probably end up putting the posts in a strange order.

      I put way too much thought into that.

      4 votes
  2. [6]
    markh
    Link
    In case you’re looking for something fun to do and haven’t previously heard about it, Advent of Code 2019 has begun! For those who don’t know, it’s 25 days of coding challenges, one challenge per...

    In case you’re looking for something fun to do and haven’t previously heard about it, Advent of Code 2019 has begun!

    For those who don’t know, it’s 25 days of coding challenges, one challenge per day, through the month of December.

    Anyone participating?

    6 votes
    1. Gyrfalcon
      Link Parent
      I started working on them yesterday. I think it's neat, just need to make sure I don't get too busy with finals and actually participating in the holidays!

      I started working on them yesterday. I think it's neat, just need to make sure I don't get too busy with finals and actually participating in the holidays!

      5 votes
    2. [4]
      krg
      Link Parent
      I'll give it a go. Do the problems start ramping up in difficulty?

      I'll give it a go. Do the problems start ramping up in difficulty?

      1 vote
      1. acdw
        Link Parent
        Last year, they sure did.

        Last year, they sure did.

        4 votes
      2. undu
        Link Parent
        Yep, they do. First day was easy, third is not obvious at all

        Yep, they do. First day was easy, third is not obvious at all

        3 votes
      3. unknown user
        Link Parent
        Post your solutions here if you do give it a go. It'd be nice to compare solutions.

        Post your solutions here if you do give it a go. It'd be nice to compare solutions.

        2 votes
  3. [3]
    Comment deleted by author
    Link
    1. Crespyl
      Link Parent
      I like the approach of testing line segments/vectors for intersection directly, I had wondered if anyone tried that. My first naive approach was to walk the lines and save every coordinate to a...

      I like the approach of testing line segments/vectors for intersection directly, I had wondered if anyone tried that. My first naive approach was to walk the lines and save every coordinate to a set, and then take advantage of the &/intersection operator built in to Ruby/Crystal.

      With my input that means tracking ~300k points which takes around ~0.5s in Ruby (negligible in Crystal) and certainly won't scale terribly well, I'm surprised that it worked as well as it did.

      The first optimization I'd probably make to my own version would've been to only build the full point set for one line, then just walk the second line and only record those points that already exist in the first line. If we revisit the problem I'm sure I'll have to move to doing both that and line-intersections.

      As an aside, it's been fun writing the first pass in Ruby and then porting to Crystal, but it's both funny and annoying that File::readlines in Ruby is File::read_lines in Crystal, where almost all the other basic utilities have used exactly the same names.

      4 votes
    2. nothis
      Link Parent
      I just brute-forced day 3 at first, storing the coordinates (and distance traveled) for each point touched by a wire. It ran embarrassingly slow but I had a result roughly half an hour in. Then I...

      I just brute-forced day 3 at first, storing the coordinates (and distance traveled) for each point touched by a wire. It ran embarrassingly slow but I had a result roughly half an hour in.

      Then I tried optimizing for fun. I basically just stored "line segments" with a start and end point and did an AABB style test for overlapping (checking whether the start point of the first line is lower than the end point of the other line and vice versa, for the x and y axis). I then picked the y value of the horizontal line (identical y start and end values = horizontal) and the x value of the other line. I assume what you used is the fancy numeric version of just doing this with a bunch of if-then branches.

      I cheekily assumed no lines with the same orientation (horizontal, vertical) ever overlap, which would have complicated things, I guess (it worked, maybe I just was lucky). Walking distance required storing the combined distance of previous line segments plus adding the distance from the current line segment's start to the intersection.

      This reduced running time from like half a minute (lol!) to a split second. I guess there's further optimization you can do by sorting lines to quickly discard all lines above and below the current line's boundaries but that seems like overkill to me.

      3 votes
  4. acdw
    Link
    Oh ! I tried this last year in Rust for about a week, then it got too hard. Maybe I'll try it again but with whatever language I can do it in!

    Oh ! I tried this last year in Rust for about a week, then it got too hard. Maybe I'll try it again but with whatever language I can do it in!

    3 votes
  5. [11]
    unknown user
    (edited )
    Link
    I'm a beginner programmer, so feedback is very welcome. I'm doing it all in Python 3. The code will probably get progressively messier as the challenges get harder and harder. I've left in my...

    I'm a beginner programmer, so feedback is very welcome. I'm doing it all in Python 3. The code will probably get progressively messier as the challenges get harder and harder. I've left in my commented out debug print statements. There isn't much inline commenting.

    Also no cheating by copying my code!

    Day 1: The Tyranny of the Rocket Equation

    Part 1
    import math
    
    with open('input','r') as f:
        data = f.read().splitlines()
    
    Total = 0
    for i in range(len(data)):
        Total = Total + (math.floor((int(data[i]) / 3)) - 2)
    
    print(Total)
    

    This was pretty simple. I'm sure it could be condensed down.

    Part 2
    import math
    
    def calculate(inamount):
        return math.floor((int(inamount) / 3)) - 2#divide by 3, round down, -2
    
    with open('input','r') as f:
        data = f.read().splitlines()
    
    Total = 0
    for i in range(len(data)):
        FuelArray = []    
        FuelArray.append(calculate(data[i]))
        if calculate(data[i]) <= 0:
            Total = Total + calculate(data[i])
        else:
            while calculate(FuelArray[-1]) > 0:
                FuelArray.append(calculate(FuelArray[-1]))#-1 means last entry
            FuelArraySum = 0
            for i in range(len(FuelArray)):
                FuelArraySum = FuelArraySum + FuelArray[i]
            Total = Total + FuelArraySum
            
    print(Total)
    

    I'm not entirely sure I needed to use a function here. But it was easier for my brain to work around it that way. This one made me think a little with the whole calculating the weight of fuel needed for fuel.


    Day 2: 1202 Program Alarm

    I really liked this one. It was much harder to wrap my head around how the intcode actually worked than to program it.

    Part 1
    data = [] #The input was given in something very similar to a python array so I just copy pasted it in here. To save space I haven't included it in the post.
    
    
    ipointer = 0
    ipointermax = (len(data) - 1) / 4#-1 because of 99 at the end.
    #print(ipointermax)
    
    
    for i in range(int(ipointermax)):#Probably could have just done a while loop that went until it found 99.
        #print('ipointer', ipointer)
        #print(data)
        val1 = data[data[ipointer + 1]]
        val2 = data[data[ipointer + 2]]
        #print('op', data[ipointer])
        #print('v1', val1)
        #print('v2', val2)
        if data[ipointer] == 1:
            data[data[ipointer + 3]] = val1 + val2
            #print(val1 + val2)
        elif data[ipointer] == 2:
            data[data[ipointer + 3]] = val1 * val2
            #print(val1 * val2)
        elif data[ipointer] == 99:
            print('STOP')
            print('Answer is', data[0])
            break
        else:
            print('Something has gone horribly and terribly wrong')
            break
        ipointer = ipointer + 4
    

    I didn't include the actual input data in this post. I really liked this challenge.

    One thing that tripped me up though. The challenge said:

    To do this, before running the program, replace position 1 with the value 12 and replace position 2 with the value 2.

    I didn't read the question properly, never changed that second value and spent a good 10 minutes manually checking that it was properly processing the intcode, before reading the question again and facepalming at my own negligence.

    Part 2
    def calculate(noun,verb):
        data = [] #Again, not including my actual input data, it's long
        ipointer = 0
        ipointermax = (len(data) - 1) / 4#-1 because of 99 at the end.
        #print(ipointermax)
        data[1] = noun
        data[2] = verb
    
        for i in range(int(ipointermax)):
            #print('ipointer', ipointer)
            #print(data)
            val1 = data[data[ipointer + 1]]
            val2 = data[data[ipointer + 2]]
            #print('op', data[ipointer])
            #print('v1', val1)
            #print('v2', val2)
            if data[ipointer] == 1:
                data[data[ipointer + 3]] = val1 + val2
                #print(val1 + val2)
            elif data[ipointer] == 2:
                data[data[ipointer + 3]] = val1 * val2
                #print(val1 * val2)
            elif data[ipointer] == 99:
                #print('STOP')
                #print('Answer is', data[0])
                return data[0]
            else:
                print('Something has gone horribly and terribly wrong')
                break
            ipointer = ipointer + 4
            
    
    
    verb = 0
    noun = 0
    
    for verb in range(100):
        for noun in range(100):
            if calculate(noun,verb) == 19690720:
                print('Answer is', 100 * noun + verb)
    

    The first part is the same as part 1, but now it is part of a function that gets run over and over by a double for loop. I'm sure if you were mathematically talented you could probably use clever maths to solve this with a method that isn't brute force. But I'm not that smart.


    Day 3: Crossed Wires

    So I had two attempts at this one. Both of them work and both of them are truly horrible. Good programmers who do not want to poison their minds please look away now. (but hey, at least they both get the same, correct answer).

    Part 1 Attempt 1
    #from tabulate import tabulate
    
    with open('input','r') as f:
        data = f.read().splitlines()
    
    for i in range(len(data)):#overdone to do it like this. But this way it isn't hardcoded to only dealing with two lines. Although the rest of the code is.. *shrug*
        data[i] = data[i].split(',')
    
    print(data)
    
    #make big array that has everything in it 20000x20000 should be big enough...
    LinesArray = [['.' for i in range(20000)] for i in range(20000)]#Normally 2000
    
    '''
    Key:
    5 = starting position
    1 = part of line 1
    2 = part of line 2
    3 = intersection of both lines
    blank = nothing here
    '''
    LinesArray[10000][10000] = 5#start point. Normally 1000
    
    Position = [10000,10000]#y,x. Normally 1000,1000
    PositionOriginal = Position#Store this for later...
    
    #now to plot the lines
    for i in range(len(data)):#Do once for each line. If len(data) is not 2, this will break.
        Position = [10000,10000]#y,x. Normally 1000,1000
        if i == 0:
            CurrentLine = 1
        elif i == 1:
            CurrentLine = 2
        else:
            print('More lines are not supported!!')
            break
        for j in range(len(data[i])):
            Direction = data[i][j][:1]
            Amount = data[i][j][1:]
            #print(Direction, Amount)
            #print(Position)
            if Direction == 'U':
                for k in range(int(Amount)):
                    #print(k)
                    if LinesArray[Position[0] - k - 1][Position[1]] == CurrentLine - 1 or LinesArray[Position[0] - k - 1][Position[1]] == 3:#neverhappens on first run. does on second
                        LinesArray[Position[0] - k - 1][Position[1]] = 3
                    else:
                        LinesArray[Position[0] - k - 1][Position[1]] = CurrentLine
                Position[0] = Position[0] - k - 1
                #print(Position)
                #LinesArray[Position[0]][1] = 2
                #print(tabulate(LinesArray))
            elif Direction == 'D':
                for k in range(int(Amount)):
                    #print(k)
                    if LinesArray[Position[0] + k + 1][Position[1]] == CurrentLine - 1 or LinesArray[Position[0] + k + 1][Position[1]] == 3:
                        LinesArray[Position[0] + k + 1][Position[1]] = 3
                    else:
                        LinesArray[Position[0] + k + 1][Position[1]] = CurrentLine
                Position[0] = Position[0] + k + 1
                #print(Position)
                #LinesArray[Position[0]][1] = 2
                #print(tabulate(LinesArray))
            elif Direction == 'L':
                for k in range(int(Amount)):
                    #print(k)
                    if LinesArray[Position[0]][Position[1] - k - 1] == CurrentLine - 1 or LinesArray[Position[0] - k - 1][Position[1]] == 3:
                        LinesArray[Position[0]][Position[1] - k - 1] = 3
                    else:
                        LinesArray[Position[0]][Position[1] - k - 1] = CurrentLine
                Position[1] = Position[1] - k - 1
                #print(Position)
                #LinesArray[Position[0]][1] = 2
                #print(tabulate(LinesArray))
            elif Direction == 'R':
                for k in range(int(Amount)):
                    #print(k)
                    if LinesArray[Position[0]][Position[1] + k + 1] == CurrentLine -1 or LinesArray[Position[0]][Position[1] + k + 1] == 3:
                        LinesArray[Position[0]][Position[1] + k + 1] = 3
                    else:
                        LinesArray[Position[0]][Position[1] + k + 1] = CurrentLine
                Position[1] = Position[1] + k + 1
                #print(Position)
                #LinesArray[Position[0]][1] = 2
                #print(tabulate(LinesArray))
            else:
                print('There is an issue')
                break
    
    #print('---------------')
    #Now do the manhattan distance thing to find the closest point...
    ListOfIntersections = []
    for i in range(len(LinesArray)):
        for j in range(len(LinesArray[i])):
            if LinesArray[i][j] == 3:#i is down from top, j is from left going right
                SubList = []
                SubList.append(i)
                SubList.append(j)
                ListOfIntersections.append(SubList)
                #print(ListOfIntersections)
                
    
    
    #print(ListOfIntersections)
    
    #Now find the one that is the closest...
    ShortestDistance = -1
    for i in range(len(ListOfIntersections)):
        XDistance = ListOfIntersections[i][1] - PositionOriginal[1]
        YDistance = ListOfIntersections[i][0] - PositionOriginal[0]
        if XDistance < 0:
            XDistance = XDistance * -1
        if YDistance < 0:
            YDistance = YDistance * -1
        ManhattanDistance = XDistance + YDistance
        #print('pos orig', PositionOriginal)
        #print(ListOfIntersections[i][1], PositionOriginal[1], XDistance)
        #print(ListOfIntersections[i][0], PositionOriginal[0], YDistance)
        #print(ManhattanDistance)
        if ManhattanDistance < ShortestDistance or ShortestDistance == -1:
            ShortestDistance = ManhattanDistance
    
    print('Answer: ',ShortestDistance)
    

    This is horrible. I used an absolutely massive two dimensional array to visualise the wires. When it runs it uses about 3.2GB's of ram and takes a minute or so to get the result.

    I used tabulate to visualise the grid when it was small (10x10) for testing. I took this out for the final, massive array.

    I kept on having to increase the size of the array, because the wires kept on going outside of it and causing errors. It worked at 20,000 by 20,000. (very big).

    Also I kept on having weird issues where I would set an array to be equal to another array, and then if I changed the first array, the second one would also change. I fixed that by using some jank. For attempt 2 I learned when you say array = array2, they are both the same object, so you need to say array = array2[:] to make them separate.

    So perhaps visualisation is not so great when dealing with very big things.

    I thought that this was so bad that I should really give it another crack. But I think attempt 2 is arguably worse.

    Part 1 Attempt 2
    with open('input','r') as f:
        data = f.read().splitlines()
    
    for i in range(len(data)):#overdone to do it like this. But this way it isn't hardcoded to only dealing with two lines. Although the rest of the code is.. *shrug*
        data[i] = data[i].split(',')
    
    History = []#Always clear your history. Well... not this one.
    StartPos = [0,0]#x,y (the middle of our 'cartesian plane' if we want to visualise)
    CurrentPos = StartPos[:]#[:] so that it makes a new object
    #print(CurrentPos)
    #print(StartPos)
    for i in range(len(data[0])):#first line
        print(len(data[0]), i)
        Direction = data[0][i][:1]
        Amount = int(data[0][i][1:])
        if Direction == 'U':
            for j in range(Amount):
                #print(CurrentPos)
                CurrentPos[1] = CurrentPos[1] + 1
                #if not CurrentPos in History:#this should save some time. Or perhaps its more checks so it takes longer??
                #    History.append(CurrentPos[:])
                History.append(CurrentPos[:])
        elif Direction == 'D':
            for j in range(Amount):
                #print(CurrentPos)
                CurrentPos[1] = CurrentPos[1] - 1
                #if not CurrentPos in History:#this should save some time. Or perhaps its more checks so it takes longer??
                #    History.append(CurrentPos[:])
                History.append(CurrentPos[:])
        elif Direction == 'L':
            for j in range(Amount):
                #print(CurrentPos)
                CurrentPos[0] = CurrentPos[0] - 1
                #if not CurrentPos in History:#this should save some time. Or perhaps its more checks so it takes longer??
                #    History.append(CurrentPos[:])
                History.append(CurrentPos[:])
        elif Direction == 'R':
            for j in range(Amount):
                #print(CurrentPos)
                CurrentPos[0] = CurrentPos[0] + 1
                #if not CurrentPos in History:#this should save some time. Or perhaps its more checks so it takes longer??
                #    History.append(CurrentPos[:])
                History.append(CurrentPos[:])
        else:
            print('Something has probably just caught fire...')
            break
    #print(History)
    
    CurrentPos = StartPos[:]
    IntersectionList = []
    
    for i in range(len(data[1])):#second line!
        print(len(data[1]), i)
        Direction = data[1][i][:1]
        Amount = int(data[1][i][1:])
        if Direction == 'U':
            for j in range(Amount):
                #print(CurrentPos)
                CurrentPos[1] = CurrentPos[1] + 1
                if CurrentPos in History:
                    IntersectionList.append(CurrentPos[:])
        elif Direction == 'D':
            for j in range(Amount):
                #print(CurrentPos)
                CurrentPos[1] = CurrentPos[1] - 1
                if CurrentPos in History:
                    IntersectionList.append(CurrentPos[:])
        elif Direction == 'L':
            for j in range(Amount):
                #print(CurrentPos)
                CurrentPos[0] = CurrentPos[0] - 1
                if CurrentPos in History:
                    IntersectionList.append(CurrentPos[:])
        elif Direction == 'R':
            for j in range(Amount):
                #print(CurrentPos)
                CurrentPos[0] = CurrentPos[0] + 1
                if CurrentPos in History:
                    IntersectionList.append(CurrentPos[:])
        else:
            print('Something has probably just caught fire... But in a different spot!')
            break
    
    #print(IntersectionList)
    
    #All the stuff down here is pretty similar to attempt 1
    #Now find the one that is the closest...
    ShortestDistance = -1
    for i in range(len(IntersectionList)):
        XDistance = IntersectionList[i][0] - StartPos[0]
        YDistance = IntersectionList[i][1] - StartPos[1]
        if XDistance < 0:
            XDistance = XDistance * -1
        if YDistance < 0:
            YDistance = YDistance * -1
        ManhattanDistance = XDistance + YDistance
        #print('pos orig', StartPos)
        #print(IntersectionList[i][0], StartPos[0], XDistance)
        #print(IntersectionList[i][1], StartPos[1], YDistance)
        #print(ManhattanDistance)
        if ManhattanDistance < ShortestDistance or ShortestDistance == -1:
            ShortestDistance = ManhattanDistance
    
    print('Answer: ',ShortestDistance)
    

    So I thought, rather than make a massive array, why don't we just record every single place that the first line goes (a different, massive array), and then when figuring out the second line, check each place to see if it's in a spot that the first line has also been. If it is, then record those coordinates. Then do the same figuring out to find the closest one.

    The good: This uses significantly less memory than the previous attempt (I didn't measure it but gotop didn't show any massive climbs like attempt 1 did)

    The bad: This is very slow. Slower than slow. It took 8 minutes to get the correct answer. The guy who completed this challenge first did it in 2 minutes and 38 seconds. They could program this whole thing ~3x faster than I could run mine.

    I tried reducing this time by checking if something has already been added to the "history" of the first line and then not adding it a second time (or perhaps more), reducing the size of the array and therefore hopefully making the comparisons quicker. But this made more checks have to be done, so it actually slowed it down. The modified code takes 11 minutes and 40 seconds to run. Ooops! I left that check code in but commented out.

    I noticed that when it was being slow, it was getting slow in the "for j in range(Amount):" loops.

    When the loops do an "if not CurrentPos in History:" check (for the first line, this is the thing I added to try speed it up that actually slowed it) they go slow. When they check is not present, the first part of the code completes very quickly.

    Of course the "if CurrentPos in History:" checks are pretty necessary on the second line because how else would I check if the lines intersect. So this part is still slow.

    Perhaps I could speed it up by just storing the end points of each line segment (eg 200,200 and 200,220 could be one segment) and then checking if the proposed spot falls within that range. I'm not sure if this will be faster though and I'm too tired at the moment to try it. Perhaps another time.

    Please don't make me feel too bad about what I've just done.

    As for Part 2, I'm tired and I'm not sure I will be able to do it. I'll give it a shot another day.


    I'm going to post new solutions into the threads that Deimos made. I'll also copy the current ones into the threads.

    3 votes
    1. [2]
      Deimos
      Link Parent
      A couple more quick notes about other minor things I noticed while I was back in here: It's almost never necessary to loop like this in Python: for i in range(len(data)): print(data[i]) When you...

      A couple more quick notes about other minor things I noticed while I was back in here:

      It's almost never necessary to loop like this in Python:

      for i in range(len(data)):
          print(data[i])
      

      When you have items in an iterable type (like a list) and you want to loop over each of them, you should usually do it like:

      for item in data:
          print(item)
      

      Each time through the loop, item will be the current element, the equivalent of your data[i].

      Also, when you're adding something to an existing total, you can write total = total + more as total += more. This works for most other operators too. For example, x = x * y can be x *= y, and so on.

      5 votes
      1. unknown user
        Link Parent
        Oh yes, that is a better way to do it. I didn't know you could iterate things like that!

        Oh yes, that is a better way to do it. I didn't know you could iterate things like that!

        4 votes
    2. [2]
      hhh
      Link Parent
      just a tip--- putting python after the three ``` characters will give the code syntax highlighting

      just a tip--- putting python after the three ``` characters will give the code syntax highlighting

      3 votes
      1. unknown user
        Link Parent
        Ah! Thank you for this, I have edited it in.

        Ah! Thank you for this, I have edited it in.

        1 vote
    3. [2]
      bloup
      Link Parent
      Fun fact, in Python, // is integer division, and will automatically give you the floor of the quotient.

      Fun fact, in Python, // is integer division, and will automatically give you the floor of the quotient.

      3 votes
      1. unknown user
        Link Parent
        Thank you for this tip.

        Thank you for this tip.

        1 vote
    4. Grzmot
      Link Parent
      Mathematically, I don't think there is, as properly solving with two variables would require 2 equations.

      The first part is the same as part 1, but now it is part of a function that gets run over and over by a double for loop. I'm sure if you were mathematically talented you could probably use clever maths to solve this with a method that isn't brute force. But I'm not that smart.

      Mathematically, I don't think there is, as properly solving with two variables would require 2 equations.

      2 votes
    5. [3]
      hhh
      Link Parent
      I had this same issue on part 2 except with variables! I completely forgot that python's variable assignments are more like name tags than boxes.

      Also I kept on having weird issues where I would set an array to be equal to another array, and then if I changed the first array, the second one would also change. I fixed that by using some jank. For attempt 2 I learned when you say array = array2, they are both the same object, so you need to say array = array2[:] to make them separate.

      I had this same issue on part 2 except with variables! I completely forgot that python's variable assignments are more like name tags than boxes.

      2 votes
      1. [2]
        Deimos
        (edited )
        Link Parent
        You can also explicitly make it a copy (instead of a reference) like: first_list = [1, 2, 3] second_list = first_list.copy() Then if you change elements of second_list, it won't affect first_list....

        You can also explicitly make it a copy (instead of a reference) like:

        first_list = [1, 2, 3]
        second_list = first_list.copy()
        

        Then if you change elements of second_list, it won't affect first_list. @HanakoIsBestGirl's second_list = first_list[:] does basically the same thing, but it's a little less obvious what it's doing. That [:] notation is called "slicing", and is usually used when you only want part of the list. For example:

        first_list = [1, 2, 3, 4]
        second_list = first_list[1:-1]
        # second list is [2, 3] - we cut off the first and last elements
        
        second_list = first_list[1:]
        # second list is [2, 3, 4] - we cut off the first element
        

        By not specifying either end of the slice with [:], it goes from the start to the end and effectively copies it.

        4 votes
        1. hhh
          Link Parent
          I already ended up figuring this out but thank you!

          I already ended up figuring this out but thank you!

          3 votes
  6. asterisk
    Link
    It is really fun and interesting. For example I liked to read about 1202 Program Alarm. My git where I am coding in [bad] PHP.

    It is really fun and interesting. For example I liked to read about 1202 Program Alarm.

    My git where I am coding in [bad] PHP.

    3 votes
  7. krg
    (edited )
    Link
    @HanakoIsBestGirl : Ok, posting solutions here, I suppose. I'll be attempting these in Rust. well, so far I've only done d1p1. DAY 1 part 1 hardest part was learning how to read lines from a file...

    @HanakoIsBestGirl : Ok, posting solutions here, I suppose. I'll be attempting these in Rust.

    well, so far I've only done d1p1.

    DAY 1

    part 1 hardest part was learning how to read lines from a file in Rust...and thinking about what to name my work function.
    use std::fs::File;
    use std::path::Path;
    use std::io::{BufRead, BufReader, Error, ErrorKind, Read};
    
    const DIVISOR: usize = 3;
    const SUBTRA: usize = 2;
    
    fn main() -> Result<(), Error>{
    	let path = Path::new("data/input.txt");
    	let vec = read(File::open(path)?)?;
    
    	let sum: usize = vec.iter()
    						.map(|&x| div_and_subt(x, DIVISOR, SUBTRA))
    						.sum();
    
    	println!("{:?}", sum);
    
    	Ok(())
    }
    
    fn div_and_subt(n: usize, x: usize, y: usize) -> usize {
    	n/x - y
    }
    
    fn read<R: Read>(io: R) -> Result<Vec<usize>, Error> {
    	let br = BufReader::new(io);
    	br.lines()
    		.map(|line| line.and_then(|v| v.parse().map_err(|e| Error::new(ErrorKind::InvalidData, e))))
    		.collect()
    }
    

    Hmm...trying to use recursion for part 2, but I guess Rust has some problems with recursion. I actually haven't thought recursively in a bit, but I think this function would otherwise work?

    fn r_div_and_subt(n: usize, x: usize, y: usize) -> usize {
    	let f = match n/x > y {
    		true => n/x - y,
    		false => 0
    	};
    
    	f + r_div_and_subt(f, x, y)
    }
    

    EDIT: fixed the recursive function. forgot to exit function when f = 0 🤦. wrong code left up for posterity.

    3 votes
  8. jzimbel
    Link
    If anyone's interested, I have projects in Python and Go that auto-download puzzle inputs for you and pass them to your solution function as a string. All you have to provide is your session ID...

    If anyone's interested, I have projects in Python and Go that auto-download puzzle inputs for you and pass them to your solution function as a string. All you have to provide is your session ID which is stored in a cookie on the site.

    Python
    Go

    Feel free to fork if they seem useful. :)

    3 votes
  9. [4]
    hhh
    (edited )
    Link
    Like @HanakoIsBestGirl, I'm also a beginner doing this in Python 3. Feedback is always welcome! thoughts about each part are on the bottom of the code :) Day 1: The Tyranny of the Rocket Equation...

    Like @HanakoIsBestGirl, I'm also a beginner doing this in Python 3. Feedback is always welcome!
    thoughts about each part are on the bottom of the code :)

    Day 1: The Tyranny of the Rocket Equation

    having to look up file i/o in python edition

    Part 1
    inputf = open('day1input.txt', 'r')
    
    def mod_fuel(mass):
        return (mass//3) - 2
    
    def fuel_sum():
        sum = 0
        for line in inputf:
            sum += mod_fuel(int(line))
        return sum
    
    print(fuel_sum());inputf.close()
    

    pretty easy for the most part but didn't know how to open a file :(

    Part 2
    inputf = open('day1input.txt', 'r')
    
    def findfuel(mass):
        if mass <= 6:
            return 0
        fuel = (mass // 3) - 2
        fuel +=  findfuel(fuel)
        return fuel
    
    def fuel_sum():
        sum = 0
        for line in inputf:
            sum += findfuel(int(line))
        return sum
    
    print(fuel_sum());inputf.close()
    

    took a little more thinking but got it down after another 10ish minutes :)

    Day 2: 1202 Program Alarm

    forgetting Python has shallow copying >:( and learning list comprehension edition

    The *cough* wall of text *cough* instructions took a long time for me to wrap my head around but implementing them was relatively straightforward. Fun little challenge but I'm worried about how far I'm going to be able to progress knowing the puzzles will get harder.

    Part 1
    with open('input_p1only.txt', 'r') as inpfile:
        readfile = inpfile.read()
    
    def convertolist(flist):
        stripped = flist.rstrip('\n')
        split = stripped.split(',')
        tape = [int(x)  for x in split]
        return tape
    
    memory = convertolist(readfile)
    pointer = 0
    while True :    
        if memory[pointer] == 1 :
            memory[memory[pointer+3]] = memory[memory[pointer+1]] + memory[memory[pointer+2]]
            pointer+=4      
        elif memory[pointer] == 2:
            memory[memory[pointer+3]] = memory[memory[pointer+1]] * memory[memory[pointer+2]]
            pointer+=4
        elif memory[pointer] == 99:
            break
        else:
            print("FUCK")
            
    print(memory)
    

    It was fun having my program spit out a scrolling wall of "FUCK" when I implemented it wrong the first time 🙃

    Part 2
    def convertolist(flist):
        stripped = flist.rstrip('\n')
        split = stripped.split(',')
        tape = [int(x)  for x in split]
        return tape
    
    def IntCode(memory):
        pointer = 0
        while True :      
            if memory[pointer] == 1 :
                memory[memory[pointer+3]] = memory[memory[pointer+1]] + memory[memory[pointer+2]]
                pointer+=4
            elif memory[pointer] == 2:
                memory[memory[pointer+3]] = memory[memory[pointer+1]] * memory[memory[pointer+2]]
                pointer+=4
            elif memory[pointer] == 99:
                break
            else:
                print("FUCK")
        return memory[0]
    
    def verbnounfinder():
        init_memory = convertolist(readfile)
        trymemory = init_memory[:]
        for x in range(100):
            trymemory[1] = x
            for y in range(100):
                trymemory[2] = y
                if IntCode(trymemory) == 19690720:
                    print(trymemory[0:3])
                    break
                trymemory = init_memory[:]
                trymemory[1] = x
            trymemory = init_memory[:]
            
    
    with open('input_p1only.txt', 'r') as inpfile:
        readfile = inpfile.read()
    verbnounfinder()
    

    if anyone has any tips for making the verbnounfinder function any neater please tell me because it is a mess.

    2 votes
    1. [3]
      Deimos
      (edited )
      Link Parent
      A few quick suggestions on your Day 1 solution, for more idiomatic/simpler Python approaches (I'll only do Part 1 since Part 2 is very similar with just the first function changed): Part 1 def...

      A few quick suggestions on your Day 1 solution, for more idiomatic/simpler Python approaches (I'll only do Part 1 since Part 2 is very similar with just the first function changed):

      Part 1
      def mod_fuel(mass):
          return (mass // 3) - 2
      
      # This basically means "if they're running this file", so this code will run
      # when you do something like (if this file is day1.py): python day1.py
      # It's not really necessary for simple cases like this where you'll always be
      # running this file anyway, but it's a good habit to get into, since otherwise
      # the "top-level" code will run if something else was to import this file.
      if __name__ == "__main__":
          # Generally you should open files using a "with" statement like this, which
          # handles closing the file and other cleanup when its indented block ends.
          with open("day1input.txt") as input_file:
              # This is a "list comprehension", and will load all the lines of the
              # file into this list while also converting them all to integers.
              module_masses = [int(line) for line in input_file]
      
          # Another list comprehension, calling mod_fuel() on each item in the list.
          module_fuel_reqs = [mod_fuel(mass) for mass in module_masses]
      
          # There's a built-in sum() function you can use on lists and other
          # sequences, no need to do it manually.
          print(sum(module_fuel_reqs))
      

      @HanakoIsBestGirl these would be good for you to know as well.

      5 votes
      1. hhh
        Link Parent
        thank you for showing that to me! i'll make sure to do that in my future versions. this was pointed out by the friendly denizens of /aocg/ as well so this is fixed from day 2 onwards :)

        if __name__ == "__main__":

        thank you for showing that to me! i'll make sure to do that in my future versions.

        with open

        list comprehension

        this was pointed out by the friendly denizens of /aocg/ as well so this is fixed from day 2 onwards :)

        2 votes
      2. unknown user
        Link Parent
        Thank you. I have noted and bookmarked this. Unfortunately I've already done half of day 3, but I'll consider this in part 2 (if I can do it). (and oh boy is my part 1 solution bad)

        Thank you. I have noted and bookmarked this. Unfortunately I've already done half of day 3, but I'll consider this in part 2 (if I can do it). (and oh boy is my part 1 solution bad)

        1 vote
  10. starchturrets
    Link
    This is fun! I'm doing it in JavaScript because it's the only language I know. Day 1 'use strict'; // Put everything in an async IIFE to use await (async () => { const res = await...

    This is fun! I'm doing it in JavaScript because it's the only language I know.

    Day 1
    'use strict';
    
    // Put everything in an async IIFE to use await
    (async () => {
      const res = await fetch('./rocket.txt');
      const text = await res.text();
      const arr = text.split('\n');
      arr.pop();
    
      // PART 1
      const mass = arr.reduce((acc, number) => acc + Math.floor(number / 3) - 2, 0);
      console.log(mass);
      // PART 2
      const calcModule = fuel => {
        const numbers = [];
        const generateArr = num => {
          const result = Math.floor(num / 3) - 2;
          numbers.push(result);
          if (result > 0) generateArr(result);
        };
        generateArr(fuel);
        return numbers.filter(num => num > 0).reduce((acc, num) => acc + num, 0);
      };
      const solution = arr.map(calcModule).reduce((acc, num) => acc + num, 0);
    
      console.log(solution);
    })();
    
    2 votes
  11. tesseractcat
    Link
    This is my first time doing one of these. I wanted to try something a little more adventurous so I'm going to attempt to solve all of these puzzles in Befunge. I'm probably not going to get very...

    This is my first time doing one of these. I wanted to try something a little more adventurous so I'm going to attempt to solve all of these puzzles in Befunge. I'm probably not going to get very far before it gets too hard.

    Day 1

    Day 1 was simple enough, a good opportunity to reintegrate myself with the language.

    Part 1
    v
    0
       >3/2-v
    v      +<
    >&:|
       >$.@
    
    Part 2
    v
    0
        >>  3/2-v
    v    : v< 
         ^ <|`0:<
            >$     >\:#v_v
                   ^ +\<
    v          +$        <
    >0&:|
        >$$.@
    

    Day 2

    Day 2 was definitely significantly more challenging, but the puzzle worked well with the put and get instructions in Befunge.

    Part 1

    This snippet of code might not work in all Befunge interpreters/compilers. I saw nothing in the spec that said I couldn't use the put instruction to store arbitrarily large numbers, but it doesn't work consistently. I actually created my own interpreter for this to run more smoothly (also so I could enter all the inputs as one array, rather than individually at each &).

    v                                                             
    
    1      >v
    >: &:1+|>68*    + \0p 1+ v  <-- Encoder
    ^                        < 
           >$$$ 1v
               > >:0g 68*-    v
                
                 v            <   <-- Opcode processing 
    
                 > :1-#v_$ 1+:0g68*- 1+0 g68*-               v
                 v     <v g10 +*86+p10\  -*86g 0+1 -*86g0:+1\<
                        > 1+0g68*- 1+0 p  01g 1+              v
                 v                                      
    
    
                 > :2-#v_$ 1+:0g68*- 1+0 g68*-               v
                 v     <v g10 +*86*p10\  -*86g 0+1 -*86g0:+1\<
                        > 1+0g68*- 1+0 p  01g 1+              v
                 v                                      
    
                 >:25*9*9+-#v_$$0>1+:0g68*-:44*+#v_@
               + v          <    ^          ," ".<
               1 $
               ^ <                                            <
    
    Part 2

    I just brute forced this section by manually trying a lot of different values.

    Day 3

    In progress...

    2 votes