Add files via upload

This commit is contained in:
Peter Norvig 2025-12-09 12:08:34 -08:00 committed by GitHub
parent b103599c44
commit d7ff868678
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 657 additions and 88 deletions

View File

@ -17,7 +17,7 @@
"\n", "\n",
"*Each day I'll choose a model and give it the prompt* \"***Write code to solve the following problem:***\" *followed by the full text of the AoC Part 1 problem description. Then I'll prompt again with* \"***There is a change to the specification:***\" *followed by the AoC Part 2 description.*\n", "*Each day I'll choose a model and give it the prompt* \"***Write code to solve the following problem:***\" *followed by the full text of the AoC Part 1 problem description. Then I'll prompt again with* \"***There is a change to the specification:***\" *followed by the AoC Part 2 description.*\n",
"\n", "\n",
"*For brevity, I have removed some of the models' output, such as:*\n", "*For brevity, I have removed some of the LLM output, such as:*\n",
"- *Prose analysis of the problem and descriptions of the programs. (In most cases these were accurate and thorough!)*\n", "- *Prose analysis of the problem and descriptions of the programs. (In most cases these were accurate and thorough!)*\n",
"- *The \"`#!/usr/bin/env python3`\" at the top of the file*\n", "- *The \"`#!/usr/bin/env python3`\" at the top of the file*\n",
"- *The \"`__main__`\" idiom for running code from the command line*\n", "- *The \"`__main__`\" idiom for running code from the command line*\n",
@ -130,7 +130,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 1.1: .0013 seconds, answer 1182 correct" "Puzzle 1.1: .0012 seconds, answer 1182 correct"
] ]
}, },
"execution_count": 3, "execution_count": 3,
@ -256,7 +256,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 1.2: .0019 seconds, answer 7509 WRONG; EXPECTED ANSWER IS 6907" "Puzzle 1.2: .0022 seconds, answer 7509 WRONG; EXPECTED ANSWER IS 6907"
] ]
}, },
"execution_count": 5, "execution_count": 5,
@ -356,7 +356,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 1.2: .0016 seconds, answer 6907 correct" "Puzzle 1.2: .0017 seconds, answer 6907 correct"
] ]
}, },
"execution_count": 7, "execution_count": 7,
@ -436,7 +436,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 2.1: .1247 seconds, answer 23560874270 correct" "Puzzle 2.1: .1217 seconds, answer 23560874270 correct"
] ]
}, },
"execution_count": 9, "execution_count": 9,
@ -520,7 +520,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 2.2: .1325 seconds, answer 44143124633 correct" "Puzzle 2.2: .1282 seconds, answer 44143124633 correct"
] ]
}, },
"execution_count": 11, "execution_count": 11,
@ -591,7 +591,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 3.1: .0042 seconds, answer 17085 correct" "Puzzle 3.1: .0038 seconds, answer 17085 correct"
] ]
}, },
"execution_count": 13, "execution_count": 13,
@ -674,7 +674,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 3.2: .0078 seconds, answer 169408143086082 correct" "Puzzle 3.2: .0069 seconds, answer 169408143086082 correct"
] ]
}, },
"execution_count": 15, "execution_count": 15,
@ -767,7 +767,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 4.1: .0182 seconds, answer 1569 correct" "Puzzle 4.1: .0170 seconds, answer 1569 correct"
] ]
}, },
"execution_count": 17, "execution_count": 17,
@ -860,7 +860,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 4.2: .3946 seconds, answer 9280 correct" "Puzzle 4.2: .3880 seconds, answer 9280 correct"
] ]
}, },
"execution_count": 19, "execution_count": 19,
@ -969,7 +969,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 4.2: .0938 seconds, answer 9280 correct" "Puzzle 4.2: .0874 seconds, answer 9280 correct"
] ]
}, },
"execution_count": 21, "execution_count": 21,
@ -1063,7 +1063,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 5.1: .0056 seconds, answer 635 correct" "Puzzle 5.1: .0053 seconds, answer 635 correct"
] ]
}, },
"execution_count": 23, "execution_count": 23,
@ -1278,7 +1278,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 6.1: .0078 seconds, answer 5877594983578 correct" "Puzzle 6.1: .0079 seconds, answer 5877594983578 correct"
] ]
}, },
"execution_count": 27, "execution_count": 27,
@ -1414,7 +1414,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 6.2: .0070 seconds, answer 11159825706149 correct" "Puzzle 6.2: .0064 seconds, answer 11159825706149 correct"
] ]
}, },
"execution_count": 29, "execution_count": 29,
@ -1798,7 +1798,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 7.2: .0022 seconds, answer 422102272495018 correct" "Puzzle 7.2: .0024 seconds, answer 422102272495018 correct"
] ]
}, },
"execution_count": 36, "execution_count": 36,
@ -1938,7 +1938,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 8.1: .8993 seconds, answer 24360 correct" "Puzzle 8.1: .8309 seconds, answer 24360 correct"
] ]
}, },
"execution_count": 38, "execution_count": 38,
@ -2077,7 +2077,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Puzzle 8.2: .8707 seconds, answer 2185817796 correct" "Puzzle 8.2: .8300 seconds, answer 2185817796 correct"
] ]
}, },
"execution_count": 40, "execution_count": 40,
@ -2090,6 +2090,267 @@
" solve_part2(boxes))" " solve_part2(boxes))"
] ]
}, },
{
"cell_type": "markdown",
"id": "c6db8a6e-47bf-490f-a54c-6472b4f935a0",
"metadata": {},
"source": [
"# [Day 9](https://adventofcode.com/2025/day/9): ChatGPT 5.1 Auto\n",
"\n",
"*For **Part 1**, ChatGPT wrote a `main` program that reads from input and prints the answer. I told it **Refactor to have a function that takes the points as input and returns the area** and got this:*"
]
},
{
"cell_type": "code",
"execution_count": 41,
"id": "aaf6b9df-b55d-4416-b806-167ad3b70fd5",
"metadata": {},
"outputs": [],
"source": [
"def largest_rectangle_area(points):\n",
" \"\"\"\n",
" Given a list of (x, y) points representing red tiles,\n",
" return the largest possible rectangle area using any\n",
" two points as opposite corners.\n",
" \"\"\"\n",
" max_area = 0\n",
" n = len(points)\n",
"\n",
" for i in range(n):\n",
" x1, y1 = points[i]\n",
" for j in range(i + 1, n):\n",
" x2, y2 = points[j]\n",
"\n",
" width = abs(x2 - x1) + 1\n",
" height = abs(y2 - y1) + 1\n",
" area = width * height\n",
"\n",
" if area > max_area:\n",
" max_area = area\n",
"\n",
" return max_area\n"
]
},
{
"cell_type": "code",
"execution_count": 42,
"id": "352cb801-67d7-4aaf-b0a1-1a59c1990c22",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Puzzle 9.1: .0282 seconds, answer 4772103936 correct"
]
},
"execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"points = parse(9, ints, show=0)\n",
"\n",
"answer(9.1, 4772103936, lambda:\n",
" largest_rectangle_area(points))"
]
},
{
"cell_type": "markdown",
"id": "5f8a09ab-0d49-4a6b-b8ea-33e4219af1eb",
"metadata": {},
"source": [
"*For **Part 2**, ChatGPT considered a [scanline algorithm](https://en.wikipedia.org/wiki/Scanline_rendering), and then went for a [flood fill](https://en.wikipedia.org/wiki/Flood_fill). It assumed \"I'm working with a grid that can have dimensions up to 2k x 2k, or 4 million cells, which seems manageable.\" So I told it **The grid can have dimensions up to 100,000 x 100,000 and there are about 500 red tile points**. ChatGPT came up with a [grid compression](https://stackoverflow.com/questions/29528934/coordinate-compression) method: define a grid where each red tile is in a separate cell, where the x and y extent of that cell spans an integer range (which must be recorded elsewhere). Now the grid is only of size roughly 500<sup>2</sup> instead of 100,000<sup>2</sup>."
]
},
{
"cell_type": "code",
"execution_count": 43,
"id": "16aa5c15-e5d5-4652-83d8-d99da9196617",
"metadata": {},
"outputs": [],
"source": [
"from typing import List, Tuple, Dict\n",
"\n",
"Point = Tuple[int, int]\n",
"Edge = Tuple[int, int, int, int]\n",
"\n",
"\n",
"def build_edges(points: List[Point]) -> List[Edge]:\n",
" \"\"\"\n",
" Build polygon edges from the red points in loop order.\n",
" Each edge is (x1, y1, x2, y2) between consecutive points (wrapped).\n",
" \"\"\"\n",
" n = len(points)\n",
" edges: List[Edge] = []\n",
" for i in range(n):\n",
" x1, y1 = points[i]\n",
" x2, y2 = points[(i + 1) % n]\n",
" edges.append((x1, y1, x2, y2))\n",
" return edges\n",
"\n",
"\n",
"def point_in_or_on_polygon(x: int, y: int, edges: List[Edge]) -> bool:\n",
" \"\"\"\n",
" Return True if lattice point (x, y) is inside the polygon or on its boundary.\n",
" Polygon is rectilinear (axis-aligned), edges given by build_edges.\n",
" Uses a ray-casting test along +x, counting intersections with vertical edges.\n",
" \"\"\"\n",
" inside = False\n",
"\n",
" for (x1, y1, x2, y2) in edges:\n",
" # Boundary check: point lies on this edge\n",
" if x1 == x2: # vertical edge\n",
" if x == x1 and min(y1, y2) <= y <= max(y1, y2):\n",
" return True\n",
" # For ray cast, only vertical edges can intersect ray to +x\n",
" # Use y-interval [min, max) to avoid double-counting vertices\n",
" if (y1 > y) != (y2 > y) and x1 > x:\n",
" inside = not inside\n",
" else: # horizontal edge\n",
" if y == y1 and min(x1, x2) <= x <= max(x1, x2):\n",
" return True\n",
" # horizontal edges do not contribute to this vertical ray count\n",
"\n",
" return inside\n",
"\n",
"\n",
"def rect_crosses_polygon(\n",
" xmin: int, xmax: int, ymin: int, ymax: int, edges: List[Edge]\n",
") -> bool:\n",
" \"\"\"\n",
" For a non-degenerate rectangle [xmin,xmax] x [ymin,ymax] (width>1,height>1),\n",
" check if any polygon edge passes through the *interior* of that rectangle.\n",
" Colinear edges on the boundary are allowed; only crossings inside are bad.\n",
" \"\"\"\n",
" for (x1, y1, x2, y2) in edges:\n",
" if x1 == x2:\n",
" # vertical edge at x = x1\n",
" x0 = x1\n",
" if xmin < x0 < xmax:\n",
" lo = max(min(y1, y2), ymin)\n",
" hi = min(max(y1, y2), ymax)\n",
" # If overlap has positive length, edge crosses interior\n",
" if hi > lo:\n",
" return True\n",
" else:\n",
" # horizontal edge at y = y1\n",
" y0 = y1\n",
" if ymin < y0 < ymax:\n",
" lo = max(min(x1, x2), xmin)\n",
" hi = min(max(x1, x2), xmax)\n",
" if hi > lo:\n",
" return True\n",
" return False\n",
"\n",
"\n",
"def largest_rectangle_area_red_green(points: List[Point]) -> int:\n",
" \"\"\"\n",
" Given the red tiles as vertices of an axis-aligned loop (in order),\n",
" return the largest rectangle area such that:\n",
"\n",
" - Two opposite corners are red tiles (from `points`).\n",
" - Every tile inside the rectangle is red or green, i.e., inside/on the loop.\n",
"\n",
" This works without building the full grid; it uses polygon geometry instead.\n",
" \"\"\"\n",
" n = len(points)\n",
" if n < 2:\n",
" return 0\n",
"\n",
" edges = build_edges(points)\n",
"\n",
" # Cache point-in-polygon results so each lattice point is tested at most once\n",
" point_cache: Dict[Point, bool] = {}\n",
"\n",
" def is_inside(x: int, y: int) -> bool:\n",
" key = (x, y)\n",
" if key in point_cache:\n",
" return point_cache[key]\n",
" val = point_in_or_on_polygon(x, y, edges)\n",
" point_cache[key] = val\n",
" return val\n",
"\n",
" max_area = 0\n",
"\n",
" for i in range(n):\n",
" x1, y1 = points[i]\n",
" for j in range(i + 1, n):\n",
" x2, y2 = points[j]\n",
"\n",
" xmin, xmax = (x1, x2) if x1 <= x2 else (x2, x1)\n",
" ymin, ymax = (y1, y2) if y1 <= y2 else (y2, y1)\n",
"\n",
" width = xmax - xmin + 1 # tiles\n",
" height = ymax - ymin + 1 # tiles\n",
" area = width * height\n",
"\n",
" if area <= max_area:\n",
" continue\n",
"\n",
" # Thin rectangles (one row or one column): treat as 1D segments.\n",
" if width == 1 or height == 1:\n",
" if width == 1:\n",
" # Vertical segment at x = xmin from ymin..ymax\n",
" x = xmin\n",
" ok = True\n",
" for yy in range(ymin, ymax + 1):\n",
" if not is_inside(x, yy):\n",
" ok = False\n",
" break\n",
" else:\n",
" # Horizontal segment at y = ymin from xmin..xmax\n",
" y = ymin\n",
" ok = True\n",
" for xx in range(xmin, xmax + 1):\n",
" if not is_inside(xx, y):\n",
" ok = False\n",
" break\n",
"\n",
" if ok:\n",
" max_area = area\n",
" continue\n",
"\n",
" # Proper 2D rectangle: width>1 and height>1\n",
"\n",
" # The two given red corners are on the boundary by definition.\n",
" # The other two corners must be inside/on polygon as well.\n",
" if not is_inside(x1, y2):\n",
" continue\n",
" if not is_inside(x2, y1):\n",
" continue\n",
"\n",
" # Ensure polygon boundary does not cut through the interior\n",
" if rect_crosses_polygon(xmin, xmax, ymin, ymax, edges):\n",
" continue\n",
"\n",
" max_area = area\n",
"\n",
" return max_area"
]
},
{
"cell_type": "code",
"execution_count": 44,
"id": "3388880d-6df9-4453-8b54-43175e3077e2",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Puzzle 9.2: .7622 seconds, answer 1529675217 correct"
]
},
"execution_count": 44,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"answer(9.2, 1529675217, lambda:\n",
" largest_rectangle_area_red_green(points))"
]
},
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "8aa26008-a652-4860-9c84-5ba4344d32f3", "id": "8aa26008-a652-4860-9c84-5ba4344d32f3",
@ -2102,7 +2363,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 41, "execution_count": 45,
"id": "16ce8af4-a1da-4280-9078-116ced3e9941", "id": "16ce8af4-a1da-4280-9078-116ced3e9941",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -2110,24 +2371,26 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Puzzle 1.1: .0013 seconds, answer 1182 correct\n", "Puzzle 1.1: .0012 seconds, answer 1182 correct\n",
"Puzzle 1.2: .0016 seconds, answer 6907 correct\n", "Puzzle 1.2: .0017 seconds, answer 6907 correct\n",
"Puzzle 2.1: .1247 seconds, answer 23560874270 correct\n", "Puzzle 2.1: .1217 seconds, answer 23560874270 correct\n",
"Puzzle 2.2: .1325 seconds, answer 44143124633 correct\n", "Puzzle 2.2: .1282 seconds, answer 44143124633 correct\n",
"Puzzle 3.1: .0042 seconds, answer 17085 correct\n", "Puzzle 3.1: .0038 seconds, answer 17085 correct\n",
"Puzzle 3.2: .0078 seconds, answer 169408143086082 correct\n", "Puzzle 3.2: .0069 seconds, answer 169408143086082 correct\n",
"Puzzle 4.1: .0182 seconds, answer 1569 correct\n", "Puzzle 4.1: .0170 seconds, answer 1569 correct\n",
"Puzzle 4.2: .0938 seconds, answer 9280 correct\n", "Puzzle 4.2: .0874 seconds, answer 9280 correct\n",
"Puzzle 5.1: .0056 seconds, answer 635 correct\n", "Puzzle 5.1: .0053 seconds, answer 635 correct\n",
"Puzzle 5.2: .0002 seconds, answer 369761800782619 correct\n", "Puzzle 5.2: .0002 seconds, answer 369761800782619 correct\n",
"Puzzle 6.1: .0078 seconds, answer 5877594983578 correct\n", "Puzzle 6.1: .0079 seconds, answer 5877594983578 correct\n",
"Puzzle 6.2: .0070 seconds, answer 11159825706149 correct\n", "Puzzle 6.2: .0064 seconds, answer 11159825706149 correct\n",
"Puzzle 7.1: .0009 seconds, answer 1681 correct\n", "Puzzle 7.1: .0009 seconds, answer 1681 correct\n",
"Puzzle 7.2: .0022 seconds, answer 422102272495018 correct\n", "Puzzle 7.2: .0024 seconds, answer 422102272495018 correct\n",
"Puzzle 8.1: .8993 seconds, answer 24360 correct\n", "Puzzle 8.1: .8309 seconds, answer 24360 correct\n",
"Puzzle 8.2: .8707 seconds, answer 2185817796 correct\n", "Puzzle 8.2: .8300 seconds, answer 2185817796 correct\n",
"Puzzle 9.1: .0282 seconds, answer 4772103936 correct\n",
"Puzzle 9.2: .7622 seconds, answer 1529675217 correct\n",
"\n", "\n",
"Time in seconds: sum = 2.178, mean = .136, median = .007, max = .899\n" "Time in seconds: sum = 2.842, mean = .158, median = .007, max = .831\n"
] ]
} }
], ],

File diff suppressed because one or more lines are too long