Started working on 2024/10 P1

This commit is contained in:
FrederikBaerentsen 2024-12-10 15:14:29 +01:00
parent 5b4728200f
commit e7a1efc09a
5 changed files with 301 additions and 4 deletions

106
2024/10/10.md Normal file
View 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
View 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
View 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.

View File

@ -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: