diff options
Diffstat (limited to '2018/aoc2018-d17.py')
-rw-r--r-- | 2018/aoc2018-d17.py | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/2018/aoc2018-d17.py b/2018/aoc2018-d17.py new file mode 100644 index 0000000..30cd726 --- /dev/null +++ b/2018/aoc2018-d17.py @@ -0,0 +1,144 @@ +#advent of code 2018 +#day 17 +#part 1 and part 2 + +#for me this is one of the most time consuming puzzles for this year +#I got too cocky because I remembered a similar puzzle during 2022 edition +#unfortunately 2018 day 17 was more tricky +#I made 3 attempts, each time starting from scratch +#first time I just scrambled something, but there was no way to calculate when to stop the algo +#so the water was extremely overflowing +#for second attempt I wrote 2 functions, one for flowing downwards, second for spreading +#I spent a whole day "improving" the spreading function so it behaves correctly, to no avail +#I figured out the logic of the puzzle, but I kept getting weird errors +#such as water bursting through walls or flowing upwards +#I was adding more and more if-elses, but they weren't fixing these bugs: +#they were merely delaying them - after filling in the water correctly, the bugs were popping up again +#third and final attempt was successful - I already learned the logic of the algorithm, +#I just needed to implement it in bug-free way +#on the other hand, I managed to get a pretty good runtime. +#Every now and then I was looking up a solution for clues from others +#one of which Michael Fogleman, probably my most common resource for learning AoC 2018 +#while his code runs for almost a minute, mine just needs less than 0.05 secs +#it's really funny to "outperform" (in a way) someone whom you were constantly consulting for help +#one last thing I want to mention is that during the third attempt I kept getting wrong answer +#since I was only off by 3 and at the end there are only 3 waterfalls connecting to lowest point, +#I was convinced that I was calculating the solution for wrong range +#turns out I misunderstood the puzzle - you're supposed to calculate the amount of still +#and flowing water in range of highest wall point and the lowest wall point, +#while I kept calculating it in range from zero to lowest +#at least this time part2 was a freebee + +import time; + +f = open("input.txt",'r'); +Testing = False; +#Testing = True; +if Testing: + f.close(); + f = open("testinput.txt",'r'); + +def parse_input(line): + line = line.replace("x=",""); + line = line.replace("y=",""); + line = line.replace("..",","); + line = "[" + line + "]"; + cords = eval(line); + return cords; #line coordinates: [x, y1, y2] or [y, x1, x2] + +Xmax = 500; #rightmost X coordinate, just for printing the area +Xmin = 500; #leftmost X coordinate, just for printing the area +Ymax = 0; #lowest Y coordinate, needed for solution +Ymin2 = 2000; #highest Y coordinate, needed for solution +LinesX = []; +LinesY = []; + +for l in f: + d = l[0]; #direction x or y + Cords = parse_input(l); + if d == "x": + Xmax = max(Cords[0], Xmax); + Xmin = min(Cords[0], Xmin); + Ymax = max(Cords[2], Ymax); + Ymin2 = min(Cords[1], Ymin2); + LinesX.append(Cords); + else: + Xmax = max(Cords[2], Xmax); + Xmin = min(Cords[1], Xmin); + Ymax = max(Cords[0], Ymax); + Ymin2 = min(Cords[0], Ymin2); + LinesY.append(Cords); + +Xmax += 1; +Xmin -= 1; +Ymin = 0; + +area = {}; +#initialize input into the area +for l in LinesX: + x = l[0]; + for y in range(l[1],l[2]+1): + area.update({(x,y):"#"}); +for l in LinesY: + y = l[0]; + for x in range(l[1],l[2]+1): + area.update({(x,y):"#"}); + +def wspread(cords, q): + r1 = 0; + r2 = 0; + x,y = cords; + while (area.get((x,y+1)," ") == "#" or area.get((x,y+1)," ") == "=") and area.get((x-1,y)," ") != "#": + r1 += 1; + x -= 1; + + x,y = cords; + while (area.get((x,y+1)," ") == "#" or area.get((x,y+1)," ") == "=") and area.get((x+1,y)," ") != "#": + r2 += 1; + x += 1; + + x,y = cords; + if area.get((x-r1-1,y)," ") == "#" and area.get((x+r2+1,y)," ") == "#": + for r in range(x-r1,x+r2+1): + area[(r,y)] = "="; + q.append((cords[0],cords[1]-1)); + else: + for r in range(x-r1,x+r2+1): + area[(r,y)] = "|"; + if area[(x-r1,y)] != "#" and area.get((x-r1,y+1)," ") == " ": + q.append((x-r1,y)); + if area[(x+r2,y)] != "#" and area.get((x+r2,y+1)," ") == " ": + q.append((x+r2,y)); + +def wfall(cords, q): + x,y = cords; + while area.get((x,y+1)," ")==" " and y < Ymax: + area[(x,y+1)] = "|"; + y += 1; + if area.get((x,y)," ")=="#" or area.get((x,y)," ")=="=": + q.append((x,y-1)); + elif y < Ymax: + q.append((x,y)); + +t1 = time.time(); +water = [(500,0)]; +area.update({(500,0):"|"}); + +while water: + w = water.pop(); + if area.get((w[0],w[1]+1)," ")==" ": + wfall(w, water); + else: + wspread(w, water); + +part1 = 0; +part2 = 0; +for a in area: + part1 += 1*(area[a]=="|" or area[a]=="=")*(a[1] >= Ymin2); + part2 += 1*(area[a]=="="); + +t2 = time.time(); + +print("part1 = ", part1); +print("part2 = ", part2); +print("runtime ", t2-t1); |