Compare commits
7 commits
7fa305d55d
...
913c012114
| Author | SHA1 | Date | |
|---|---|---|---|
| 913c012114 | |||
| 53bd9bac44 | |||
| cbbd4abf57 | |||
| 8867b061ff | |||
| d4c99a01c0 | |||
| 021b70953a | |||
| 0cddc55192 |
7 changed files with 2397 additions and 0 deletions
116
2025/d08/ex1/ex1.py
Executable file
116
2025/d08/ex1/ex1.py
Executable file
|
|
@ -0,0 +1,116 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import collections
|
||||
import itertools
|
||||
import math
|
||||
import sys
|
||||
from collections.abc import Iterable
|
||||
from typing import Generic, Hashable, NamedTuple, TypeVar
|
||||
|
||||
|
||||
class Point(NamedTuple):
|
||||
x: int
|
||||
y: int
|
||||
z: int
|
||||
|
||||
|
||||
class UnionFind:
|
||||
_parent: list[int]
|
||||
_rank: list[int]
|
||||
|
||||
def __init__(self, size: int):
|
||||
# Each node is in its own set, making it its own parent...
|
||||
self._parent = list(range(size))
|
||||
# ... And its rank 0
|
||||
self._rank = [0] * size
|
||||
|
||||
def find(self, elem: int) -> int:
|
||||
while (parent := self._parent[elem]) != elem:
|
||||
# Replace each parent link by a link to the grand-parent
|
||||
elem, self._parent[elem] = parent, self._parent[parent]
|
||||
return elem
|
||||
|
||||
def union(self, lhs: int, rhs: int) -> int:
|
||||
lhs = self.find(lhs)
|
||||
rhs = self.find(rhs)
|
||||
# Bail out early if they already belong to the same set
|
||||
if lhs == rhs:
|
||||
return lhs
|
||||
# Always keep `lhs` as the taller tree
|
||||
if self._rank[lhs] < self._rank[rhs]:
|
||||
lhs, rhs = rhs, lhs
|
||||
# Merge the smaller tree into the taller one
|
||||
self._parent[rhs] = lhs
|
||||
# Update the rank when merging trees of approximately the same size
|
||||
if self._rank[lhs] == self._rank[rhs]:
|
||||
self._rank[lhs] += 1
|
||||
return lhs
|
||||
|
||||
def sets(self) -> dict[int, set[int]]:
|
||||
res: dict[int, set[int]] = collections.defaultdict(set)
|
||||
for elem in range(len(self._parent)):
|
||||
res[self.find(elem)].add(elem)
|
||||
return dict(res)
|
||||
|
||||
|
||||
# PEP 695 still not supported by MyPy...
|
||||
T = TypeVar("T", bound=Hashable)
|
||||
|
||||
|
||||
class DisjointSet(Generic[T]):
|
||||
_values: list[T]
|
||||
_to_index: dict[T, int]
|
||||
_sets: UnionFind
|
||||
|
||||
def __init__(self, values: Iterable[T]) -> None:
|
||||
self._values = list(values)
|
||||
self._to_index = {v: i for i, v in enumerate(self._values)}
|
||||
self._sets = UnionFind(len(self._values))
|
||||
|
||||
def find(self, elem: T) -> T:
|
||||
return self._values[self._sets.find(self._to_index[elem])]
|
||||
|
||||
def union(self, lhs: T, rhs: T) -> T:
|
||||
return self._values[self._sets.union(self._to_index[lhs], self._to_index[rhs])]
|
||||
|
||||
def sets(self) -> dict[T, set[T]]:
|
||||
sets = self._sets.sets()
|
||||
return {
|
||||
self._values[r]: {self._values[i] for i in values}
|
||||
for r, values in sets.items()
|
||||
}
|
||||
|
||||
|
||||
def solve(input: list[str]) -> int:
|
||||
def parse(input: list[str]) -> list[Point]:
|
||||
return [Point(*map(int, line.split(","))) for line in input]
|
||||
|
||||
def sq_dist(p: Point, other: Point) -> int:
|
||||
return sum(abs(a - b) ** 2 for a, b in zip(p, other))
|
||||
|
||||
def list_connections(boxes: list[Point]) -> list[tuple[Point, Point]]:
|
||||
connections = itertools.combinations(boxes, 2)
|
||||
return sorted(connections, key=lambda con: sq_dist(*con))
|
||||
|
||||
def connect_boxes(boxes: list[Point], n: int = 1000) -> DisjointSet[Point]:
|
||||
connections = list_connections(boxes)
|
||||
sets = DisjointSet(boxes)
|
||||
for a, b in connections[:n]:
|
||||
sets.union(a, b)
|
||||
return sets
|
||||
|
||||
boxes = parse(input)
|
||||
connected = connect_boxes(boxes)
|
||||
circuit_sizes = collections.Counter(
|
||||
{r: len(val) for r, val in connected.sets().items()}
|
||||
)
|
||||
return math.prod(size for _, size in circuit_sizes.most_common(3))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
input = sys.stdin.read().splitlines()
|
||||
print(solve(input))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
108
2025/d08/ex2/ex2.py
Executable file
108
2025/d08/ex2/ex2.py
Executable file
|
|
@ -0,0 +1,108 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import collections
|
||||
import itertools
|
||||
import sys
|
||||
from collections.abc import Iterable
|
||||
from typing import Generic, Hashable, NamedTuple, TypeVar
|
||||
|
||||
|
||||
class Point(NamedTuple):
|
||||
x: int
|
||||
y: int
|
||||
z: int
|
||||
|
||||
|
||||
class UnionFind:
|
||||
_parent: list[int]
|
||||
_rank: list[int]
|
||||
|
||||
def __init__(self, size: int):
|
||||
self._parent = list(range(size))
|
||||
self._rank = [0] * size
|
||||
|
||||
def find(self, elem: int) -> int:
|
||||
while (parent := self._parent[elem]) != elem:
|
||||
elem, self._parent[elem] = parent, self._parent[parent]
|
||||
return elem
|
||||
|
||||
def union(self, lhs: int, rhs: int) -> bool:
|
||||
lhs = self.find(lhs)
|
||||
rhs = self.find(rhs)
|
||||
if lhs == rhs:
|
||||
return False
|
||||
if self._rank[lhs] < self._rank[rhs]:
|
||||
lhs, rhs = rhs, lhs
|
||||
self._parent[rhs] = lhs
|
||||
if self._rank[lhs] == self._rank[rhs]:
|
||||
self._rank[lhs] += 1
|
||||
return True
|
||||
|
||||
def sets(self) -> dict[int, set[int]]:
|
||||
res: dict[int, set[int]] = collections.defaultdict(set)
|
||||
for elem in range(len(self._parent)):
|
||||
res[self.find(elem)].add(elem)
|
||||
return dict(res)
|
||||
|
||||
|
||||
# PEP 695 still not supported by MyPy...
|
||||
T = TypeVar("T", bound=Hashable)
|
||||
|
||||
|
||||
class DisjointSet(Generic[T]):
|
||||
_values: list[T]
|
||||
_to_index: dict[T, int]
|
||||
_sets: UnionFind
|
||||
|
||||
def __init__(self, values: Iterable[T]) -> None:
|
||||
self._values = list(values)
|
||||
self._to_index = {v: i for i, v in enumerate(self._values)}
|
||||
self._sets = UnionFind(len(self._values))
|
||||
|
||||
def find(self, elem: T) -> T:
|
||||
return self._values[self._sets.find(self._to_index[elem])]
|
||||
|
||||
def union(self, lhs: T, rhs: T) -> bool:
|
||||
return self._sets.union(self._to_index[lhs], self._to_index[rhs])
|
||||
|
||||
def sets(self) -> dict[T, set[T]]:
|
||||
sets = self._sets.sets()
|
||||
return {
|
||||
self._values[r]: {self._values[i] for i in values}
|
||||
for r, values in sets.items()
|
||||
}
|
||||
|
||||
|
||||
def solve(input: list[str]) -> int:
|
||||
def parse(input: list[str]) -> list[Point]:
|
||||
return [Point(*map(int, line.split(","))) for line in input]
|
||||
|
||||
def sq_dist(p: Point, other: Point) -> int:
|
||||
return sum(abs(a - b) ** 2 for a, b in zip(p, other))
|
||||
|
||||
def list_connections(boxes: list[Point]) -> list[tuple[Point, Point]]:
|
||||
connections = itertools.combinations(boxes, 2)
|
||||
return sorted(connections, key=lambda con: sq_dist(*con))
|
||||
|
||||
def connect_boxes(boxes: list[Point]) -> tuple[Point, Point]:
|
||||
connections = list_connections(boxes)
|
||||
sets = DisjointSet(boxes)
|
||||
num_sets = len(boxes)
|
||||
for a, b in connections:
|
||||
num_sets -= sets.union(a, b)
|
||||
if num_sets == 1:
|
||||
return a, b
|
||||
assert False
|
||||
|
||||
boxes = parse(input)
|
||||
last_connection = connect_boxes(boxes)
|
||||
return last_connection[0].x * last_connection[1].x
|
||||
|
||||
|
||||
def main() -> None:
|
||||
input = sys.stdin.read().splitlines()
|
||||
print(solve(input))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1000
2025/d08/ex2/input
Normal file
1000
2025/d08/ex2/input
Normal file
File diff suppressed because it is too large
Load diff
32
2025/d09/ex1/ex1.py
Executable file
32
2025/d09/ex1/ex1.py
Executable file
|
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import itertools
|
||||
import sys
|
||||
from typing import NamedTuple
|
||||
|
||||
|
||||
class Point(NamedTuple):
|
||||
x: int
|
||||
y: int
|
||||
|
||||
|
||||
def solve(input: list[str]) -> int:
|
||||
def parse(input: list[str]) -> list[Point]:
|
||||
return [Point(*map(int, line.split(","))) for line in input]
|
||||
|
||||
def rectangle_area(p: Point, other: Point) -> int:
|
||||
dx = abs(p.x - other.x)
|
||||
dy = abs(p.y - other.y)
|
||||
return (dx + 1) * (dy + 1)
|
||||
|
||||
tiles = parse(input)
|
||||
return max(rectangle_area(a, b) for a, b in itertools.combinations(tiles, 2))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
input = sys.stdin.read().splitlines()
|
||||
print(solve(input))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
496
2025/d09/ex1/input
Normal file
496
2025/d09/ex1/input
Normal file
|
|
@ -0,0 +1,496 @@
|
|||
97918,50201
|
||||
97918,51425
|
||||
98247,51425
|
||||
98247,52647
|
||||
98195,52647
|
||||
98195,53859
|
||||
98005,53859
|
||||
98005,55071
|
||||
97872,55071
|
||||
97872,56297
|
||||
97835,56297
|
||||
97835,57522
|
||||
97759,57522
|
||||
97759,58659
|
||||
97171,58659
|
||||
97171,59849
|
||||
96924,59849
|
||||
96924,61075
|
||||
96832,61075
|
||||
96832,62278
|
||||
96613,62278
|
||||
96613,63385
|
||||
96045,63385
|
||||
96045,64538
|
||||
95663,64538
|
||||
95663,65837
|
||||
95705,65837
|
||||
95705,66999
|
||||
95314,66999
|
||||
95314,68121
|
||||
94816,68121
|
||||
94816,69159
|
||||
94132,69159
|
||||
94132,70235
|
||||
93557,70235
|
||||
93557,71392
|
||||
93150,71392
|
||||
93150,72594
|
||||
92813,72594
|
||||
92813,73464
|
||||
91858,73464
|
||||
91858,74283
|
||||
90857,74283
|
||||
90857,75827
|
||||
91050,75827
|
||||
91050,76622
|
||||
90026,76622
|
||||
90026,77623
|
||||
89334,77623
|
||||
89334,78461
|
||||
88419,78461
|
||||
88419,79592
|
||||
87898,79592
|
||||
87898,80529
|
||||
87121,80529
|
||||
87121,81258
|
||||
86103,81258
|
||||
86103,82506
|
||||
85676,82506
|
||||
85676,82951
|
||||
84373,82951
|
||||
84373,84417
|
||||
84129,84417
|
||||
84129,84738
|
||||
82744,84738
|
||||
82744,85431
|
||||
81740,85431
|
||||
81740,86272
|
||||
80874,86272
|
||||
80874,86984
|
||||
79898,86984
|
||||
79898,87707
|
||||
78934,87707
|
||||
78934,88651
|
||||
78132,88651
|
||||
78132,89825
|
||||
77471,89825
|
||||
77471,90048
|
||||
76152,90048
|
||||
76152,91026
|
||||
75332,91026
|
||||
75332,91113
|
||||
73969,91113
|
||||
73969,92433
|
||||
73319,92433
|
||||
73319,92653
|
||||
72052,92653
|
||||
72052,92817
|
||||
70779,92817
|
||||
70779,93561
|
||||
69793,93561
|
||||
69793,94429
|
||||
68844,94429
|
||||
68844,94816
|
||||
67683,94816
|
||||
67683,94825
|
||||
66387,94825
|
||||
66387,95504
|
||||
65340,95504
|
||||
65340,96215
|
||||
64286,96215
|
||||
64286,95778
|
||||
62890,95778
|
||||
62890,96609
|
||||
61858,96609
|
||||
61858,97235
|
||||
60751,97235
|
||||
60751,97506
|
||||
59554,97506
|
||||
59554,97496
|
||||
58306,97496
|
||||
58306,97162
|
||||
57021,97162
|
||||
57021,97638
|
||||
55863,97638
|
||||
55863,98017
|
||||
54678,98017
|
||||
54678,98087
|
||||
53458,98087
|
||||
53458,98404
|
||||
52250,98404
|
||||
52250,98467
|
||||
51023,98467
|
||||
51023,97591
|
||||
49799,97591
|
||||
49799,97549
|
||||
48594,97549
|
||||
48594,97447
|
||||
47393,97447
|
||||
47393,97559
|
||||
46176,97559
|
||||
46176,97590
|
||||
44957,97590
|
||||
44957,97139
|
||||
43794,97139
|
||||
43794,97718
|
||||
42484,97718
|
||||
42484,97235
|
||||
41328,97235
|
||||
41328,97025
|
||||
40129,97025
|
||||
40129,96569
|
||||
38986,96569
|
||||
38986,96439
|
||||
37767,96439
|
||||
37767,96227
|
||||
36561,96227
|
||||
36561,95775
|
||||
35425,95775
|
||||
35425,95708
|
||||
34160,95708
|
||||
34160,94873
|
||||
33165,94873
|
||||
33165,94442
|
||||
32030,94442
|
||||
32030,93853
|
||||
30961,93853
|
||||
30961,93475
|
||||
29801,93475
|
||||
29801,93145
|
||||
28610,93145
|
||||
28610,92571
|
||||
27533,92571
|
||||
27533,91778
|
||||
26580,91778
|
||||
26580,91054
|
||||
25599,91054
|
||||
25599,90700
|
||||
24392,90700
|
||||
24392,90098
|
||||
23330,90098
|
||||
23330,89610
|
||||
22181,89610
|
||||
22181,88575
|
||||
21422,88575
|
||||
21422,87836
|
||||
20456,87836
|
||||
20456,87257
|
||||
19358,87257
|
||||
19358,86584
|
||||
18325,86584
|
||||
18325,85761
|
||||
17416,85761
|
||||
17416,84396
|
||||
17026,84396
|
||||
17026,83497
|
||||
16219,83497
|
||||
16219,82724
|
||||
15282,82724
|
||||
15282,81812
|
||||
14488,81812
|
||||
14488,81287
|
||||
13242,81287
|
||||
13242,80044
|
||||
12835,80044
|
||||
12835,79273
|
||||
11850,79273
|
||||
11850,78300
|
||||
11117,78300
|
||||
11117,77140
|
||||
10654,77140
|
||||
10654,76100
|
||||
10032,76100
|
||||
10032,75292
|
||||
9038,75292
|
||||
9038,74404
|
||||
8140,74404
|
||||
8140,73087
|
||||
7988,73087
|
||||
7988,71995
|
||||
7455,71995
|
||||
7455,71036
|
||||
6653,71036
|
||||
6653,69869
|
||||
6271,69869
|
||||
6271,68669
|
||||
5984,68669
|
||||
5984,67752
|
||||
5008,67752
|
||||
5008,66446
|
||||
5011,66446
|
||||
5011,65435
|
||||
4213,65435
|
||||
4213,64209
|
||||
4035,64209
|
||||
4035,63114
|
||||
3426,63114
|
||||
3426,61827
|
||||
3512,61827
|
||||
3512,60715
|
||||
2925,60715
|
||||
2925,59521
|
||||
2657,59521
|
||||
2657,58341
|
||||
2305,58341
|
||||
2305,57063
|
||||
2555,57063
|
||||
2555,55868
|
||||
2321,55868
|
||||
2321,54631
|
||||
2469,54631
|
||||
2469,53453
|
||||
1978,53453
|
||||
1978,52239
|
||||
1840,52239
|
||||
1840,51023
|
||||
1568,51023
|
||||
1568,50187
|
||||
94581,50187
|
||||
94581,48595
|
||||
2489,48595
|
||||
2489,47360
|
||||
1948,47360
|
||||
1948,46149
|
||||
2099,46149
|
||||
2099,44932
|
||||
2173,44932
|
||||
2173,43745
|
||||
2490,43745
|
||||
2490,42544
|
||||
2663,42544
|
||||
2663,41373
|
||||
3007,41373
|
||||
3007,40066
|
||||
2674,40066
|
||||
2674,39008
|
||||
3523,39008
|
||||
3523,37778
|
||||
3604,37778
|
||||
3604,36502
|
||||
3567,36502
|
||||
3567,35540
|
||||
4584,35540
|
||||
4584,34126
|
||||
4191,34126
|
||||
4191,33194
|
||||
5204,33194
|
||||
5204,32063
|
||||
5639,32063
|
||||
5639,30930
|
||||
6073,30930
|
||||
6073,29848
|
||||
6623,29848
|
||||
6623,28717
|
||||
7070,28717
|
||||
7070,27492
|
||||
7350,27492
|
||||
7350,26613
|
||||
8281,26613
|
||||
8281,25390
|
||||
8594,25390
|
||||
8594,24514
|
||||
9492,24514
|
||||
9492,23522
|
||||
10191,23522
|
||||
10191,22173
|
||||
10377,22173
|
||||
10377,21180
|
||||
11097,21180
|
||||
11097,20343
|
||||
12018,20343
|
||||
12018,19523
|
||||
12942,19523
|
||||
12942,18816
|
||||
13983,18816
|
||||
13983,17981
|
||||
14858,17981
|
||||
14858,16809
|
||||
15376,16809
|
||||
15376,16068
|
||||
16353,16068
|
||||
16353,15030
|
||||
17038,15030
|
||||
17038,14301
|
||||
18019,14301
|
||||
18019,13410
|
||||
18855,13410
|
||||
18855,12559
|
||||
19733,12559
|
||||
19733,12152
|
||||
20957,12152
|
||||
20957,10852
|
||||
21506,10852
|
||||
21506,10788
|
||||
22952,10788
|
||||
22952,9988
|
||||
23871,9988
|
||||
23871,8781
|
||||
24548,8781
|
||||
24548,8442
|
||||
25771,8442
|
||||
25771,7748
|
||||
26780,7748
|
||||
26780,7638
|
||||
28098,7638
|
||||
28098,6597
|
||||
28936,6597
|
||||
28936,6634
|
||||
30295,6634
|
||||
30295,5530
|
||||
31137,5530
|
||||
31137,5119
|
||||
32291,5119
|
||||
32291,5171
|
||||
33611,5171
|
||||
33611,4750
|
||||
34745,4750
|
||||
34745,4394
|
||||
35901,4394
|
||||
35901,4192
|
||||
37101,4192
|
||||
37101,3248
|
||||
38105,3248
|
||||
38105,3209
|
||||
39349,3209
|
||||
39349,2909
|
||||
40529,2909
|
||||
40529,2965
|
||||
41774,2965
|
||||
41774,2208
|
||||
42884,2208
|
||||
42884,2578
|
||||
44163,2578
|
||||
44163,2700
|
||||
45391,2700
|
||||
45391,1938
|
||||
46543,1938
|
||||
46543,2387
|
||||
47786,2387
|
||||
47786,2473
|
||||
48995,2473
|
||||
48995,2002
|
||||
50202,2002
|
||||
50202,1582
|
||||
51430,1582
|
||||
51430,1775
|
||||
52649,1775
|
||||
52649,2210
|
||||
53841,2210
|
||||
53841,2166
|
||||
55067,2166
|
||||
55067,2369
|
||||
56270,2369
|
||||
56270,2715
|
||||
57447,2715
|
||||
57447,2376
|
||||
58742,2376
|
||||
58742,3117
|
||||
59840,3117
|
||||
59840,2894
|
||||
61140,2894
|
||||
61140,3742
|
||||
62185,3742
|
||||
62185,3817
|
||||
63425,3817
|
||||
63425,3989
|
||||
64648,3989
|
||||
64648,5057
|
||||
65573,5057
|
||||
65573,4922
|
||||
66910,4922
|
||||
66910,5185
|
||||
68120,5185
|
||||
68120,5964
|
||||
69117,5964
|
||||
69117,6674
|
||||
70128,6674
|
||||
70128,6710
|
||||
71460,6710
|
||||
71460,7450
|
||||
72454,7450
|
||||
72454,8385
|
||||
73327,8385
|
||||
73327,8392
|
||||
74729,8392
|
||||
74729,9508
|
||||
75475,9508
|
||||
75475,10041
|
||||
76576,10041
|
||||
76576,10869
|
||||
77480,10869
|
||||
77480,11720
|
||||
78357,11720
|
||||
78357,12429
|
||||
79335,12429
|
||||
79335,12852
|
||||
80550,12852
|
||||
80550,13833
|
||||
81313,13833
|
||||
81313,14720
|
||||
82144,14720
|
||||
82144,15684
|
||||
82895,15684
|
||||
82895,16530
|
||||
83752,16530
|
||||
83752,17162
|
||||
84838,17162
|
||||
84838,17952
|
||||
85773,17952
|
||||
85773,18787
|
||||
86668,18787
|
||||
86668,19898
|
||||
87235,19898
|
||||
87235,20534
|
||||
88399,20534
|
||||
88399,21819
|
||||
88718,21819
|
||||
88718,22937
|
||||
89233,22937
|
||||
89233,23968
|
||||
89861,23968
|
||||
89861,24660
|
||||
91036,24660
|
||||
91036,25849
|
||||
91424,25849
|
||||
91424,26916
|
||||
92004,26916
|
||||
92004,27802
|
||||
92933,27802
|
||||
92933,28832
|
||||
93616,28832
|
||||
93616,30336
|
||||
93275,30336
|
||||
93275,31169
|
||||
94394,31169
|
||||
94394,32316
|
||||
94816,32316
|
||||
94816,33403
|
||||
95397,33403
|
||||
95397,34581
|
||||
95737,34581
|
||||
95737,35916
|
||||
95557,35916
|
||||
95557,37120
|
||||
95737,37120
|
||||
95737,38230
|
||||
96258,38230
|
||||
96258,39290
|
||||
97047,39290
|
||||
97047,40627
|
||||
96600,40627
|
||||
96600,41738
|
||||
97237,41738
|
||||
97237,42902
|
||||
97667,42902
|
||||
97667,44190
|
||||
97201,44190
|
||||
97201,45331
|
||||
97913,45331
|
||||
97913,46539
|
||||
98110,46539
|
||||
98110,47754
|
||||
98296,47754
|
||||
98296,48987
|
||||
97943,48987
|
||||
97943,50201
|
||||
149
2025/d09/ex2/ex2.py
Executable file
149
2025/d09/ex2/ex2.py
Executable file
|
|
@ -0,0 +1,149 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import itertools
|
||||
import sys
|
||||
from collections.abc import Iterator
|
||||
from typing import NamedTuple
|
||||
|
||||
|
||||
class Point(NamedTuple):
|
||||
x: int
|
||||
y: int
|
||||
|
||||
|
||||
def solve(input: list[str]) -> int:
|
||||
def parse(input: list[str]) -> list[Point]:
|
||||
return [Point(*map(int, line.split(","))) for line in input]
|
||||
|
||||
def compression_mapping(points: list[Point]) -> dict[Point, Point]:
|
||||
def compress_1d(values: set[int]) -> dict[int, int]:
|
||||
return {val: i for i, val in enumerate(sorted(values))}
|
||||
|
||||
xs = compress_1d({p.x for p in points})
|
||||
ys = compress_1d({p.y for p in points})
|
||||
compress = lambda p: Point(xs[p.x], ys[p.y])
|
||||
|
||||
return {p: compress(p) for p in points}
|
||||
|
||||
def line(p1: Point, p2: Point) -> Iterator[Point]:
|
||||
def inclusive_range_any_order(a: int, b: int) -> Iterator[int]:
|
||||
if a < b:
|
||||
yield from range(a, b + 1)
|
||||
else:
|
||||
yield from range(a, b - 1, -1)
|
||||
|
||||
# Hack-ish work-around to avoid infinite loops
|
||||
if p1 == p2:
|
||||
yield p1
|
||||
return
|
||||
|
||||
xs = inclusive_range_any_order(p1.x, p2.x)
|
||||
ys = inclusive_range_any_order(p1.y, p2.y)
|
||||
|
||||
if p1.x == p2.x:
|
||||
xs = itertools.repeat(p1.x)
|
||||
|
||||
if p1.y == p2.y:
|
||||
ys = itertools.repeat(p1.y)
|
||||
|
||||
yield from map(Point._make, zip(xs, ys))
|
||||
|
||||
def draw_edges(tiles: list[Point]) -> set[Point]:
|
||||
# Close the loop by repeating the first vertex at the end
|
||||
vertices = tiles + [tiles[0]]
|
||||
edges = {p for a, b in itertools.pairwise(vertices) for p in line(a, b)}
|
||||
return edges
|
||||
|
||||
def flood_fill(start: Point, points: set[Point]) -> set[Point]:
|
||||
assert start in points # Sanity check
|
||||
visited: set[Point] = set()
|
||||
stack = [start]
|
||||
while stack:
|
||||
p = stack.pop()
|
||||
visited.add(p)
|
||||
for dx, dy in (
|
||||
(-1, 0),
|
||||
(1, 0),
|
||||
(0, -1),
|
||||
(0, 1),
|
||||
):
|
||||
n = Point(p.x + dx, p.y + dy)
|
||||
if n in visited:
|
||||
continue
|
||||
if n not in points:
|
||||
continue
|
||||
stack.append(n)
|
||||
return visited
|
||||
|
||||
def fill_tiles(tiles: list[Point]) -> set[Point]:
|
||||
# I'm too lazy to find an interior point to flood-fill to the edges from,
|
||||
# instead fill the exterior and invert the set
|
||||
min_x, max_x = min(p.x for p in tiles), max(p.x for p in tiles)
|
||||
min_y, max_y = min(p.y for p in tiles), max(p.y for p in tiles)
|
||||
|
||||
# Keep a border all around to make sure the flood-fill can reach everywhere
|
||||
all_points = {
|
||||
Point(x, y)
|
||||
for x in range(min_x - 1, max_x + 1 + 1)
|
||||
for y in range(min_y - 1, max_y + 1 + 1)
|
||||
}
|
||||
|
||||
edges = draw_edges(tiles)
|
||||
|
||||
# Pick a corner we know for sure won't be in the polygon
|
||||
start = Point(min_x - 1, min_y - 1)
|
||||
|
||||
# Sever the points inside and outside the polygon, then flood-fill exterior
|
||||
exterior = flood_fill(start, all_points - edges)
|
||||
|
||||
# Return interior/edge points by removing everything that is on the exterior
|
||||
return all_points - exterior
|
||||
|
||||
def rectangle_edges(p: Point, other: Point) -> Iterator[Point]:
|
||||
min_x, max_x = min(p.x, other.x), max(p.x, other.x)
|
||||
min_y, max_y = min(p.y, other.y), max(p.y, other.y)
|
||||
|
||||
c1 = Point(min_x, min_y)
|
||||
c2 = Point(max_x, min_y)
|
||||
c3 = Point(max_x, max_y)
|
||||
c4 = Point(min_x, max_y)
|
||||
|
||||
yield from line(c1, c2)
|
||||
yield from line(c2, c3)
|
||||
yield from line(c3, c4)
|
||||
yield from line(c4, c1)
|
||||
|
||||
def rectangle_area(p: Point, other: Point) -> int:
|
||||
dx = abs(p.x - other.x)
|
||||
dy = abs(p.y - other.y)
|
||||
return (dx + 1) * (dy + 1)
|
||||
|
||||
def inscribed_rectangles(tiles: list[Point]) -> Iterator[tuple[Point, Point]]:
|
||||
inside_tiles = fill_tiles(tiles)
|
||||
yield from (
|
||||
(a, b)
|
||||
for a, b in itertools.combinations(tiles, 2)
|
||||
if all(p in inside_tiles for p in rectangle_edges(a, b))
|
||||
)
|
||||
|
||||
def largest_rectangle_area(tiles: list[Point]) -> int:
|
||||
to_compressed = compression_mapping(tiles)
|
||||
decompress = {v: k for k, v in to_compressed.items()}.__getitem__
|
||||
compressed_tiles = [to_compressed[p] for p in tiles]
|
||||
compressed_rectangles = inscribed_rectangles(compressed_tiles)
|
||||
return max(
|
||||
rectangle_area(decompress(a), decompress(b))
|
||||
for a, b in compressed_rectangles
|
||||
)
|
||||
|
||||
tiles = parse(input)
|
||||
return largest_rectangle_area(tiles)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
input = sys.stdin.read().splitlines()
|
||||
print(solve(input))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
496
2025/d09/ex2/input
Normal file
496
2025/d09/ex2/input
Normal file
|
|
@ -0,0 +1,496 @@
|
|||
97918,50201
|
||||
97918,51425
|
||||
98247,51425
|
||||
98247,52647
|
||||
98195,52647
|
||||
98195,53859
|
||||
98005,53859
|
||||
98005,55071
|
||||
97872,55071
|
||||
97872,56297
|
||||
97835,56297
|
||||
97835,57522
|
||||
97759,57522
|
||||
97759,58659
|
||||
97171,58659
|
||||
97171,59849
|
||||
96924,59849
|
||||
96924,61075
|
||||
96832,61075
|
||||
96832,62278
|
||||
96613,62278
|
||||
96613,63385
|
||||
96045,63385
|
||||
96045,64538
|
||||
95663,64538
|
||||
95663,65837
|
||||
95705,65837
|
||||
95705,66999
|
||||
95314,66999
|
||||
95314,68121
|
||||
94816,68121
|
||||
94816,69159
|
||||
94132,69159
|
||||
94132,70235
|
||||
93557,70235
|
||||
93557,71392
|
||||
93150,71392
|
||||
93150,72594
|
||||
92813,72594
|
||||
92813,73464
|
||||
91858,73464
|
||||
91858,74283
|
||||
90857,74283
|
||||
90857,75827
|
||||
91050,75827
|
||||
91050,76622
|
||||
90026,76622
|
||||
90026,77623
|
||||
89334,77623
|
||||
89334,78461
|
||||
88419,78461
|
||||
88419,79592
|
||||
87898,79592
|
||||
87898,80529
|
||||
87121,80529
|
||||
87121,81258
|
||||
86103,81258
|
||||
86103,82506
|
||||
85676,82506
|
||||
85676,82951
|
||||
84373,82951
|
||||
84373,84417
|
||||
84129,84417
|
||||
84129,84738
|
||||
82744,84738
|
||||
82744,85431
|
||||
81740,85431
|
||||
81740,86272
|
||||
80874,86272
|
||||
80874,86984
|
||||
79898,86984
|
||||
79898,87707
|
||||
78934,87707
|
||||
78934,88651
|
||||
78132,88651
|
||||
78132,89825
|
||||
77471,89825
|
||||
77471,90048
|
||||
76152,90048
|
||||
76152,91026
|
||||
75332,91026
|
||||
75332,91113
|
||||
73969,91113
|
||||
73969,92433
|
||||
73319,92433
|
||||
73319,92653
|
||||
72052,92653
|
||||
72052,92817
|
||||
70779,92817
|
||||
70779,93561
|
||||
69793,93561
|
||||
69793,94429
|
||||
68844,94429
|
||||
68844,94816
|
||||
67683,94816
|
||||
67683,94825
|
||||
66387,94825
|
||||
66387,95504
|
||||
65340,95504
|
||||
65340,96215
|
||||
64286,96215
|
||||
64286,95778
|
||||
62890,95778
|
||||
62890,96609
|
||||
61858,96609
|
||||
61858,97235
|
||||
60751,97235
|
||||
60751,97506
|
||||
59554,97506
|
||||
59554,97496
|
||||
58306,97496
|
||||
58306,97162
|
||||
57021,97162
|
||||
57021,97638
|
||||
55863,97638
|
||||
55863,98017
|
||||
54678,98017
|
||||
54678,98087
|
||||
53458,98087
|
||||
53458,98404
|
||||
52250,98404
|
||||
52250,98467
|
||||
51023,98467
|
||||
51023,97591
|
||||
49799,97591
|
||||
49799,97549
|
||||
48594,97549
|
||||
48594,97447
|
||||
47393,97447
|
||||
47393,97559
|
||||
46176,97559
|
||||
46176,97590
|
||||
44957,97590
|
||||
44957,97139
|
||||
43794,97139
|
||||
43794,97718
|
||||
42484,97718
|
||||
42484,97235
|
||||
41328,97235
|
||||
41328,97025
|
||||
40129,97025
|
||||
40129,96569
|
||||
38986,96569
|
||||
38986,96439
|
||||
37767,96439
|
||||
37767,96227
|
||||
36561,96227
|
||||
36561,95775
|
||||
35425,95775
|
||||
35425,95708
|
||||
34160,95708
|
||||
34160,94873
|
||||
33165,94873
|
||||
33165,94442
|
||||
32030,94442
|
||||
32030,93853
|
||||
30961,93853
|
||||
30961,93475
|
||||
29801,93475
|
||||
29801,93145
|
||||
28610,93145
|
||||
28610,92571
|
||||
27533,92571
|
||||
27533,91778
|
||||
26580,91778
|
||||
26580,91054
|
||||
25599,91054
|
||||
25599,90700
|
||||
24392,90700
|
||||
24392,90098
|
||||
23330,90098
|
||||
23330,89610
|
||||
22181,89610
|
||||
22181,88575
|
||||
21422,88575
|
||||
21422,87836
|
||||
20456,87836
|
||||
20456,87257
|
||||
19358,87257
|
||||
19358,86584
|
||||
18325,86584
|
||||
18325,85761
|
||||
17416,85761
|
||||
17416,84396
|
||||
17026,84396
|
||||
17026,83497
|
||||
16219,83497
|
||||
16219,82724
|
||||
15282,82724
|
||||
15282,81812
|
||||
14488,81812
|
||||
14488,81287
|
||||
13242,81287
|
||||
13242,80044
|
||||
12835,80044
|
||||
12835,79273
|
||||
11850,79273
|
||||
11850,78300
|
||||
11117,78300
|
||||
11117,77140
|
||||
10654,77140
|
||||
10654,76100
|
||||
10032,76100
|
||||
10032,75292
|
||||
9038,75292
|
||||
9038,74404
|
||||
8140,74404
|
||||
8140,73087
|
||||
7988,73087
|
||||
7988,71995
|
||||
7455,71995
|
||||
7455,71036
|
||||
6653,71036
|
||||
6653,69869
|
||||
6271,69869
|
||||
6271,68669
|
||||
5984,68669
|
||||
5984,67752
|
||||
5008,67752
|
||||
5008,66446
|
||||
5011,66446
|
||||
5011,65435
|
||||
4213,65435
|
||||
4213,64209
|
||||
4035,64209
|
||||
4035,63114
|
||||
3426,63114
|
||||
3426,61827
|
||||
3512,61827
|
||||
3512,60715
|
||||
2925,60715
|
||||
2925,59521
|
||||
2657,59521
|
||||
2657,58341
|
||||
2305,58341
|
||||
2305,57063
|
||||
2555,57063
|
||||
2555,55868
|
||||
2321,55868
|
||||
2321,54631
|
||||
2469,54631
|
||||
2469,53453
|
||||
1978,53453
|
||||
1978,52239
|
||||
1840,52239
|
||||
1840,51023
|
||||
1568,51023
|
||||
1568,50187
|
||||
94581,50187
|
||||
94581,48595
|
||||
2489,48595
|
||||
2489,47360
|
||||
1948,47360
|
||||
1948,46149
|
||||
2099,46149
|
||||
2099,44932
|
||||
2173,44932
|
||||
2173,43745
|
||||
2490,43745
|
||||
2490,42544
|
||||
2663,42544
|
||||
2663,41373
|
||||
3007,41373
|
||||
3007,40066
|
||||
2674,40066
|
||||
2674,39008
|
||||
3523,39008
|
||||
3523,37778
|
||||
3604,37778
|
||||
3604,36502
|
||||
3567,36502
|
||||
3567,35540
|
||||
4584,35540
|
||||
4584,34126
|
||||
4191,34126
|
||||
4191,33194
|
||||
5204,33194
|
||||
5204,32063
|
||||
5639,32063
|
||||
5639,30930
|
||||
6073,30930
|
||||
6073,29848
|
||||
6623,29848
|
||||
6623,28717
|
||||
7070,28717
|
||||
7070,27492
|
||||
7350,27492
|
||||
7350,26613
|
||||
8281,26613
|
||||
8281,25390
|
||||
8594,25390
|
||||
8594,24514
|
||||
9492,24514
|
||||
9492,23522
|
||||
10191,23522
|
||||
10191,22173
|
||||
10377,22173
|
||||
10377,21180
|
||||
11097,21180
|
||||
11097,20343
|
||||
12018,20343
|
||||
12018,19523
|
||||
12942,19523
|
||||
12942,18816
|
||||
13983,18816
|
||||
13983,17981
|
||||
14858,17981
|
||||
14858,16809
|
||||
15376,16809
|
||||
15376,16068
|
||||
16353,16068
|
||||
16353,15030
|
||||
17038,15030
|
||||
17038,14301
|
||||
18019,14301
|
||||
18019,13410
|
||||
18855,13410
|
||||
18855,12559
|
||||
19733,12559
|
||||
19733,12152
|
||||
20957,12152
|
||||
20957,10852
|
||||
21506,10852
|
||||
21506,10788
|
||||
22952,10788
|
||||
22952,9988
|
||||
23871,9988
|
||||
23871,8781
|
||||
24548,8781
|
||||
24548,8442
|
||||
25771,8442
|
||||
25771,7748
|
||||
26780,7748
|
||||
26780,7638
|
||||
28098,7638
|
||||
28098,6597
|
||||
28936,6597
|
||||
28936,6634
|
||||
30295,6634
|
||||
30295,5530
|
||||
31137,5530
|
||||
31137,5119
|
||||
32291,5119
|
||||
32291,5171
|
||||
33611,5171
|
||||
33611,4750
|
||||
34745,4750
|
||||
34745,4394
|
||||
35901,4394
|
||||
35901,4192
|
||||
37101,4192
|
||||
37101,3248
|
||||
38105,3248
|
||||
38105,3209
|
||||
39349,3209
|
||||
39349,2909
|
||||
40529,2909
|
||||
40529,2965
|
||||
41774,2965
|
||||
41774,2208
|
||||
42884,2208
|
||||
42884,2578
|
||||
44163,2578
|
||||
44163,2700
|
||||
45391,2700
|
||||
45391,1938
|
||||
46543,1938
|
||||
46543,2387
|
||||
47786,2387
|
||||
47786,2473
|
||||
48995,2473
|
||||
48995,2002
|
||||
50202,2002
|
||||
50202,1582
|
||||
51430,1582
|
||||
51430,1775
|
||||
52649,1775
|
||||
52649,2210
|
||||
53841,2210
|
||||
53841,2166
|
||||
55067,2166
|
||||
55067,2369
|
||||
56270,2369
|
||||
56270,2715
|
||||
57447,2715
|
||||
57447,2376
|
||||
58742,2376
|
||||
58742,3117
|
||||
59840,3117
|
||||
59840,2894
|
||||
61140,2894
|
||||
61140,3742
|
||||
62185,3742
|
||||
62185,3817
|
||||
63425,3817
|
||||
63425,3989
|
||||
64648,3989
|
||||
64648,5057
|
||||
65573,5057
|
||||
65573,4922
|
||||
66910,4922
|
||||
66910,5185
|
||||
68120,5185
|
||||
68120,5964
|
||||
69117,5964
|
||||
69117,6674
|
||||
70128,6674
|
||||
70128,6710
|
||||
71460,6710
|
||||
71460,7450
|
||||
72454,7450
|
||||
72454,8385
|
||||
73327,8385
|
||||
73327,8392
|
||||
74729,8392
|
||||
74729,9508
|
||||
75475,9508
|
||||
75475,10041
|
||||
76576,10041
|
||||
76576,10869
|
||||
77480,10869
|
||||
77480,11720
|
||||
78357,11720
|
||||
78357,12429
|
||||
79335,12429
|
||||
79335,12852
|
||||
80550,12852
|
||||
80550,13833
|
||||
81313,13833
|
||||
81313,14720
|
||||
82144,14720
|
||||
82144,15684
|
||||
82895,15684
|
||||
82895,16530
|
||||
83752,16530
|
||||
83752,17162
|
||||
84838,17162
|
||||
84838,17952
|
||||
85773,17952
|
||||
85773,18787
|
||||
86668,18787
|
||||
86668,19898
|
||||
87235,19898
|
||||
87235,20534
|
||||
88399,20534
|
||||
88399,21819
|
||||
88718,21819
|
||||
88718,22937
|
||||
89233,22937
|
||||
89233,23968
|
||||
89861,23968
|
||||
89861,24660
|
||||
91036,24660
|
||||
91036,25849
|
||||
91424,25849
|
||||
91424,26916
|
||||
92004,26916
|
||||
92004,27802
|
||||
92933,27802
|
||||
92933,28832
|
||||
93616,28832
|
||||
93616,30336
|
||||
93275,30336
|
||||
93275,31169
|
||||
94394,31169
|
||||
94394,32316
|
||||
94816,32316
|
||||
94816,33403
|
||||
95397,33403
|
||||
95397,34581
|
||||
95737,34581
|
||||
95737,35916
|
||||
95557,35916
|
||||
95557,37120
|
||||
95737,37120
|
||||
95737,38230
|
||||
96258,38230
|
||||
96258,39290
|
||||
97047,39290
|
||||
97047,40627
|
||||
96600,40627
|
||||
96600,41738
|
||||
97237,41738
|
||||
97237,42902
|
||||
97667,42902
|
||||
97667,44190
|
||||
97201,44190
|
||||
97201,45331
|
||||
97913,45331
|
||||
97913,46539
|
||||
98110,46539
|
||||
98110,47754
|
||||
98296,47754
|
||||
98296,48987
|
||||
97943,48987
|
||||
97943,50201
|
||||
Loading…
Add table
Add a link
Reference in a new issue