Explorar el Código

day 9 python, eto pizdez

metya hace 1 mes
padre
commit
cfc2e32a94
Se han modificado 6 ficheros con 893 adiciones y 1 borrados
  1. 1 1
      aoc2025/aocutils.py
  2. 176 0
      aoc2025/day9/README.md
  3. 0 0
      aoc2025/day9/day9.go
  4. 212 0
      aoc2025/day9/day9.py
  5. 8 0
      aoc2025/day9/example.txt
  6. 496 0
      aoc2025/day9/input.txt

+ 1 - 1
aoc2025/aocutils.py

@@ -95,7 +95,7 @@ def bench(part):
 
 
 if __name__ == "__main__":
-    day = 8
+    day = 9
     root = os.path.dirname(__file__)
     task_dir = os.path.join(root, f"day{day}")
     generate_readme(task_dir, day)

+ 176 - 0
aoc2025/day9/README.md

@@ -0,0 +1,176 @@
+--- Day 9: Movie Theater ---
+----------------------------
+
+You slide down the [firepole](https://en.wikipedia.org/wiki/Fireman%27s_pole) in the corner of the playground and land in the North Pole base movie theater!
+
+The movie theater has a big tile floor with an interesting pattern. Elves here are redecorating the theater by switching out some of the square tiles in the big grid they form. Some of the tiles are *red*; the Elves would like to find the largest rectangle that uses red tiles for two of its opposite corners. They even have a list of where the red tiles are located in the grid (your puzzle input).
+
+For example:
+
+```
+7,1
+11,1
+11,7
+9,7
+9,5
+2,5
+2,3
+7,3
+```
+
+Showing red tiles as `#` and other tiles as `.`, the above arrangement of red tiles would look like this:
+
+```
+..............
+.......#...#..
+..............
+..#....#......
+..............
+..#......#....
+..............
+.........#.#..
+..............
+```
+
+You can choose any two red tiles as the opposite corners of your rectangle; your goal is to find the largest rectangle possible.
+
+For example, you could make a rectangle (shown as `O`) with an area of `24` between `2,5` and `9,7`:
+
+```
+..............
+.......#...#..
+..............
+..#....#......
+..............
+..OOOOOOOO....
+..OOOOOOOO....
+..OOOOOOOO.#..
+..............
+```
+
+Or, you could make a rectangle with area `35` between `7,1` and `11,7`:
+
+```
+..............
+.......OOOOO..
+.......OOOOO..
+..#....OOOOO..
+.......OOOOO..
+..#....OOOOO..
+.......OOOOO..
+.......OOOOO..
+..............
+```
+
+You could even make a thin rectangle with an area of only `6` between `7,3` and `2,3`:
+
+```
+..............
+.......#...#..
+..............
+..OOOOOO......
+..............
+..#......#....
+..............
+.........#.#..
+..............
+```
+
+Ultimately, the largest rectangle you can make in this example has area `50`. One way to do this is between `2,5` and `11,1`:
+
+```
+..............
+..OOOOOOOOOO..
+..OOOOOOOOOO..
+..OOOOOOOOOO..
+..OOOOOOOOOO..
+..OOOOOOOOOO..
+..............
+.........#.#..
+..............
+```
+
+Using two red tiles as opposite corners, *what is the largest area of any rectangle you can make?*
+
+--- Part Two ---
+----------------
+
+The Elves just remembered: they can only switch out tiles that are *red* or *green*. So, your rectangle can only include red or green tiles.
+
+In your list, every red tile is connected to the red tile before and after it by a straight line of *green tiles*. The list wraps, so the first red tile is also connected to the last red tile. Tiles that are adjacent in your list will always be on either the same row or the same column.
+
+Using the same example as before, the tiles marked `X` would be green:
+
+```
+..............
+.......#XXX#..
+.......X...X..
+..#XXXX#...X..
+..X........X..
+..#XXXXXX#.X..
+.........X.X..
+.........#X#..
+..............
+```
+
+In addition, all of the tiles *inside* this loop of red and green tiles are *also* green. So, in this example, these are the green tiles:
+
+```
+..............
+.......#XXX#..
+.......XXXXX..
+..#XXXX#XXXX..
+..XXXXXXXXXX..
+..#XXXXXX#XX..
+.........XXX..
+.........#X#..
+..............
+```
+
+The remaining tiles are never red nor green.
+
+The rectangle you choose still must have red tiles in opposite corners, but any other tiles it includes must now be red or green. This significantly limits your options.
+
+For example, you could make a rectangle out of red and green tiles with an area of `15` between `7,3` and `11,1`:
+
+```
+..............
+.......OOOOO..
+.......OOOOO..
+..#XXXXOOOOO..
+..XXXXXXXXXX..
+..#XXXXXX#XX..
+.........XXX..
+.........#X#..
+..............
+```
+
+Or, you could make a thin rectangle with an area of `3` between `9,7` and `9,5`:
+
+```
+..............
+.......#XXX#..
+.......XXXXX..
+..#XXXX#XXXX..
+..XXXXXXXXXX..
+..#XXXXXXOXX..
+.........OXX..
+.........OX#..
+..............
+```
+
+The largest rectangle you can make in this example using only red and green tiles has area `24`. One way to do this is between `9,5` and `2,3`:
+
+```
+..............
+.......#XXX#..
+.......XXXXX..
+..OOOOOOOOXX..
+..OOOOOOOOXX..
+..OOOOOOOOXX..
+.........XXX..
+.........#X#..
+..............
+```
+
+Using two red tiles as opposite corners, *what is the largest area of any rectangle you can make using only red and green tiles?*

+ 0 - 0
aoc2025/day9/day9.go


+ 212 - 0
aoc2025/day9/day9.py

@@ -0,0 +1,212 @@
+import os
+from functools import lru_cache
+
+with open(os.path.join(os.path.dirname(__file__), "example.txt")) as example:
+    example_data = example.read().splitlines()
+
+with open(os.path.join(os.path.dirname(__file__), "input.txt")) as example:
+    input_data = example.read().splitlines()
+
+
+def bench(part):
+    import time
+
+    def wrapper(*args, **kwargs):
+        start = time.perf_counter()
+        value = part(*args, **kwargs)
+        print(f"\tevaluation time: {time.perf_counter() - start} s")
+        return value
+
+    return wrapper
+
+
+@bench
+def part1(data):
+    points = [list(map(int, point.split(","))) for point in data]
+
+    n = len(points)
+    max_area = 0
+    for i in range(n):
+        x1, y1 = points[i]
+        for j in range(i + 1, n):
+            x2, y2 = points[j]
+            dx = abs(x1 - x2)
+            dy = abs(y1 - y2)
+            area = (dx + 1) * (dy + 1)
+            if area > max_area:
+                max_area = area
+    print(f"Part1: {max_area=}")
+
+
+@bench
+def part2(data):
+
+    def orient(a, b, c):
+        """orient of trinity points: >0 – left, <0 – right, 0 – on the same line."""
+        (x1, y1), (x2, y2), (x3, y3) = a, b, c
+        return (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1)
+
+    def on_segment(a, b, c, incl=False):
+        """point on the line ab"""
+        (x1, y1), (x2, y2), (x3, y3) = a, b, c
+        if incl:
+            return min(x1, x2) <= x3 <= max(x1, x2) and min(y1, y2) <= y3 <= max(y1, y2)
+        else:
+            return min(x1, x2) < x3 < max(x1, x2) and min(y1, y2) < y3 < max(y1, y2)
+
+    def segments_intersect(p1, p2, q1, q2, incl=False):
+        """either cross lines p1-p2 и q1-q2"""
+        o1 = orient(p1, p2, q1)
+        o2 = orient(p1, p2, q2)
+        o3 = orient(q1, q2, p1)
+        o4 = orient(q1, q2, p2)
+
+        # general case
+        if o1 * o2 < 0 and o3 * o4 < 0:
+            return True
+
+        # partial cases: collinearity + adjoint
+        if o1 == 0 and on_segment(p1, p2, q1, incl):
+            return True
+        if o2 == 0 and on_segment(p1, p2, q2, incl):
+            return True
+        if o3 == 0 and on_segment(q1, q2, p1, incl):
+            return True
+        if o4 == 0 and on_segment(q1, q2, p2, incl):
+            return True
+
+        return False
+
+    def point_in_poly(x, y, poly):
+        inside = False
+        n = len(poly)
+        for i in range(n):
+            x1, y1 = poly[i]
+            x2, y2 = poly[(i + 1) % n]
+            if orient((x1, y1), (x2, y2), (x, y)) == 0 and on_segment((x1, y1), (x2, y2), (x, y), incl=True):
+                return True
+
+            # beam to the right from point (x,y)
+            if (y1 > y) != (y2 > y):
+                # x-coord cross with y
+                x_inter = x1 + (x2 - x1) * (y - y1) / (y2 - y1)
+                if x_inter >= x:
+                    inside = not inside
+
+        return inside
+
+    def rect_inside_polygon(p1, p2, poly, cache_func=None):
+        x1, y1 = p1
+        x2, y2 = p2
+        if x1 == x2 or y1 == y2:
+            return False
+
+        xmin, xmax = (x1, x2) if x1 < x2 else (x2, x1)
+        ymin, ymax = (y1, y2) if y1 < y2 else (y2, y1)
+
+        r0 = (xmin, ymin)
+        r1 = (xmin, ymax)
+        r2 = (xmax, ymax)
+        r3 = (xmax, ymin)
+        rect = [r0, r1, r2, r3]
+
+        if cache_func is None:
+
+            def cache_func(xx, yy):
+                return point_in_poly(xx, yy, poly)
+
+        def is_vertex(pt):
+            return pt == p1 or pt == p2
+
+        for xx, yy in rect:
+            if not is_vertex((xx, yy)):
+                if not cache_func(xx, yy):
+                    return False
+
+        # check crossing edges
+        rect_edges = [(r0, r1), (r1, r2), (r2, r3), (r3, r0)]
+        n = len(poly)
+        for e in rect_edges:
+            p_a, p_b = e
+            for i in range(n):
+                q_a = poly[i]
+                q_b = poly[(i + 1) % n]
+                if segments_intersect(p_a, p_b, q_a, q_b, False):
+                    return False
+
+        return True
+
+    # part2
+    poly = [tuple(map(int, point.split(","))) for point in data]
+    alpha = 0.1
+    beta = 0.1
+
+    n = len(poly)
+
+    xs = [x for x, _ in poly]
+    ys = [y for _, y in poly]
+    min_x, max_x = min(xs), max(xs)
+    min_y, max_y = min(ys), max(ys)
+    width = max_x - min_x
+    height = max_y - min_y
+
+    # geometric center
+    cx = sum(xs) / n
+    cy = sum(ys) / n
+
+    # turn to tuple
+    poly_tuple = tuple(poly)
+
+    @lru_cache(maxsize=None)
+    def pip_cached(xx, yy):
+        return point_in_poly(xx, yy, poly_tuple)
+
+    # filter candidates
+    candidates = []
+    for i in range(n):
+        x1, y1 = poly[i]
+        for j in range(i + 1, n):
+            x2, y2 = poly[j]
+            dx = abs(x1 - x2) + 1
+            dy = abs(y1 - y2) + 1
+            if dx == 0 or dy == 0:
+                continue
+
+            # heuristic 1: take only reasonable size of sides
+            if dx < alpha * width or dy < beta * height:
+                continue
+
+            # heuristic 2: points lie on the both side of center
+            # in one quadrant for example
+            if (x1 - cx) * (x2 - cx) > 0 and (y1 - cy) * (y2 - cy) > 0:
+                continue
+
+            area_est = dx * dy
+            candidates.append((area_est, i, j))
+
+    candidates.sort(key=lambda t: t[0], reverse=True)
+
+    best = None  # (area, p1, p2)
+
+    for area_est, i, j in candidates:
+
+        p1 = poly[i]
+        p2 = poly[j]
+        if rect_inside_polygon(p1, p2, poly_tuple, cache_func=pip_cached):
+            area = area_est
+            if best is None or area > best[0]:
+                best = (area, p1, p2)
+
+    if best is None:
+        return None
+
+    area, p1, p2 = best
+    result = {"area": area, "p1": p1, "p2": p2}
+    print(f"Part2: {result}")
+
+
+part1(example_data)
+part1(input_data)
+
+part2(example_data)
+part2(input_data)

+ 8 - 0
aoc2025/day9/example.txt

@@ -0,0 +1,8 @@
+7,1
+11,1
+11,7
+9,7
+9,5
+2,5
+2,3
+7,3

+ 496 - 0
aoc2025/day9/input.txt

@@ -0,0 +1,496 @@
+97978,50277
+97978,51488
+97817,51488
+97817,52688
+97558,52688
+97558,53953
+98224,53953
+98224,55158
+97965,55158
+97965,56343
+97604,56343
+97604,57489
+97068,57489
+97068,58817
+97606,58817
+97606,59849
+96559,59849
+96559,61133
+96749,61133
+96749,62316
+96460,62316
+96460,63403
+95836,63403
+95836,64731
+96019,64731
+96019,65787
+95328,65787
+95328,66770
+94489,66770
+94489,68064
+94475,68064
+94475,69335
+94345,69335
+94345,70209
+93322,70209
+93322,71442
+93080,71442
+93080,72329
+92151,72329
+92151,73318
+91444,73318
+91444,74546
+91151,74546
+91151,75797
+90858,75797
+90858,76720
+90037,76720
+90037,77845
+89516,77845
+89516,78556
+88420,78556
+88420,79540
+87710,79540
+87710,80329
+86759,80329
+86759,81342
+86084,81342
+86084,82390
+85436,82390
+85436,83372
+84703,83372
+84703,84326
+83931,84326
+83931,84661
+82568,84661
+82568,85771
+81944,85771
+81944,86566
+81025,86566
+81025,87005
+79818,87005
+79818,88523
+79464,88523
+79464,88658
+78044,88658
+78044,89368
+77064,89368
+77064,90015
+76041,90015
+76041,90649
+75011,90649
+75011,91513
+74115,91513
+74115,92289
+73153,92289
+73153,92881
+72084,92881
+72084,93315
+70936,93315
+70936,93901
+69864,93901
+69864,94285
+68701,94285
+68701,94570
+67505,94570
+67505,95150
+66425,95150
+66425,95969
+65416,95969
+65416,96222
+64209,96222
+64209,95938
+62857,95938
+62857,97011
+61881,97011
+61881,96332
+60469,96332
+60469,96607
+59297,96607
+59297,97782
+58278,97782
+58278,97929
+57058,97929
+57058,98041
+55836,98041
+55836,97319
+54535,97319
+54535,98323
+53398,98323
+53398,98065
+52158,98065
+52158,97571
+50929,97571
+50929,97763
+49723,97763
+49723,97905
+48508,97905
+48508,97763
+47300,97763
+47300,98324
+46038,98324
+46038,97823
+44856,97823
+44856,97720
+43641,97720
+43641,97442
+42450,97442
+42450,96794
+41333,96794
+41333,96981
+40061,96981
+40061,96920
+38825,96920
+38825,96489
+37675,96489
+37675,96415
+36427,96415
+36427,95956
+35288,95956
+35288,94915
+34356,94915
+34356,94585
+33193,94585
+33193,94542
+31907,94542
+31907,94276
+30695,94276
+30695,93249
+29823,93249
+29823,92789
+28702,92789
+28702,92589
+27438,92589
+27438,92104
+26310,92104
+26310,91205
+25421,91205
+25421,90595
+24369,90595
+24369,89956
+23333,89956
+23333,89205
+22374,89205
+22374,88227
+21587,88227
+21587,88053
+20190,88053
+20190,87370
+19166,87370
+19166,85862
+18850,85862
+18850,85629
+17433,85629
+17433,84806
+16528,84806
+16528,83594
+16014,83594
+16014,83092
+14781,83092
+14781,81980
+14187,81980
+14187,80954
+13516,80954
+13516,80170
+12558,80170
+12558,79270
+11729,79270
+11729,78414
+10830,78414
+10830,77195
+10440,77195
+10440,76141
+9831,76141
+9831,75157
+9113,75157
+9113,74267
+8223,74267
+8223,73289
+7461,73289
+7461,71948
+7383,71948
+7383,70715
+7142,70715
+7142,69659
+6551,69659
+6551,68708
+5698,68708
+5698,67681
+4981,67681
+4981,66577
+4431,66577
+4431,65338
+4262,65338
+4262,64184
+3856,64184
+3856,63017
+3487,63017
+3487,61847
+3124,61847
+3124,60582
+3164,60582
+3164,59324
+3255,59324
+3255,58217
+2569,58217
+2569,56954
+2776,56954
+2776,55748
+2677,55748
+2677,54567
+2341,54567
+2341,53376
+1985,53376
+1985,52150
+2107,52150
+2107,50938
+2012,50938
+2012,50260
+94916,50260
+94916,48492
+1575,48492
+1575,47268
+1673,47268
+1673,46038
+1678,46038
+1678,44848
+2095,44848
+2095,43650
+2345,43650
+2345,42418
+2356,42418
+2356,41295
+3002,41295
+3002,39997
+2718,39997
+2718,38886
+3337,38886
+3337,37597
+3215,37597
+3215,36425
+3577,36425
+3577,35418
+4450,35418
+4450,34048
+4199,34048
+4199,32895
+4624,32895
+4624,31891
+5417,31891
+5417,30681
+5692,30681
+5692,29860
+6828,29860
+6828,28560
+6924,28560
+6924,27596
+7708,27596
+7708,26575
+8367,26575
+8367,25164
+8363,25164
+8363,24466
+9558,24466
+9558,23580
+10414,23580
+10414,22115
+10428,22115
+10428,21429
+11560,21429
+11560,20341
+12139,20341
+12139,19416
+12932,19416
+12932,18242
+13437,18242
+13437,17310
+14236,17310
+14236,16572
+15239,16572
+15239,15856
+16249,15856
+16249,14787
+16913,14787
+16913,13926
+17785,13926
+17785,13512
+19041,13512
+19041,12876
+20086,12876
+20086,12230
+21112,12230
+21112,10788
+21554,10788
+21554,10766
+23028,10766
+23028,9437
+23602,9437
+23602,9072
+24817,9072
+24817,8885
+26116,8885
+26116,7539
+26752,7539
+26752,7352
+28036,7352
+28036,7085
+29256,7085
+29256,6667
+30393,6667
+30393,6211
+31508,6211
+31508,5473
+32512,5473
+32512,4596
+33482,4596
+33482,4562
+34762,4562
+34762,3643
+35749,3643
+35749,3584
+37009,3584
+37009,3597
+38271,3597
+38271,3226
+39430,3226
+39430,2639
+40552,2639
+40552,2960
+41849,2960
+41849,2505
+43005,2505
+43005,2768
+44262,2768
+44262,2590
+45456,2590
+45456,1976
+46622,1976
+46622,2158
+47851,2158
+47851,1736
+49056,1736
+49056,1879
+50278,1879
+50278,1977
+51495,1977
+51495,2389
+52690,2389
+52690,2362
+53905,2362
+53905,2592
+55098,2592
+55098,2036
+56391,2036
+56391,2897
+57495,2897
+57495,2786
+58744,2786
+58744,3497
+59837,3497
+59837,3663
+61035,3663
+61035,3399
+62354,3399
+62354,3525
+63589,3525
+63589,4608
+64530,4608
+64530,5043
+65657,5043
+65657,4752
+67056,4752
+67056,5781
+67960,5781
+67960,6419
+69001,6419
+69001,6759
+70171,6759
+70171,6689
+71556,6689
+71556,7470
+72529,7470
+72529,8583
+73302,8583
+73302,8896
+74517,8896
+74517,9558
+75533,9558
+75533,9755
+76858,9755
+76858,10904
+77548,10904
+77548,11233
+78813,11233
+78813,12198
+79611,12198
+79611,12794
+80697,12794
+80697,13921
+81337,13921
+81337,14522
+82427,14522
+82427,15388
+83284,15388
+83284,16170
+84223,16170
+84223,17007
+85112,17007
+85112,18054
+85773,18054
+85773,19074
+86448,19074
+86448,19856
+87408,19856
+87408,20988
+87931,20988
+87931,21792
+88883,21792
+88883,23080
+89157,23080
+89157,23978
+89985,23978
+89985,24874
+90835,24874
+90835,25943
+91413,25943
+91413,26938
+92121,26938
+92121,27904
+92903,27904
+92903,29245
+92938,29245
+92938,30090
+94002,30090
+94002,31435
+93960,31435
+93960,32410
+94784,32410
+94784,33552
+95211,33552
+95211,34703
+95613,34703
+95613,35959
+95674,35959
+95674,37196
+95747,37196
+95747,38148
+96889,38148
+96889,39505
+96441,39505
+96441,40574
+97251,40574
+97251,41817
+97224,41817
+97224,43023
+97368,43023
+97368,44232
+97474,44232
+97474,45397
+98016,45397
+98016,46600
+98335,46600
+98335,47865
+97528,47865
+97528,49070
+97546,49070
+97546,50277