Add files via upload
This commit is contained in:
1 parent
9cf68a49e8
commit
a6b89dfbc0
1 file changed
+238
-176
+238
-176
@@ -158,7 +158,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 1.1: .0005 seconds, answer 1182 correct"
|
||||
"Puzzle 1.1: .0006 seconds, answer 1182 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
@@ -192,7 +192,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 1.2: .1418 seconds, answer 6907 correct"
|
||||
"Puzzle 1.2: .1639 seconds, answer 6907 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
@@ -242,7 +242,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 1.2: .0009 seconds, answer 6907 correct"
|
||||
"Puzzle 1.2: .0013 seconds, answer 6907 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
@@ -387,7 +387,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 2.1: .0028 seconds, answer 23560874270 correct"
|
||||
"Puzzle 2.1: .0030 seconds, answer 23560874270 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 12,
|
||||
@@ -471,7 +471,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 2.1: .0029 seconds, answer 23560874270 correct"
|
||||
"Puzzle 2.1: .0039 seconds, answer 23560874270 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 15,
|
||||
@@ -493,7 +493,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 2.2: .0037 seconds, answer 44143124633 correct"
|
||||
"Puzzle 2.2: .0039 seconds, answer 44143124633 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 16,
|
||||
@@ -602,7 +602,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 3.1: .0006 seconds, answer 17085 correct"
|
||||
"Puzzle 3.1: .0007 seconds, answer 17085 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 20,
|
||||
@@ -679,7 +679,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 3.1: .0006 seconds, answer 17085 correct"
|
||||
"Puzzle 3.1: .0007 seconds, answer 17085 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 23,
|
||||
@@ -701,7 +701,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 3.2: .0021 seconds, answer 169408143086082 correct"
|
||||
"Puzzle 3.2: .0020 seconds, answer 169408143086082 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 24,
|
||||
@@ -800,7 +800,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 4.1: .0572 seconds, answer 1569 correct"
|
||||
"Puzzle 4.1: .0610 seconds, answer 1569 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 27,
|
||||
@@ -851,7 +851,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 4.2: 1.2620 seconds, answer 9280 correct"
|
||||
"Puzzle 4.2: 1.3428 seconds, answer 9280 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 29,
|
||||
@@ -900,7 +900,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 4.2: .1446 seconds, answer 9280 correct"
|
||||
"Puzzle 4.2: .1437 seconds, answer 9280 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 31,
|
||||
@@ -1040,7 +1040,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 5.1: .0111 seconds, answer 635 correct"
|
||||
"Puzzle 5.1: .0118 seconds, answer 635 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 35,
|
||||
@@ -1205,7 +1205,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 6.1: .0025 seconds, answer 5877594983578 correct"
|
||||
"Puzzle 6.1: .0021 seconds, answer 5877594983578 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 41,
|
||||
@@ -1288,7 +1288,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 6.2: .0065 seconds, answer 11159825706149 correct"
|
||||
"Puzzle 6.2: .0061 seconds, answer 11159825706149 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 43,
|
||||
@@ -1678,7 +1678,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 8.1: .6055 seconds, answer 24360 correct"
|
||||
"Puzzle 8.1: .6053 seconds, answer 24360 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 56,
|
||||
@@ -1709,7 +1709,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def last_connected(boxes) -> Tuple[Point, Point]:\n",
|
||||
" \"\"\"Go through tall the pairs of boxes, in closest first order. \n",
|
||||
" \"\"\"Go through all the pairs of boxes, in closest first order. \n",
|
||||
" Return the last two boxes that finally make it all one big circuit.\"\"\"\n",
|
||||
" circuits = {B: (B,) for B in boxes} # A dict of {box: circuit}\n",
|
||||
" for (A, B) in closest_pairs(boxes, len(boxes) ** 2):\n",
|
||||
@@ -1731,7 +1731,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 8.2: .6371 seconds, answer 2185817796 correct"
|
||||
"Puzzle 8.2: .6392 seconds, answer 2185817796 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 58,
|
||||
@@ -1749,7 +1749,7 @@
|
||||
"id": "fa988909-1a8b-4e8c-aca6-c53af99bc0b6",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Today's puzzles had the slowest run times yet. I could perhaps make them faster by mutating circuits rather than forming a new tuple for each new circuit, or by using a Union-Find data structure, but I think gains from that would be small, and since the run time is still under a second, I'll leave the code as is."
|
||||
"Today's puzzles had the slowest run times yet. I could perhaps make them faster by mutating circuits rather than forming a new tuple for each new circuit, or by using a Union-Find data structure (optimized for unions, not finds). If we had 100,000 unions I think that would be worth it, but for just 1000 I think gains would be small, so I'll leave the code as is."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1759,7 +1759,7 @@
|
||||
"source": [
|
||||
"# [Day 9](https://adventofcode.com/2025/day/9): Movie Theater \n",
|
||||
"\n",
|
||||
"The Elves are redecorating the movie theater floor by switching out some of the square tiles in the big grid they form. Some of the tiles are red; their coordinates form the day's input file:"
|
||||
"The Elves are redecorating the movie theater floor by switching out some of the square tiles in the big grid they form. Some of the tiles are red; their *x*, *y* coordinates form the day's input file:"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1812,7 +1812,7 @@
|
||||
"\n",
|
||||
"### Part 1: What is the largest area of any rectangle you can make?\n",
|
||||
"\n",
|
||||
"The Elves would like to find the largest rectangle that uses red tiles for two of its opposite corners. That's easy; we can try all combinations of two corners and take the corners with the maximum area. The only tricky part is remembering that we have to add one to the delta-x and delta-y values before multiplying them; the area of a square with corners (0, 0) and (1, 1) is 4 tiles, not 1."
|
||||
"The Elves would like to find the largest rectangle that uses red tiles for two of its opposite corners. That's easy; we can try all combinations of two corners and take the corners with the maximum area. (I'll define a pair of corner points to be a type called `Rectangle`.) The only **tricky part** is remembering that we have to add one to the delta-x and delta-y values before multiplying them; the area of a square with corners (0, 0) and (1, 1) is 4 tiles, not 1. Initially I had a **bug** and forgot this on my first submission."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1822,11 +1822,11 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"Corners = Tuple[Point, Point] # Type representing a rectangle as specified by two corners\n",
|
||||
"Rectangle = Tuple[Point, Point] # Type: a rectangle is defined by two opposite corners\n",
|
||||
"\n",
|
||||
"def tile_area(corners: Corners):\n",
|
||||
" \"\"\"Area, in tiles, of a rectangle formed by tiles at these corner positions.\"\"\"\n",
|
||||
" (x1, y1), (x2, y2) = corners\n",
|
||||
"def tile_area(rect: Rectangle):\n",
|
||||
" \"\"\"Area, in tiles, of a rectangle defined by two opposite corner positions.\"\"\"\n",
|
||||
" (x1, y1), (x2, y2) = rect\n",
|
||||
" return (abs(x1 - x2) + 1) * (abs(y1 - y2) + 1)"
|
||||
]
|
||||
},
|
||||
@@ -1835,7 +1835,7 @@
|
||||
"id": "271f2f81-dc40-41db-9912-0c45f4d75dbb",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now we just maximize the area over all combinations of two corners:"
|
||||
"That's all there is to Part 1; just maximize the area over all combinations of two corners:"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1847,7 +1847,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 9.1: .0278 seconds, answer 4772103936 correct"
|
||||
"Puzzle 9.1: .0262 seconds, answer 4772103936 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 61,
|
||||
@@ -1867,13 +1867,11 @@
|
||||
"source": [
|
||||
"### Part 2: What is the largest area of any rectangle that has only red and green tiles?\n",
|
||||
"\n",
|
||||
"In Part 2 we pay attention to the **green** tiles on the floor. Every red tile is connected to the red tile before and after it (in the input list order) by a straight line of green tiles. (It is guaranteed this will always be a straight horizontal or vertical line.) The first red tile is also connected to the last red tile. This forms a closed polygon, and the interior of the polygon is also all green. (The color of the tiles outside of the polygon is not stated, but I'm going to say \"white.\") The elves want to know: What is the largest area of any rectangle that consists of only red and green tiles?\n",
|
||||
"In Part 2 we pay attention to the **green** tiles on the floor. Every red tile is connected to the red tile before and after it (in the input list order) by a straight line of green tiles. (It is guaranteed this will always be a straight horizontal or vertical line.) The last red tile loops around and is connected to the first one. This forms a closed polygon, and the interior of the polygon is also all green. (The color of the tiles outside of the polygon is not stated, but I'm going to say **white**.) The elves want to know: What is the largest area of any rectangle that consists of only red and green tiles?\n",
|
||||
"\n",
|
||||
"**This is a tough one!** More difficult than all the previous puzzles. There are only 496 red tiles, so enumerating all pairs of them in Part 1 was easy. But there are roughly 100,000<sup>2</sup>or 10 billion total tiles, so doing something like a [flood fill](https://en.wikipedia.org/wiki/Flood_fill) for all the green tiles and checking against them for each pair of corners would be too slow. \n",
|
||||
"**This is a tough one!** More difficult than all the previous puzzles. There are only 496 red tiles, so enumerating all pairs of them in Part 1 was easy. But the *x* and *y* coordinates range from 0 to 100,000, so there are roughly 10 billion total tiles to consider. I need some way of finding the biggest rectangle without having to consider tiles one by one for every candidate rectangle. \n",
|
||||
"\n",
|
||||
"I really want to see what the red and green tiles look like! \n",
|
||||
"\n",
|
||||
"I'll plot the border tiles, but not the interior tiles:"
|
||||
"I really think it will help to see what the red and green tiles look like:"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1884,9 +1882,9 @@
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 800x800 with 1 Axes>"
|
||||
"<Figure size 700x700 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
@@ -1894,9 +1892,11 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def plot_tiles(red_tiles, figsize=(8, 8)) -> None:\n",
|
||||
" \"\"\"Plot the red-and-green border tiles.\"\"\"\n",
|
||||
" plt.figure(figsize=figsize)\n",
|
||||
"def plot_tiles(red_tiles: Sequence[Point], figsize=(7, 7)) -> None:\n",
|
||||
" \"\"\"Plot the red tiles (as dots) and the green border (as lines), but not the green interior.\"\"\"\n",
|
||||
" red_tiles = red_tiles + red_tiles[:1] # Close the loop\n",
|
||||
" plt.figure(figsize=figsize) \n",
|
||||
" plt.axis('equal')\n",
|
||||
" plt.plot(*T(red_tiles), 'g-')\n",
|
||||
" plt.plot(*T(red_tiles), 'r.')\n",
|
||||
"\n",
|
||||
@@ -1905,7 +1905,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ef662323-d014-4c64-88cf-b6e777aee3d8",
|
||||
"id": "cd555e6f-897d-4d0f-bdb7-e946b79a9cc9",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Very Interesting!** Here's what I'm thinking:\n",
|
||||
@@ -1913,20 +1913,29 @@
|
||||
"- A maximal-area red-and-green rectangle can't cross the two equator lines, because there are white tiles between them.\n",
|
||||
"- Therefore one of the corners of the maximal rectangle has to be one of the two points on the east end of the equator lines, and the other corner has to be somewhere on the left side of the circle.\n",
|
||||
"- The points are all roughly in a circle, so we're looking for a rectangle roughly inscribed in the circle.\n",
|
||||
"- A roughly correct way to check if a candidate rectangle is all red-and-green is to see if **the rectangle contains a red tile** in its interior.\n",
|
||||
"- To be more precise, consider the diagram below, in which the two large red circles mark the corners of a rectangle depicted with small purple squares. I have filled in the green tiles that connect the red tiles to form a polygon, and used light green for the interior of the polygon. Is the purple rectangle valid? It is ok that there are two other red tiles on the bottom border; they don't let a white square in. It is ok that there are two red tiles at the top that extend one square into the rectangle; they still don't let a white square in. But the red tile near the bottom right corner is two squares in from the border, and any red tiles in that position let in white squares (here three of them in the bottom right of the rectangle. The only exception is when there are two adjacent red tiles that form a 180 degree turn (as in the left of the rectangle); they do intrude into the rectangle, but because they are adjacent there are no white squares between them.\n",
|
||||
" \n",
|
||||
" <img src=\"tiles2025.png\" width=300>\n",
|
||||
"- A roughly correct way to check if a candidate rectangle is all red-and-green is to make sure **the rectangle contains no red tile** in its interior. If the red tile is in the middle of the rectangle, then there must be white tiles on at least one side of the red tile, and thus in the rectangle (with some caveats).\n",
|
||||
"- The red tiles are serving two purposes: as potential **corners** of the maximal rectangle, and as **obstacles** that disqualify a candidate rectangle.\n",
|
||||
"- To be more precise, consider the diagram below, in which the two large red circles mark the corners of a rectangle depicted with small purple squares. I have filled in the green tiles that connect the red tiles to form a polygon, and used light green for the interior of the polygon.\n",
|
||||
"\n",
|
||||
"- To deal with the two-adjacent-red-tile problem, I will verify that there are no adjacent red tiles in *my* input. I bet Eric Wastl designed it so that nobody gets two adjacent tiles, but they aren't explicitly forbidden in the rules.\n",
|
||||
"- This red-tile-in-interior heuristic by itself isn't enough to stop a candidate rectangle from crossing over the long equator lines. But if we assume that any maximal-area rectangle has sides at least *d* units long, we can fix the problem by inserting an extra red tile every *d* steps along the path. Then, any rectangle with sides greater than *d* that crosses the equator (or any other long line) will contain a red tile in the interior.\n",
|
||||
" <img src=\"tiles2025.png\" width=300>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "279fc8b1-bcf6-4b09-a9b7-ed5875242f76",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"- Does the purple rectangle contain only red and green tiles? Let's consider red tiles that are potential obstacles:\n",
|
||||
" - The two **corners** are obviously **ok**; they define the rectangle and they're red.\n",
|
||||
" - The two red tiles **on the border** at the bottom right are **ok**; they don't let a white square in.\n",
|
||||
" - The two red tiles that **extend one square in** to the rectangle at the top middle are **ok**; they don't let a white square in.\n",
|
||||
" - The two red tiles that are **adjacent** to each other the left side are **ok**, even though they extend three squares in, because there is no room for any white squares to fit between them. This only applies when the two adjacent tiles form a 180° U-turn like this.\n",
|
||||
" - The red tile that **extends two squares in** from the lower right corner **disqualifies** the rectangle; it lets in the three white squares in the lower right corner.\n",
|
||||
"- Besides red tile obstacles inside the rectangle, we also have to worry about two red tiles that are both outside the rectangle, but whose connecting green line passes through the interior of the rectangle. But if we assume that the largest rectangle has width and height of at least *d* spaces, then we can lay down an additional obstacle every *d* spaces, and that means there will always be an obstacle inside the rectangle. I call such obstacles \"breadcrumbs.\" \n",
|
||||
"- If there were more red tiles we could put them into a data structure like a [quadtree](https://en.wikipedia.org/wiki/Quadtree).\n",
|
||||
"- Normally in problems like this we have to check if the rectangle we are considering is inside the polygon or outside of it. But for polygons that are anything like mine (i.e., mostly convex), only very small rectangles can be on the outside. Any sufficiently large rectangle must be on the inside, so I didn't bother checking.\n",
|
||||
"- Normally in problems like this we have to check if the rectangle we are considering is inside the polygon or outside of it. But for polygons that are anything like mine (i.e., mostly convex), and if we are only considering rectangles with corners on tiles, any sufficiently large rectangle must be on the inside, so I didn't bother checking.\n",
|
||||
"\n",
|
||||
"I'm ready to start coding! I'll start with this:\n",
|
||||
"- `find_2_corners` will return a list of the two candidate corner points at the east end of the equator lines.\n",
|
||||
"- `breadcrumbs` will leave \"breadcrumbs\" (that is, red tiles) along the trail at least every `d` spaces.\n",
|
||||
"- An assertion to show that no two of my red tiles are in adjacent squares."
|
||||
"I'm ready to start coding! I'll start with some functions that manipulate the sequence of red tiles: finding obstacles, laying down breadcrumbs, finding adjacent tiles, and finding the 2 corners on the equator."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1936,23 +1945,35 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def find_2_corners(red_tiles, d=10000) -> Optional[List[Point]]:\n",
|
||||
"GAP = 10000 # How big a gap between red tiles to put in a \"breadcrumb\" red tile\n",
|
||||
"\n",
|
||||
"def find_obstacles(red_tiles: Sequence[Point], d:int=GAP) -> Set[Point]:\n",
|
||||
" \"\"\"Obstacles are tiles that, when found inside a rectangle, disqualify that rectangle.\n",
|
||||
" They are the set of red tiles with breadcrumbs added, minus the adjacent tiles with 180° turns.\"\"\"\n",
|
||||
" return (set(red_tiles) | set(breadcrumbs(red_tiles, d))) - adjacent_180_tiles(red_tiles)\n",
|
||||
" \n",
|
||||
"def breadcrumbs(red_tiles: Sequence[Point], d:int=GAP) -> Iterator[Point]:\n",
|
||||
" \"\"\"Extra obstacles to lay down along the trail when the gap between red tiles is too big.\"\"\"\n",
|
||||
" for (p, q) in sliding_window(red_tiles, 2):\n",
|
||||
" if distance(p, q) > d: \n",
|
||||
" dx, dy = d * sign(X_(p) - X_(q)), d * sign(Y_(p) - Y_(q))\n",
|
||||
" for i in range(1, distance(p, q) // d + 1):\n",
|
||||
" yield (X_(q) + i * dx, Y_(q) + i * dy)\n",
|
||||
"\n",
|
||||
"def adjacent_180_tiles(red_tiles: Set[Point]) -> Set[Point]:\n",
|
||||
" \"\"\"Yield all adjacent points that form a 180 degree U-turn.\"\"\"\n",
|
||||
" return union({q, r} for (p, q, r, s) in sliding_window(red_tiles, 4)\n",
|
||||
" if distance(q, r) == 1 and direction(p, q) == direction(s, r))\n",
|
||||
"\n",
|
||||
"def find_2_corners(red_tiles, d:int=GAP) -> Optional[List[Point]]:\n",
|
||||
" \"\"\"Find two adjacent corners, separated on each side by a gap of at least `d`.\"\"\"\n",
|
||||
" return first([B, C] for [A, B, C, D] in sliding_window(red_tiles, 4)\n",
|
||||
" if distance(A, B) > d and distance(C, D) > d)\n",
|
||||
" return first([q, r] for [p, q, r, s] in sliding_window(red_tiles, 4)\n",
|
||||
" if distance(p, q) > d and distance(r, s) > d)\n",
|
||||
"\n",
|
||||
"def breadcrumbs(points, d=10000) -> List[Point]:\n",
|
||||
" \"\"\"Leave extra points along the trail on long lines, every `d` spaces.\"\"\"\n",
|
||||
" trail = [points[-1]]\n",
|
||||
" for p in points:\n",
|
||||
" while distance(trail[-1], p) > d: \n",
|
||||
" q = trail[-1]\n",
|
||||
" dx, dy = sign(X_(p) - X_(q)), sign(Y_(p) - Y_(q))\n",
|
||||
" trail.append((X_(q) + d * dx, Y_(q) + d * dy)) # Leave a breadcrumb\n",
|
||||
" trail.append(p)\n",
|
||||
" return trail\n",
|
||||
"\n",
|
||||
"assert not any(distance(p, q) == 1 for (p, q) in sliding_window(red_tiles, 2))"
|
||||
"def direction(p: Point, q: Point) -> Point:\n",
|
||||
" \"\"\"A unit vector in the orthogonal direction from p to q.\"\"\"\n",
|
||||
" ((x1, y1), (x2, y2)) = p, q\n",
|
||||
" return (sign(x2 - x1), sign(y2 - y1))"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1960,7 +1981,7 @@
|
||||
"id": "4425bb14-d9ca-4afb-8f1c-5787bf3e17a4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let's visualize the output of these two functions:"
|
||||
"Let's visualize the breadcrumbs (blue squares) and the two corners (black diamonds):"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1971,9 +1992,9 @@
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 800x800 with 1 Axes>"
|
||||
"<Figure size 700x700 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
@@ -1981,8 +2002,9 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"plot_tiles(breadcrumbs(red_tiles))\n",
|
||||
"plt.plot(*T(find_2_corners(red_tiles)), 'bD');"
|
||||
"plot_tiles(red_tiles)\n",
|
||||
"plt.plot(*T(breadcrumbs(red_tiles)), 'bs');\n",
|
||||
"plt.plot(*T(find_2_corners(red_tiles)), 'kD');"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2002,24 +2024,23 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def biggest_rectangle(red_tiles, second_corners=None, d=10000) -> Corners:\n",
|
||||
" \"\"\"Find the biggest rectangle that stays within the interior-and-border of the tiles.\"\"\"\n",
|
||||
" if second_corners is None: # You can pass in a hint for second corners, or it will try them all\n",
|
||||
" second_corners = red_tiles\n",
|
||||
" tiles = breadcrumbs(red_tiles, d)\n",
|
||||
" corner_pairs = cross_product(second_corners, red_tiles)\n",
|
||||
" for corners in sorted(corner_pairs, key=tile_area, reverse=True):\n",
|
||||
" if not any_intrusions(tiles, corners):\n",
|
||||
" return corners\n",
|
||||
"def biggest_rectangle(red_tiles, second_corners=None, d:int=GAP) -> Rectangle:\n",
|
||||
" \"\"\"Find the biggest rectangle that stays within the interior-and-border of the red tiles.\n",
|
||||
" You can pass in a hint for `second_corners`, or they can default to `red_tiles`.\"\"\"\n",
|
||||
" obstacles = find_obstacles(red_tiles, d)\n",
|
||||
" rectangles = cross_product(second_corners or red_tiles, red_tiles)\n",
|
||||
" for rect in sorted(rectangles, key=tile_area, reverse=True):\n",
|
||||
" if not any_intrusions(obstacles, rect):\n",
|
||||
" return rect\n",
|
||||
" raise ValueError('No rectangle') # Shouldn't get here unless there are no corners\n",
|
||||
"\n",
|
||||
"def any_intrusions(red_tiles: List[Point], corners: Corners) -> bool:\n",
|
||||
" \"\"\"Does any red tile intrude inside the rectangle defined by the corners?\"\"\"\n",
|
||||
" # OK for a red tile to be on border or just one square in, but not 2 squares in\n",
|
||||
" xlo, xhi = min(Xs(corners)) + 2, max(Xs(corners)) - 2\n",
|
||||
" ylo, yhi = min(Ys(corners)) + 2, max(Ys(corners)) - 2\n",
|
||||
"def any_intrusions(obstacles: List[Point], rect: Rectangle) -> bool:\n",
|
||||
" \"\"\"Does any ostacle point intrude inside the rectangle?\"\"\"\n",
|
||||
" # OK for an obstacle to be on border or just one square in, but not 2 squares in\n",
|
||||
" xlo, xhi = min(Xs(rect)) + 2, max(Xs(rect)) - 2\n",
|
||||
" ylo, yhi = min(Ys(rect)) + 2, max(Ys(rect)) - 2\n",
|
||||
" return any(xlo <= x <= xhi and ylo <= y <= yhi\n",
|
||||
" for (x, y) in red_tiles)"
|
||||
" for (x, y) in obstacles)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2039,7 +2060,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 9.2: .0156 seconds, answer 1529675217 correct"
|
||||
"Puzzle 9.2: .0068 seconds, answer 1529675217 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 66,
|
||||
@@ -2057,7 +2078,7 @@
|
||||
"id": "53ef7a00-aef7-4c20-8a2b-d735df8f28dd",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let's see what the biggest rectangle looks like:"
|
||||
"Let's see what the biggest rectangle looks like (at a bigger scale to see more detail):"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2068,7 +2089,7 @@
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA/QAAAPHCAYAAACGywJhAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAADHI0lEQVR4nOz9f3yU9Z3v/z+vmRDID5lla5Elo6OYgeLS3W7VWkyFSKvpp6Xudo9tt1g2spGkkGqp2irdle3up5Wj9Sj7gcaT6ByNlC7H2o9n91vRpdtNqWgplNbdUhTjWX5dUUvPN3RoxpAhmevzxzuZ38lMyCSTmXncb7e55cqVd2auQDLJa97v9/NlOY7jCAAAAAAAFBRXvi8AAAAAAACMHwU9AAAAAAAFiIIeAAAAAIACREEPAAAAAEABoqAHAAAAAKAAUdADAAAAAFCAKOgBAAAAAChAZfm+gOkuEonozTff1AUXXCDLsvJ9OQAAAACAIuc4jn73u99p/vz5crlGn4enoM/gzTff1MUXX5zvywAAAAAAlJiTJ0/K6/WO+nEK+gwuuOACSeYfcvbs2Xm+GgAAAABAsTtz5owuvvjiaD06Ggr6DEaW2c+ePZuCHgAAAAAwZTJt+yYUDwAAAACAAkRBDwAAAABAAaKgBwAAAACgAFHQAwAAAABQgCjoAQAAAAAoQBT0AAAAAAAUIAp6AAAAAAAKEAU9AAAAAAAFiIIeAAAAAIACREEPAAAAAEABoqAHAAAAAKAAUdADAAAAAFCAKOgBAAAAAChAFPQAAAAAABQgCnoAAAAAAAoQBT0AAAAAAAWIgh4AAAAAgAJEQQ8AAAAAQAGioAcAAAAAoACNu6D/8Y9/rE984hOaP3++LMvS//pf/yvh447j6Gtf+5rmz5+viooK1dfX61e/+lXCmIGBAd1+++268MILVVVVpZtuukm2bSeMOX36tFavXi2PxyOPx6PVq1frt7/9bcKYEydO6BOf+ISqqqp04YUX6o477lA4HE4Y88tf/lLLly9XRUWFampq9Pd///dyHGe8XzYAAAAAANPKuAv6UCikP/7jP9a2bdvSfvzBBx/Uww8/rG3btunAgQOaN2+ebrjhBv3ud7+LjtmwYYOeffZZ7dy5U3v37lVfX59WrlypoaGh6JhVq1bplVde0QsvvKAXXnhBr7zyilavXh39+NDQkD7+8Y8rFApp79692rlzp773ve/prrvuio45c+aMbrjhBs2fP18HDhzQ1q1b9dBDD+nhhx8e75cNAAAAAMC0YjkTmK62LEvPPvus/uzP/kySmZ2fP3++NmzYoHvuuUeSmY2/6KKL9MADD6ilpUXBYFDvfve7tX37dn3mM5+RJL355pu6+OKLtWvXLjU0NOjVV1/VFVdcoX379umaa66RJO3bt09Lly7Va6+9pkWLFun555/XypUrdfLkSc2fP1+StHPnTt166606deqUZs+erUcffVQbN27Ur3/9a82cOVOS9F//63/V1q1bZdu2LMvK+DWeOXNGHo9HwWBQs2fPPt9/KgAAAAAAspJtHZrTPfRHjx7V22+/rRtvvDF6bubMmVq+fLlefvllSdLBgwd17ty5hDHz58/XkiVLomN+8pOfyOPxRIt5SfrgBz8oj8eTMGbJkiXRYl6SGhoaNDAwoIMHD0bHLF++PFrMj4x58803dezYsbRfw8DAgM6cOZNwAwAAAABguslpQf/2229Lki666KKE8xdddFH0Y2+//bbKy8s1Z86cMcfMnTs35f7nzp2bMCb5cebMmaPy8vIxx4y8PzIm2ebNm6P79j0ejy6++OLMXzgAAAAAAFNsUlLuk5eyO46TcXl78ph043MxZmSHwWjXs3HjRgWDwejt5MmTY143AAAAAAD5kNOCft68eZJSZ79PnToVnRmfN2+ewuGwTp8+PeaYX//61yn3/5vf/CZhTPLjnD59WufOnRtzzKlTpySlriIYMXPmTM2ePTvhBgAAAADAdJPTgv6yyy7TvHnz9IMf/CB6LhwOa8+ePbr22mslSVdeeaVmzJiRMOatt97SoUOHomOWLl2qYDCo/fv3R8f89Kc/VTAYTBhz6NAhvfXWW9Exu3fv1syZM3XllVdGx/z4xz9OaGW3e/duzZ8/X5deemkuv3QAAAAAAKbUuAv6vr4+vfLKK3rllVckmSC8V155RSdOnJBlWdqwYYPuv/9+Pfvsszp06JBuvfVWVVZWatWqVZIkj8ejpqYm3XXXXfrhD3+oX/ziF/rc5z6n9773vfrIRz4iSVq8eLE++tGPau3atdq3b5/27duntWvXauXKlVq0aJEk6cYbb9QVV1yh1atX6xe/+IV++MMf6u6779batWujs+qrVq3SzJkzdeutt+rQoUN69tlndf/99+vO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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1200x1200 with 1 Axes>"
|
||||
]
|
||||
@@ -2078,10 +2099,13 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"((x1, y1), (x2, y2)) = biggest_rectangle(red_tiles, find_2_corners(red_tiles))\n",
|
||||
"\n",
|
||||
"plot_tiles(breadcrumbs(red_tiles), figsize=(12, 12))\n",
|
||||
"plt.plot([x1, x1, x2, x2, x1], [y1, y2, y2, y1, y1], 'b:');"
|
||||
"def plot_rect(rect: Rectangle, fmt='b:') -> None:\n",
|
||||
" \"\"\"Plot a rectangle.\"\"\"\n",
|
||||
" ((x1, y1), (x2, y2)) = rect\n",
|
||||
" plt.plot([x1, x1, x2, x2, x1], [y1, y2, y2, y1, y1], fmt)\n",
|
||||
" \n",
|
||||
"plot_tiles(red_tiles, figsize=(12, 12))\n",
|
||||
"plot_rect(biggest_rectangle(red_tiles, find_2_corners(red_tiles)))"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2104,8 +2128,8 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"CPU times: user 2.33 s, sys: 166 ms, total: 2.5 s\n",
|
||||
"Wall time: 1.6 s\n"
|
||||
"CPU times: user 1.3 s, sys: 139 ms, total: 1.44 s\n",
|
||||
"Wall time: 547 ms\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2123,16 +2147,52 @@
|
||||
"%time tile_area(biggest_rectangle(red_tiles, red_tiles)) == tile_area(biggest_rectangle(red_tiles, find_2_corners(red_tiles)))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b7161525-d572-455f-b6d0-cfe9e86405c8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Yes, it gets the correct answer, and yes, it is slower.\n",
|
||||
"\n",
|
||||
"In my puzzle (and if Eric Wastl is being fair (which he always is), then in everybody's puzzle) there were no adjacent points, and thus no `adjacent_180_tiles`. So here is a test case with five pairs of adjacent points. We can see that `adjacent_180_tiles` coorectly found the ten adjacent points (the magenta \"o\"s), that it correctly did not eliminate obstacles for the adjacent points that do not form 180° U-turns, and that `biggest_rectangle` finds what appears to be the right answer."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 69,
|
||||
"id": "437bd73a-6c8f-4196-8095-3299e5f8ef9d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 700x700 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"points = [(-16, 3), (-16, 24), (-17, 24), (-17, 39), (-17, 32), (-5, 32), (-5, 33), (-17, 33), \n",
|
||||
" (-17, 39), (30, 39), (30, 38), (41, 38), (41, -9), \n",
|
||||
" (40, -9), (40, 27), (18, 27), (18, 26), (34, 26), (34, 3), (16, 3), (16, 15), \n",
|
||||
" (30, 15), (30, 16), (10, 16), (10, -3), (2, -3), (2, 27), (1, 27), (1, 3)]\n",
|
||||
"\n",
|
||||
"plot_tiles(points) # Green dots and red lines\n",
|
||||
"plt.plot(*T(adjacent_180_tiles(points)), 'mo') # The eliminated obstacles are magenta dots\n",
|
||||
"plot_rect(biggest_rectangle(points)) # Rectangle is blue dotted line"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b4e35203-687a-434e-88f5-0afea9f31c57",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Yes, it finds the same maximal-area rectangle, but it takes a lot longer to find it.\n",
|
||||
"\n",
|
||||
"**Three final remarks**:\n",
|
||||
"1) This was the first puzzle of the year that was **difficult**; we had to work to find an efficient solution.\n",
|
||||
"2) My solution is **unsatisfying** in that it works for *my* input, and I strongly suspect that it would work for *your* input, because Eric Wastl probably created them all to be similar. But it does not work on every possible input allowed by the rules. \n",
|
||||
"2) My solution is **unsatisfying** in that it works for *my* input, and I strongly suspect that it would work for *your* input, because Eric Wastl probably created them all to be similar. But it does not work on every possible input (particularly a highly non-convex shape).\n",
|
||||
"3) In retrospect, I could have done the standard edge-edge intersection algorithm for determining if the rectangle intersects the polygon formed by the red tiles. I was scared away from that because the geometry is tricky for general polygon intersection, when the edges can have any slope. But the geometry is actually easy when all lines are axis-aligned."
|
||||
]
|
||||
},
|
||||
@@ -2152,7 +2212,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 69,
|
||||
"execution_count": 70,
|
||||
"id": "84cd63a7-4d50-4f14-9807-3cb439f80c88",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -2210,7 +2270,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 70,
|
||||
"execution_count": 71,
|
||||
"id": "179e62b1-e4cb-43e4-8dc7-b87a28d21e8d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -2231,17 +2291,17 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 71,
|
||||
"execution_count": 72,
|
||||
"id": "d1368c2f-d792-4353-82e7-b0161ece784f",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 10.1: .0535 seconds, answer 441 correct"
|
||||
"Puzzle 10.1: .0840 seconds, answer 441 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 71,
|
||||
"execution_count": 72,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -2267,7 +2327,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 72,
|
||||
"execution_count": 73,
|
||||
"id": "1d2683fa-5126-4d2a-9dad-6a0e155f3449",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -2277,7 +2337,7 @@
|
||||
"7.181818181818182"
|
||||
]
|
||||
},
|
||||
"execution_count": 72,
|
||||
"execution_count": 73,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -2296,7 +2356,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 73,
|
||||
"execution_count": 74,
|
||||
"id": "a714c2c2-d433-41d0-8d1e-01832b35a1a9",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -2306,7 +2366,7 @@
|
||||
"114.81498043610085"
|
||||
]
|
||||
},
|
||||
"execution_count": 73,
|
||||
"execution_count": 74,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -2353,7 +2413,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 74,
|
||||
"execution_count": 75,
|
||||
"id": "713a1503-ae14-445f-91ea-714fcd618ad0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -2383,7 +2443,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 75,
|
||||
"execution_count": 76,
|
||||
"id": "46d0d274-bd4c-44af-83e9-35c791a8e96b",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -2393,7 +2453,7 @@
|
||||
"Puzzle 10.2: .1304 seconds, answer 18559 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 75,
|
||||
"execution_count": 76,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -2420,7 +2480,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 76,
|
||||
"execution_count": 77,
|
||||
"id": "b9f82fef-612b-48a5-9de1-6ff0b137f7fb",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -2430,7 +2490,7 @@
|
||||
"Counter({-1: 68, 1: 65, 0: 32})"
|
||||
]
|
||||
},
|
||||
"execution_count": 76,
|
||||
"execution_count": 77,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -2449,7 +2509,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 77,
|
||||
"execution_count": 78,
|
||||
"id": "e536441d-64d4-410d-bb40-2343f6e01d88",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -2459,7 +2519,7 @@
|
||||
"Counter({-1: 32, -2: 31, 1: 34, 2: 31, 0: 32, -3: 5})"
|
||||
]
|
||||
},
|
||||
"execution_count": 77,
|
||||
"execution_count": 78,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -2486,7 +2546,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 78,
|
||||
"execution_count": 79,
|
||||
"id": "b72544c8-6069-4310-a6dc-b4acd77981b4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -2513,7 +2573,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 79,
|
||||
"execution_count": 80,
|
||||
"id": "11e17f6a-acba-44c4-b704-7e4ff7471e7e",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -2566,7 +2626,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 80,
|
||||
"execution_count": 81,
|
||||
"id": "7540a982-988a-4822-af0d-6581f6f848c6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -2593,7 +2653,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 81,
|
||||
"execution_count": 82,
|
||||
"id": "0c2d68a5-843b-49d6-aff6-23045968207f",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -2603,7 +2663,7 @@
|
||||
"Puzzle 11.1: .0003 seconds, answer 574 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 81,
|
||||
"execution_count": 82,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -2625,7 +2685,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 82,
|
||||
"execution_count": 83,
|
||||
"id": "0294e044-c7ef-418a-9c02-71615a453002",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -2645,17 +2705,17 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 83,
|
||||
"execution_count": 84,
|
||||
"id": "677a97b3-183b-474e-87ba-7db0d6b763d8",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 11.2: .0017 seconds, answer 306594217920240 correct"
|
||||
"Puzzle 11.2: .0020 seconds, answer 306594217920240 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 83,
|
||||
"execution_count": 84,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -2677,7 +2737,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 84,
|
||||
"execution_count": 85,
|
||||
"id": "a1b304e8-339e-4e32-a462-3ba88103c415",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -2754,12 +2814,12 @@
|
||||
"source": [
|
||||
"### Part 1: How many of the regions can fit all of the presents listed?\n",
|
||||
"\n",
|
||||
"There have been Tetris-like puzzles in past AoC years. Is this another search problem? If so, will the searches be trivial or difficult? I want to get a feel for it. First, how many regions?"
|
||||
"There have been Tetris-like puzzles in past AoC years. Is this another search problem? If so, how big will the search trees be? I want to get a feel. First, how many regions?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 85,
|
||||
"execution_count": 86,
|
||||
"id": "194cbece-0104-4934-b335-13a4e7c720e0",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -2769,7 +2829,7 @@
|
||||
"1000"
|
||||
]
|
||||
},
|
||||
"execution_count": 85,
|
||||
"execution_count": 86,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -2788,7 +2848,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 86,
|
||||
"execution_count": 87,
|
||||
"id": "388d13ab-b5db-47e4-9f33-50f7062424b9",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -2798,7 +2858,7 @@
|
||||
"1822.223"
|
||||
]
|
||||
},
|
||||
"execution_count": 86,
|
||||
"execution_count": 87,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -2817,7 +2877,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 87,
|
||||
"execution_count": 88,
|
||||
"id": "5d982737-cbca-4739-be1c-fa1dce319ef4",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -2827,7 +2887,7 @@
|
||||
"240.488"
|
||||
]
|
||||
},
|
||||
"execution_count": 87,
|
||||
"execution_count": 88,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -2841,12 +2901,12 @@
|
||||
"id": "af3fe830-aa75-469b-9046-3f36ff3a03e2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Next I want to get a feel for the variation in how tight the packing is. Each present can definitely fit into a 3x3 square, so what's the ratio of the total quantity of presents to the number of 3x3 squares? I'll make a histogram of that ratio, which I'll call the occupancy ratio, for each region:"
|
||||
"Next I want to get a feel for the variation in how tight the packing is. Each present can definitely fit into a 3x3 **box**, so what's the ratio of the total quantity of presents to the number of 3x3 boxes? I'll make a histogram of that ratio, which I'll call the occupancy ratio, for each region:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 88,
|
||||
"execution_count": 89,
|
||||
"id": "b8cf45b6-5513-426a-86c2-425d0d74d781",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -2862,11 +2922,14 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def squares(width, length) -> int: \n",
|
||||
" \"Number of full 3x3 squares in a region.\"\n",
|
||||
" return (width // 3) * (length // 3)\n",
|
||||
"def boxes(region_W, region_L, shape_W=3, shape_L=3) -> int: \n",
|
||||
" \"\"\"Number of shape-sized boxes that can fit into a WxL region. By default 3x3 boxes.\"\"\"\n",
|
||||
" # Our presents all fit in a 3x3 box, but if they were diffferent, say 4x3,\n",
|
||||
" # then we try to fit the boxes into the region both ways and take the most.\n",
|
||||
" return max((region_W // shape_W) * (region_L // shape_L),\n",
|
||||
" (region_W // shape_L) * (region_L // shape_W))\n",
|
||||
" \n",
|
||||
"occupancy_ratios = [sum(quantities) / squares(W, L) \n",
|
||||
"occupancy_ratios = [sum(quantities) / boxes(W, L) \n",
|
||||
" for (W, L, quantities) in regions]\n",
|
||||
"\n",
|
||||
"plt.hist(occupancy_ratios, bins=100);"
|
||||
@@ -2877,30 +2940,29 @@
|
||||
"id": "54f2eaa0-b8b6-4a60-bcde-28eeefa26e8c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Very interesting!** There's a real split. About half the regions have an occupancy ratio below 1.0 and thus are trivially easy to fit into the region: just plop onee present into each 3x3 square, without worrying about rotations. The rest of the regions with occupancy ratios above 1.35 may well be impossible to fit. I say that because, just looking at the shapes, I estimate that the average overlap of one shape with another would be to save two \".\" squares; so I could see getting to an occupancy rato of 1 + 2/9 = 1.22, but I don't think it is possible to get to 1.35. I can prove it is impossible to fit all the presents in a region if the total area of the solid parts of the presents (the '#' squares) is more than the total area of the region (the width times length). \n",
|
||||
"**Very interesting!** There's a real split. About half the regions have an occupancy ratio below 1.0 and thus are trivially easy to fit into the region: just plop one present into each 3x3 box, without worrying about rotations. The rest of the regions with occupancy ratios above 1.35 may well be impossible to fit. Just looking at the shapes, I estimate that the average overlap of one shape with another would be to save two \".\" squares; so I could see getting to an occupancy rato of 1 + 2/9 = 1.22, but I don't think it is possible to get to 1.35; almost certainly not 1.4 or more. I can prove it is impossible to fit all the presents in a region if the total area of the solid parts of the presents (the '#' squares) is more than the total area of the region (the width times length). \n",
|
||||
"\n",
|
||||
"I can do **triage** on the regions to classify each one as a trivial fit, an impossible fit, or an uncertain fit (for which we would have to do a search):"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 89,
|
||||
"id": "58b879f2-19ad-4e3f-a804-8c22151e5865",
|
||||
"execution_count": 90,
|
||||
"id": "0cd74af7-a078-4e63-975a-ee459f3eb26d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"shape_area = [cat(shape).count('#') for shape in shapes] # List of total number of '#' in each shape\n",
|
||||
"\n",
|
||||
"def triage(region) -> str:\n",
|
||||
"def triage(regions, shapes) -> str:\n",
|
||||
" \"\"\"Decide if a region's presents trivially fit, or are impossible to fit, or it is uncertain.\"\"\"\n",
|
||||
" width, length, quantities = region\n",
|
||||
" shape_area = [cat(shape).count('#') for shape in shapes] # List of total number of '#' in each shape\n",
|
||||
" counts = Counter()\n",
|
||||
" for (width, length, quantities) in regions:\n",
|
||||
" presents_area = sum(q * shape_area[i] for (i, q) in enumerate(quantities))\n",
|
||||
" if sum(quantities) <= squares(width, length):\n",
|
||||
" return 'fit' # The total number of presents is no more than the number of 3x3 squares\n",
|
||||
" elif presents_area > width * length:\n",
|
||||
" return 'impossible' # The '#' area of all the presents is greater than the area of the region\n",
|
||||
" else:\n",
|
||||
" return 'uncertain' # We would need to do a search to see if the presents fit"
|
||||
" result = ('fit' if sum(quantities) <= boxes(width, length) # The presents all fit in their own 3x3 box\n",
|
||||
" else 'fail' if presents_area > width * length # The presents are bigger than the region\n",
|
||||
" else '????') # Uncertain; would need a search\n",
|
||||
" counts[result] += 1\n",
|
||||
" return counts"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2913,23 +2975,23 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 90,
|
||||
"execution_count": 91,
|
||||
"id": "6768fa83-2af7-4aab-a930-9106da3859bd",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Counter({'impossible': 546, 'fit': 454})"
|
||||
"Counter({'fail': 546, 'fit': 454})"
|
||||
]
|
||||
},
|
||||
"execution_count": 90,
|
||||
"execution_count": 91,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"Counter(map(triage, regions))"
|
||||
"triage(regions, shapes)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2942,24 +3004,24 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 91,
|
||||
"execution_count": 92,
|
||||
"id": "0ec553c4-85eb-40a6-8bed-7adddf75e512",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Puzzle 12.1: .0018 seconds, answer 454 correct"
|
||||
"Puzzle 12.1: .0021 seconds, answer 454 correct"
|
||||
]
|
||||
},
|
||||
"execution_count": 91,
|
||||
"execution_count": 92,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"answer(12.1, 454, lambda:\n",
|
||||
" quantify(triage(region) == 'fit' for region in regions))"
|
||||
" triage(regions, shapes)['fit'])"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2974,7 +3036,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 92,
|
||||
"execution_count": 93,
|
||||
"id": "4d512a50-c6ae-4803-a787-b8f6e0103e31",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -2982,31 +3044,31 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Puzzle 1.1: .0005 seconds, answer 1182 correct\n",
|
||||
"Puzzle 1.2: .0009 seconds, answer 6907 correct\n",
|
||||
"Puzzle 2.1: .0029 seconds, answer 23560874270 correct\n",
|
||||
"Puzzle 2.2: .0037 seconds, answer 44143124633 correct\n",
|
||||
"Puzzle 3.1: .0006 seconds, answer 17085 correct\n",
|
||||
"Puzzle 3.2: .0021 seconds, answer 169408143086082 correct\n",
|
||||
"Puzzle 4.1: .0572 seconds, answer 1569 correct\n",
|
||||
"Puzzle 4.2: .1446 seconds, answer 9280 correct\n",
|
||||
"Puzzle 5.1: .0111 seconds, answer 635 correct\n",
|
||||
"Puzzle 1.1: .0006 seconds, answer 1182 correct\n",
|
||||
"Puzzle 1.2: .0013 seconds, answer 6907 correct\n",
|
||||
"Puzzle 2.1: .0039 seconds, answer 23560874270 correct\n",
|
||||
"Puzzle 2.2: .0039 seconds, answer 44143124633 correct\n",
|
||||
"Puzzle 3.1: .0007 seconds, answer 17085 correct\n",
|
||||
"Puzzle 3.2: .0020 seconds, answer 169408143086082 correct\n",
|
||||
"Puzzle 4.1: .0610 seconds, answer 1569 correct\n",
|
||||
"Puzzle 4.2: .1437 seconds, answer 9280 correct\n",
|
||||
"Puzzle 5.1: .0118 seconds, answer 635 correct\n",
|
||||
"Puzzle 5.2: .0002 seconds, answer 369761800782619 correct\n",
|
||||
"Puzzle 6.1: .0025 seconds, answer 5877594983578 correct\n",
|
||||
"Puzzle 6.2: .0065 seconds, answer 11159825706149 correct\n",
|
||||
"Puzzle 6.1: .0021 seconds, answer 5877594983578 correct\n",
|
||||
"Puzzle 6.2: .0061 seconds, answer 11159825706149 correct\n",
|
||||
"Puzzle 7.1: .0011 seconds, answer 1681 correct\n",
|
||||
"Puzzle 7.2: .0020 seconds, answer 422102272495018 correct\n",
|
||||
"Puzzle 8.1: .6055 seconds, answer 24360 correct\n",
|
||||
"Puzzle 8.2: .6371 seconds, answer 2185817796 correct\n",
|
||||
"Puzzle 9.1: .0278 seconds, answer 4772103936 correct\n",
|
||||
"Puzzle 9.2: .0156 seconds, answer 1529675217 correct\n",
|
||||
"Puzzle 10.1: .0535 seconds, answer 441 correct\n",
|
||||
"Puzzle 8.1: .6053 seconds, answer 24360 correct\n",
|
||||
"Puzzle 8.2: .6392 seconds, answer 2185817796 correct\n",
|
||||
"Puzzle 9.1: .0262 seconds, answer 4772103936 correct\n",
|
||||
"Puzzle 9.2: .0068 seconds, answer 1529675217 correct\n",
|
||||
"Puzzle 10.1: .0840 seconds, answer 441 correct\n",
|
||||
"Puzzle 10.2: .1304 seconds, answer 18559 correct\n",
|
||||
"Puzzle 11.1: .0003 seconds, answer 574 correct\n",
|
||||
"Puzzle 11.2: .0017 seconds, answer 306594217920240 correct\n",
|
||||
"Puzzle 12.1: .0018 seconds, answer 454 correct\n",
|
||||
"Puzzle 11.2: .0020 seconds, answer 306594217920240 correct\n",
|
||||
"Puzzle 12.1: .0021 seconds, answer 454 correct\n",
|
||||
"\n",
|
||||
"Time in seconds: sum = 1.710, mean = .074, median = .003, max = .637\n"
|
||||
"Time in seconds: sum = 1.737, mean = .076, median = .004, max = .639\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
Reference in new issue
Block a user