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.
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.
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.
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!
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.
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.
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.
This was pretty simple. I'm sure it could be condensed down.
Part 2
importmathdefcalculate(inamount):returnmath.floor((int(inamount)/3))-2#divide by 3, round down, -2withopen('input','r')asf:data=f.read().splitlines()Total=0foriinrange(len(data)):FuelArray=[]FuelArray.append(calculate(data[i]))ifcalculate(data[i])<=0:Total=Total+calculate(data[i])else:whilecalculate(FuelArray[-1])>0:FuelArray.append(calculate(FuelArray[-1]))#-1 means last entryFuelArraySum=0foriinrange(len(FuelArray)):FuelArraySum=FuelArraySum+FuelArray[i]Total=Total+FuelArraySumprint(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=0ipointermax=(len(data)-1)/4#-1 because of 99 at the end.#print(ipointermax)foriinrange(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)ifdata[ipointer]==1:data[data[ipointer+3]]=val1+val2#print(val1 + val2)elifdata[ipointer]==2:data[data[ipointer+3]]=val1*val2#print(val1 * val2)elifdata[ipointer]==99:print('STOP')print('Answer is',data[0])breakelse:print('Something has gone horribly and terribly wrong')breakipointer=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
defcalculate(noun,verb):data=[]#Again, not including my actual input data, it's longipointer=0ipointermax=(len(data)-1)/4#-1 because of 99 at the end.#print(ipointermax)data[1]=noundata[2]=verbforiinrange(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)ifdata[ipointer]==1:data[data[ipointer+3]]=val1+val2#print(val1 + val2)elifdata[ipointer]==2:data[data[ipointer+3]]=val1*val2#print(val1 * val2)elifdata[ipointer]==99:#print('STOP')#print('Answer is', data[0])returndata[0]else:print('Something has gone horribly and terribly wrong')breakipointer=ipointer+4verb=0noun=0forverbinrange(100):fornouninrange(100):ifcalculate(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 tabulatewithopen('input','r')asf:data=f.read().splitlines()foriinrange(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=[['.'foriinrange(20000)]foriinrange(20000)]#Normally 2000'''Key:5 = starting position1 = part of line 12 = part of line 23 = intersection of both linesblank = nothing here'''LinesArray[10000][10000]=5#start point. Normally 1000Position=[10000,10000]#y,x. Normally 1000,1000PositionOriginal=Position#Store this for later...#now to plot the linesforiinrange(len(data)):#Do once for each line. If len(data) is not 2, this will break.Position=[10000,10000]#y,x. Normally 1000,1000ifi==0:CurrentLine=1elifi==1:CurrentLine=2else:print('More lines are not supported!!')breakforjinrange(len(data[i])):Direction=data[i][j][:1]Amount=data[i][j][1:]#print(Direction, Amount)#print(Position)ifDirection=='U':forkinrange(int(Amount)):#print(k)ifLinesArray[Position[0]-k-1][Position[1]]==CurrentLine-1orLinesArray[Position[0]-k-1][Position[1]]==3:#neverhappens on first run. does on secondLinesArray[Position[0]-k-1][Position[1]]=3else:LinesArray[Position[0]-k-1][Position[1]]=CurrentLinePosition[0]=Position[0]-k-1#print(Position)#LinesArray[Position[0]][1] = 2#print(tabulate(LinesArray))elifDirection=='D':forkinrange(int(Amount)):#print(k)ifLinesArray[Position[0]+k+1][Position[1]]==CurrentLine-1orLinesArray[Position[0]+k+1][Position[1]]==3:LinesArray[Position[0]+k+1][Position[1]]=3else:LinesArray[Position[0]+k+1][Position[1]]=CurrentLinePosition[0]=Position[0]+k+1#print(Position)#LinesArray[Position[0]][1] = 2#print(tabulate(LinesArray))elifDirection=='L':forkinrange(int(Amount)):#print(k)ifLinesArray[Position[0]][Position[1]-k-1]==CurrentLine-1orLinesArray[Position[0]-k-1][Position[1]]==3:LinesArray[Position[0]][Position[1]-k-1]=3else:LinesArray[Position[0]][Position[1]-k-1]=CurrentLinePosition[1]=Position[1]-k-1#print(Position)#LinesArray[Position[0]][1] = 2#print(tabulate(LinesArray))elifDirection=='R':forkinrange(int(Amount)):#print(k)ifLinesArray[Position[0]][Position[1]+k+1]==CurrentLine-1orLinesArray[Position[0]][Position[1]+k+1]==3:LinesArray[Position[0]][Position[1]+k+1]=3else:LinesArray[Position[0]][Position[1]+k+1]=CurrentLinePosition[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=[]foriinrange(len(LinesArray)):forjinrange(len(LinesArray[i])):ifLinesArray[i][j]==3:#i is down from top, j is from left going rightSubList=[]SubList.append(i)SubList.append(j)ListOfIntersections.append(SubList)#print(ListOfIntersections)#print(ListOfIntersections)#Now find the one that is the closest...ShortestDistance=-1foriinrange(len(ListOfIntersections)):XDistance=ListOfIntersections[i][1]-PositionOriginal[1]YDistance=ListOfIntersections[i][0]-PositionOriginal[0]ifXDistance<0:XDistance=XDistance*-1ifYDistance<0:YDistance=YDistance*-1ManhattanDistance=XDistance+YDistance#print('pos orig', PositionOriginal)#print(ListOfIntersections[i][1], PositionOriginal[1], XDistance)#print(ListOfIntersections[i][0], PositionOriginal[0], YDistance)#print(ManhattanDistance)ifManhattanDistance<ShortestDistanceorShortestDistance==-1:ShortestDistance=ManhattanDistanceprint('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
withopen('input','r')asf:data=f.read().splitlines()foriinrange(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)foriinrange(len(data[0])):#first lineprint(len(data[0]),i)Direction=data[0][i][:1]Amount=int(data[0][i][1:])ifDirection=='U':forjinrange(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[:])elifDirection=='D':forjinrange(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[:])elifDirection=='L':forjinrange(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[:])elifDirection=='R':forjinrange(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=[]foriinrange(len(data[1])):#second line!print(len(data[1]),i)Direction=data[1][i][:1]Amount=int(data[1][i][1:])ifDirection=='U':forjinrange(Amount):#print(CurrentPos)CurrentPos[1]=CurrentPos[1]+1ifCurrentPosinHistory:IntersectionList.append(CurrentPos[:])elifDirection=='D':forjinrange(Amount):#print(CurrentPos)CurrentPos[1]=CurrentPos[1]-1ifCurrentPosinHistory:IntersectionList.append(CurrentPos[:])elifDirection=='L':forjinrange(Amount):#print(CurrentPos)CurrentPos[0]=CurrentPos[0]-1ifCurrentPosinHistory:IntersectionList.append(CurrentPos[:])elifDirection=='R':forjinrange(Amount):#print(CurrentPos)CurrentPos[0]=CurrentPos[0]+1ifCurrentPosinHistory: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=-1foriinrange(len(IntersectionList)):XDistance=IntersectionList[i][0]-StartPos[0]YDistance=IntersectionList[i][1]-StartPos[1]ifXDistance<0:XDistance=XDistance*-1ifYDistance<0:YDistance=YDistance*-1ManhattanDistance=XDistance+YDistance#print('pos orig', StartPos)#print(IntersectionList[i][0], StartPos[0], XDistance)#print(IntersectionList[i][1], StartPos[1], YDistance)#print(ManhattanDistance)ifManhattanDistance<ShortestDistanceorShortestDistance==-1:ShortestDistance=ManhattanDistanceprint('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.
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:
foriinrange(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:
foritemindata: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.
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.
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.
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 elementssecond_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.
@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.
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?
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.
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 :)
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.
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
defmod_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.withopen("day1input.txt")asinput_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)forlineininput_file]# Another list comprehension, calling mod_fuel() on each item in the list.module_fuel_reqs=[mod_fuel(mass)formassinmodule_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))
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 :)
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)
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()=>{constres=awaitfetch('./rocket.txt');consttext=awaitres.text();constarr=text.split('\n');arr.pop();// PART 1constmass=arr.reduce((acc,number)=>acc+Math.floor(number/3)-2,0);console.log(mass);// PART 2constcalcModule=fuel=>{constnumbers=[];constgenerateArr=num=>{constresult=Math.floor(num/3)-2;numbers.push(result);if(result>0)generateArr(result);};generateArr(fuel);returnnumbers.filter(num=>num>0).reduce((acc,num)=>acc+num,0);};constsolution=arr.map(calcModule).reduce((acc,num)=>acc+num,0);console.log(solution);})();
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
v0>3/2-vv+<>&:|>$.@
Part 2
v0>>3/2-vv: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 &).
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.
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.
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?
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'll give it a go. Do the problems start ramping up in difficulty?
Last year, they sure did.
Yep, they do. First day was easy, third is not obvious at all
Post your solutions here if you do give it a go. It'd be nice to compare solutions.
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 isFile::read_lines
in Crystal, where almost all the other basic utilities have used exactly the same names.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.
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!
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
This was pretty simple. I'm sure it could be condensed down.
Part 2
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
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:
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
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
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
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.
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:
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:
Each time through the loop,
item
will be the current element, the equivalent of yourdata[i]
.Also, when you're adding something to an existing total, you can write
total = total + more
astotal += more
. This works for most other operators too. For example,x = x * y
can bex *= y
, and so on.Oh yes, that is a better way to do it. I didn't know you could iterate things like that!
just a tip--- putting
python
after the three ``` characters will give the code syntax highlightingAh! Thank you for this, I have edited it in.
Fun fact, in Python,
//
is integer division, and will automatically give you the floor of the quotient.Thank you for this tip.
Mathematically, I don't think there is, as properly solving with two variables would require 2 equations.
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.
You can also explicitly make it a copy (instead of a reference) like:
Then if you change elements of
second_list
, it won't affectfirst_list
. @HanakoIsBestGirl'ssecond_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:By not specifying either end of the slice with
[:]
, it goes from the start to the end and effectively copies it.I already ended up figuring this out but thank you!
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.
@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.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?
EDIT: fixed the recursive function. forgot to exit function when
f = 0
🤦. wrong code left up for posterity.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. :)
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
pretty easy for the most part but didn't know how to open a file :(
Part 2
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
It was fun having my program spit out a scrolling wall of "FUCK" when I implemented it wrong the first time 🙃
Part 2
if anyone has any tips for making the
verbnounfinder
function any neater please tell me because it is a mess.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
@HanakoIsBestGirl these would be good for you to know as well.
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 :)
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)
This is fun! I'm doing it in JavaScript because it's the only language I know.
Day 1
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
Part 2
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
&
).Part 2
I just brute forced this section by manually trying a lot of different values.
Day 3
In progress...