Started working on 2024/10 P1
This commit is contained in:
parent
5b4728200f
commit
e7a1efc09a
106
2024/10/10.md
Normal file
106
2024/10/10.md
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
## \-\-- Day 10: Hoof It \-\--
|
||||||
|
|
||||||
|
You all arrive at a [Lava Production Facility](/2023/day/15) on a
|
||||||
|
floating island in the sky. As the others begin to search the massive
|
||||||
|
industrial complex, you feel a small nose boop your leg and look down to
|
||||||
|
discover a reindeer wearing a hard
|
||||||
|
hat.
|
||||||
|
|
||||||
|
The reindeer is holding a book titled \"Lava Island Hiking Guide\".
|
||||||
|
However, when you open the book, you discover that most of it seems to
|
||||||
|
have been scorched by lava! As you\'re about to ask how you can help,
|
||||||
|
the reindeer brings you a blank [topographic
|
||||||
|
map](https://en.wikipedia.org/wiki/Topographic_map) of
|
||||||
|
the surrounding area (your puzzle input) and looks up at you excitedly.
|
||||||
|
|
||||||
|
Perhaps you can help fill in the missing hiking trails?
|
||||||
|
|
||||||
|
The topographic map indicates the *height* at each position using a
|
||||||
|
scale from `0` (lowest) to `9` (highest). For example:
|
||||||
|
|
||||||
|
0123
|
||||||
|
1234
|
||||||
|
8765
|
||||||
|
9876
|
||||||
|
|
||||||
|
Based on un-scorched scraps of the book, you determine that a good
|
||||||
|
hiking trail is *as long as possible* and has an *even, gradual, uphill
|
||||||
|
slope*. For all practical purposes, this means that a *hiking trail* is
|
||||||
|
any path that starts at height `0`, ends at height `9`, and always
|
||||||
|
increases by a height of exactly 1 at each step. Hiking trails never
|
||||||
|
include diagonal steps - only up, down, left, or right (from the
|
||||||
|
perspective of the map).
|
||||||
|
|
||||||
|
You look up from the map and notice that the reindeer has helpfully
|
||||||
|
begun to construct a small pile of pencils, markers, rulers, compasses,
|
||||||
|
stickers, and other equipment you might need to update the map with
|
||||||
|
hiking trails.
|
||||||
|
|
||||||
|
A *trailhead* is any position that starts one or more hiking trails -
|
||||||
|
here, these positions will always have height `0`. Assembling more
|
||||||
|
fragments of pages, you establish that a trailhead\'s *score* is the
|
||||||
|
number of `9`-height positions reachable from that trailhead via a
|
||||||
|
hiking trail. In the above example, the single trailhead in the top left
|
||||||
|
corner has a score of `1` because it can reach a single `9` (the one in
|
||||||
|
the bottom left).
|
||||||
|
|
||||||
|
This trailhead has a score of `2`:
|
||||||
|
|
||||||
|
...0...
|
||||||
|
...1...
|
||||||
|
...2...
|
||||||
|
6543456
|
||||||
|
7.....7
|
||||||
|
8.....8
|
||||||
|
9.....9
|
||||||
|
|
||||||
|
(The positions marked `.` are impassable tiles to simplify these
|
||||||
|
examples; they do not appear on your actual topographic map.)
|
||||||
|
|
||||||
|
This trailhead has a score of `4` because every `9` is reachable via a
|
||||||
|
hiking trail except the one immediately to the left of the trailhead:
|
||||||
|
|
||||||
|
..90..9
|
||||||
|
...1.98
|
||||||
|
...2..7
|
||||||
|
6543456
|
||||||
|
765.987
|
||||||
|
876....
|
||||||
|
987....
|
||||||
|
|
||||||
|
This topographic map contains *two* trailheads; the trailhead at the top
|
||||||
|
has a score of `1`, while the trailhead at the bottom has a score of
|
||||||
|
`2`:
|
||||||
|
|
||||||
|
10..9..
|
||||||
|
2...8..
|
||||||
|
3...7..
|
||||||
|
4567654
|
||||||
|
...8..3
|
||||||
|
...9..2
|
||||||
|
.....01
|
||||||
|
|
||||||
|
Here\'s a larger example:
|
||||||
|
|
||||||
|
89010123
|
||||||
|
78121874
|
||||||
|
87430965
|
||||||
|
96549874
|
||||||
|
45678903
|
||||||
|
32019012
|
||||||
|
01329801
|
||||||
|
10456732
|
||||||
|
|
||||||
|
This larger example has 9 trailheads. Considering the trailheads in
|
||||||
|
reading order, they have scores of `5`, `6`, `5`, `3`, `1`, `3`, `5`,
|
||||||
|
`3`, and `5`. Adding these scores together, the sum of the scores of all
|
||||||
|
trailheads is `36`.
|
||||||
|
|
||||||
|
The reindeer gleefully carries over a protractor and adds it to the
|
||||||
|
pile. *What is the sum of the scores of all trailheads on your
|
||||||
|
topographic map?*
|
||||||
|
|
||||||
|
To begin, [get your puzzle input](10/input).
|
||||||
|
|
||||||
|
Answer:
|
||||||
|
|
31
2024/10/solution.py
Normal file
31
2024/10/solution.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#!/bin/python3
|
||||||
|
import sys,time,re
|
||||||
|
from pprint import pprint
|
||||||
|
sys.path.insert(0, '../../')
|
||||||
|
from fred import list2int,get_re,nprint,lprint,loadFile,toGrid,TSP,dijkstra
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
input_f = 'test'
|
||||||
|
|
||||||
|
part = 1
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 1 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
|
||||||
|
if part == 1:
|
||||||
|
grid = toGrid(input_f,True)
|
||||||
|
nprint(grid)
|
||||||
|
|
||||||
|
print(dijkstra(grid,0,9))
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 2 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
if part == 2:
|
||||||
|
exit()
|
||||||
|
|
||||||
|
print("--- %s seconds ---" % (time.time() - start_time))
|
162
2024/10/solution_old.py
Normal file
162
2024/10/solution_old.py
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
#!/bin/python3
|
||||||
|
import sys,time,re
|
||||||
|
from pprint import pprint
|
||||||
|
sys.path.insert(0, '../../')
|
||||||
|
from fred import list2int,get_re,nprint,lprint,loadFile,toGrid, get_value_in_direction,addTuples
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
input_f = 'test2'
|
||||||
|
|
||||||
|
part = 1
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 1 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
|
||||||
|
if part == 1:
|
||||||
|
|
||||||
|
|
||||||
|
def get_value_in_direction(grid, position, direction=None, length=1, type: str = None):
|
||||||
|
"""
|
||||||
|
Get the value(s) in a specified direction from a given position in a grid.
|
||||||
|
If no direction is provided, returns the value at the current position.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
grid (list of list of int/float/str): The 2D grid.
|
||||||
|
position (set): A set containing x (row index) and y (column index) as integers.
|
||||||
|
direction (str, optional): The direction to check. Defaults to None.
|
||||||
|
length (int, optional): The number of steps to check in the given direction. Default is 1.
|
||||||
|
type (str, optional): The type of result to return ('list' or 'str'). Defaults to None.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list or str: A list or string of values in the specified direction, or a single value.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If direction is invalid or position is not a set of two integers.
|
||||||
|
TypeError: If grid is not a list of lists.
|
||||||
|
"""
|
||||||
|
if not all(isinstance(row, list) for row in grid):
|
||||||
|
raise TypeError("Grid must be a list of lists.")
|
||||||
|
|
||||||
|
# Ensure position is a set of two integers
|
||||||
|
if len(position) != 2 or not all(isinstance(coord, int) for coord in position):
|
||||||
|
raise ValueError("Position must be a set containing two integers (x, y).")
|
||||||
|
|
||||||
|
x, y = position
|
||||||
|
offsets = {
|
||||||
|
'up': (-1, 0),
|
||||||
|
'down': (1, 0),
|
||||||
|
'left': (0, -1),
|
||||||
|
'right': (0, 1),
|
||||||
|
'up-left': (-1, -1),
|
||||||
|
'up-right': (-1, 1),
|
||||||
|
'down-left': (1, -1),
|
||||||
|
'down-right': (1, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
# If no direction is given, return the value at the current position
|
||||||
|
if direction is None:
|
||||||
|
if 0 <= x < len(grid) and 0 <= y < len(grid[x]):
|
||||||
|
return grid[x][y]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Validate direction
|
||||||
|
if direction not in offsets:
|
||||||
|
raise ValueError(f"Invalid direction: {direction}. Choose from {list(offsets.keys())}")
|
||||||
|
|
||||||
|
dx, dy = offsets[direction]
|
||||||
|
new_x, new_y = x + dx, y + dy
|
||||||
|
|
||||||
|
values = []
|
||||||
|
|
||||||
|
if length == 1:
|
||||||
|
# Check for out-of-bounds
|
||||||
|
if 0 <= new_x < len(grid) and 0 <= new_y < len(grid[new_x]):
|
||||||
|
return grid[new_x][new_y]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
for step in range(length):
|
||||||
|
new_x, new_y = x + step * dx, y + step * dy
|
||||||
|
# Check for out-of-bounds
|
||||||
|
if 0 <= new_x < len(grid) and 0 <= new_y < len(grid[new_x]):
|
||||||
|
values.append(grid[new_x][new_y])
|
||||||
|
else:
|
||||||
|
return [] # Return empty list if any position is out of bounds
|
||||||
|
if type == 'list':
|
||||||
|
return values
|
||||||
|
elif type == 'str':
|
||||||
|
return ''.join(values)
|
||||||
|
else:
|
||||||
|
return values
|
||||||
|
|
||||||
|
grid = toGrid(input_f,True)
|
||||||
|
|
||||||
|
def extract_tuples(nested_list):
|
||||||
|
result = []
|
||||||
|
for item in nested_list:
|
||||||
|
if isinstance(item, tuple): # Check if the item is a tuple
|
||||||
|
result.append(item)
|
||||||
|
elif isinstance(item, list): # If it's a list, recurse into it
|
||||||
|
result.extend(extract_tuples(item))
|
||||||
|
return result
|
||||||
|
|
||||||
|
def find_path(grid,pos:set,cur):
|
||||||
|
path = 0
|
||||||
|
if cur == 9:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
cur+=1
|
||||||
|
|
||||||
|
|
||||||
|
if get_value_in_direction(grid,pos,'up') == cur:
|
||||||
|
path += find_path(grid,addTuples(pos,(-1,0)),cur)
|
||||||
|
|
||||||
|
if get_value_in_direction(grid,pos,'down') == cur:
|
||||||
|
path += find_path(grid,addTuples(pos,(1,0)),cur)
|
||||||
|
|
||||||
|
if get_value_in_direction(grid,pos,'left') == cur:
|
||||||
|
path += find_path(grid,addTuples(pos,(0,-1)),cur)
|
||||||
|
|
||||||
|
if get_value_in_direction(grid,pos,'right') == cur:
|
||||||
|
path += find_path(grid,addTuples(pos,(0,1)),cur)
|
||||||
|
|
||||||
|
|
||||||
|
return path
|
||||||
|
|
||||||
|
result = 0
|
||||||
|
|
||||||
|
for r, row in enumerate(grid):
|
||||||
|
for c, col in enumerate(row):
|
||||||
|
#get_value_in_direction(grid, position, direction=None, length=1, type: str = None):
|
||||||
|
if grid[r][c] == 0:
|
||||||
|
if get_value_in_direction(grid,(r,c),'up') == 1:
|
||||||
|
#print(find_path(grid,(r-1,c),1))
|
||||||
|
result += find_path(grid,(r-1,c),1)
|
||||||
|
|
||||||
|
if get_value_in_direction(grid,(r,c),'down') == 1:
|
||||||
|
result += find_path(grid,(r+1,c),1)
|
||||||
|
#print(find_path(grid,(r+1,c),1,0))
|
||||||
|
|
||||||
|
if get_value_in_direction(grid,(r,c),'left') == 1:
|
||||||
|
result += find_path(grid,(r,c-1),1)
|
||||||
|
#print(find_path(grid,(r,c-1),1,0))
|
||||||
|
|
||||||
|
if get_value_in_direction(grid,(r,c),'right') == 1:
|
||||||
|
result += find_path(grid,(r,c+1),1)
|
||||||
|
#print(find_path(grid,(r,c+1),1,0))
|
||||||
|
|
||||||
|
print(result)
|
||||||
|
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 2 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
if part == 2:
|
||||||
|
exit()
|
||||||
|
|
||||||
|
print("--- %s seconds ---" % (time.time() - start_time))
|
Binary file not shown.
4
fred.py
4
fred.py
@ -66,14 +66,12 @@ def toGrid(input, parser=None):
|
|||||||
FileNotFoundError: If the file cannot be found (if input is a file path).
|
FileNotFoundError: If the file cannot be found (if input is a file path).
|
||||||
ValueError: If the parser function is invalid.
|
ValueError: If the parser function is invalid.
|
||||||
"""
|
"""
|
||||||
if parser is not None and not callable(parser):
|
|
||||||
raise ValueError("The parser must be a callable function.")
|
|
||||||
|
|
||||||
grid = []
|
grid = []
|
||||||
try:
|
try:
|
||||||
with open(input) as file:
|
with open(input) as file:
|
||||||
for line in file:
|
for line in file:
|
||||||
grid.append(list2int(line.rstrip()) if parser else list(line.rstrip())) # Use parser or default processing
|
grid.append(list2int(list(line.rstrip())) if parser else list(line.rstrip())) # Use parser or default processing
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
raise FileNotFoundError(f"The file '{input}' was not found.")
|
raise FileNotFoundError(f"The file '{input}' was not found.")
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
|
Loading…
Reference in New Issue
Block a user