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.
6
fred.py
6
fred.py
@ -66,14 +66,12 @@ def toGrid(input, parser=None):
|
||||
FileNotFoundError: If the file cannot be found (if input is a file path).
|
||||
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 = []
|
||||
try:
|
||||
with open(input) as 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:
|
||||
raise FileNotFoundError(f"The file '{input}' was not found.")
|
||||
except IOError as e:
|
||||
|
Loading…
Reference in New Issue
Block a user