summaryrefslogtreecommitdiff
path: root/2018/aoc2018-d17.py
diff options
context:
space:
mode:
Diffstat (limited to '2018/aoc2018-d17.py')
-rw-r--r--2018/aoc2018-d17.py144
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);