Solved 2024/18 P1
This commit is contained in:
parent
d119956812
commit
2674f6e723
170
2024/16/16.md
Normal file
170
2024/16/16.md
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
## \-\-- Day 16: Reindeer Maze \-\--
|
||||||
|
|
||||||
|
It\'s time again for the [Reindeer Olympics](/2015/day/14)! This year,
|
||||||
|
the big event is the *Reindeer Maze*, where the Reindeer compete for the
|
||||||
|
*[lowest
|
||||||
|
score]{title="I would say it's like Reindeer Golf, but knowing Reindeer, it's almost certainly nothing like Reindeer Golf."}*.
|
||||||
|
|
||||||
|
You and The Historians arrive to search for the Chief right as the event
|
||||||
|
is about to start. It wouldn\'t hurt to watch a little, right?
|
||||||
|
|
||||||
|
The Reindeer start on the Start Tile (marked `S`) facing *East* and need
|
||||||
|
to reach the End Tile (marked `E`). They can move forward one tile at a
|
||||||
|
time (increasing their score by `1` point), but never into a wall (`#`).
|
||||||
|
They can also rotate clockwise or counterclockwise 90 degrees at a time
|
||||||
|
(increasing their score by `1000` points).
|
||||||
|
|
||||||
|
To figure out the best place to sit, you start by grabbing a map (your
|
||||||
|
puzzle input) from a nearby kiosk. For example:
|
||||||
|
|
||||||
|
###############
|
||||||
|
#.......#....E#
|
||||||
|
#.#.###.#.###.#
|
||||||
|
#.....#.#...#.#
|
||||||
|
#.###.#####.#.#
|
||||||
|
#.#.#.......#.#
|
||||||
|
#.#.#####.###.#
|
||||||
|
#...........#.#
|
||||||
|
###.#.#####.#.#
|
||||||
|
#...#.....#.#.#
|
||||||
|
#.#.#.###.#.#.#
|
||||||
|
#.....#...#.#.#
|
||||||
|
#.###.#.#.#.#.#
|
||||||
|
#S..#.....#...#
|
||||||
|
###############
|
||||||
|
|
||||||
|
There are many paths through this maze, but taking any of the best paths
|
||||||
|
would incur a score of only `7036`. This can be achieved by taking a
|
||||||
|
total of `36` steps forward and turning 90 degrees a total of `7` times:
|
||||||
|
|
||||||
|
###############
|
||||||
|
#.......#....E#
|
||||||
|
#.#.###.#.###^#
|
||||||
|
#.....#.#...#^#
|
||||||
|
#.###.#####.#^#
|
||||||
|
#.#.#.......#^#
|
||||||
|
#.#.#####.###^#
|
||||||
|
#..>>>>>>>>v#^#
|
||||||
|
###^#.#####v#^#
|
||||||
|
#>>^#.....#v#^#
|
||||||
|
#^#.#.###.#v#^#
|
||||||
|
#^....#...#v#^#
|
||||||
|
#^###.#.#.#v#^#
|
||||||
|
#S..#.....#>>^#
|
||||||
|
###############
|
||||||
|
|
||||||
|
Here\'s a second example:
|
||||||
|
|
||||||
|
#################
|
||||||
|
#...#...#...#..E#
|
||||||
|
#.#.#.#.#.#.#.#.#
|
||||||
|
#.#.#.#...#...#.#
|
||||||
|
#.#.#.#.###.#.#.#
|
||||||
|
#...#.#.#.....#.#
|
||||||
|
#.#.#.#.#.#####.#
|
||||||
|
#.#...#.#.#.....#
|
||||||
|
#.#.#####.#.###.#
|
||||||
|
#.#.#.......#...#
|
||||||
|
#.#.###.#####.###
|
||||||
|
#.#.#...#.....#.#
|
||||||
|
#.#.#.#####.###.#
|
||||||
|
#.#.#.........#.#
|
||||||
|
#.#.#.#########.#
|
||||||
|
#S#.............#
|
||||||
|
#################
|
||||||
|
|
||||||
|
In this maze, the best paths cost `11048` points; following one such
|
||||||
|
path would look like this:
|
||||||
|
|
||||||
|
#################
|
||||||
|
#...#...#...#..E#
|
||||||
|
#.#.#.#.#.#.#.#^#
|
||||||
|
#.#.#.#...#...#^#
|
||||||
|
#.#.#.#.###.#.#^#
|
||||||
|
#>>v#.#.#.....#^#
|
||||||
|
#^#v#.#.#.#####^#
|
||||||
|
#^#v..#.#.#>>>>^#
|
||||||
|
#^#v#####.#^###.#
|
||||||
|
#^#v#..>>>>^#...#
|
||||||
|
#^#v###^#####.###
|
||||||
|
#^#v#>>^#.....#.#
|
||||||
|
#^#v#^#####.###.#
|
||||||
|
#^#v#^........#.#
|
||||||
|
#^#v#^#########.#
|
||||||
|
#S#>>^..........#
|
||||||
|
#################
|
||||||
|
|
||||||
|
Note that the path shown above includes one 90 degree turn as the very
|
||||||
|
first move, rotating the Reindeer from facing East to facing North.
|
||||||
|
|
||||||
|
Analyze your map carefully. *What is the lowest score a Reindeer could
|
||||||
|
possibly get?*
|
||||||
|
|
||||||
|
Your puzzle answer was `108504`.
|
||||||
|
|
||||||
|
The first half of this puzzle is complete! It provides one gold star: \*
|
||||||
|
|
||||||
|
## \-\-- Part Two \-\-- {#part2}
|
||||||
|
|
||||||
|
Now that you know what the best paths look like, you can figure out the
|
||||||
|
best spot to sit.
|
||||||
|
|
||||||
|
Every non-wall tile (`S`, `.`, or `E`) is equipped with places to sit
|
||||||
|
along the edges of the tile. While determining which of these tiles
|
||||||
|
would be the best spot to sit depends on a whole bunch of factors (how
|
||||||
|
comfortable the seats are, how far away the bathrooms are, whether
|
||||||
|
there\'s a pillar blocking your view, etc.), the most important factor
|
||||||
|
is *whether the tile is on one of the best paths through the maze*. If
|
||||||
|
you sit somewhere else, you\'d miss all the action!
|
||||||
|
|
||||||
|
So, you\'ll need to determine which tiles are part of *any* best path
|
||||||
|
through the maze, including the `S` and `E` tiles.
|
||||||
|
|
||||||
|
In the first example, there are `45` tiles (marked `O`) that are part of
|
||||||
|
at least one of the various best paths through the maze:
|
||||||
|
|
||||||
|
###############
|
||||||
|
#.......#....O#
|
||||||
|
#.#.###.#.###O#
|
||||||
|
#.....#.#...#O#
|
||||||
|
#.###.#####.#O#
|
||||||
|
#.#.#.......#O#
|
||||||
|
#.#.#####.###O#
|
||||||
|
#..OOOOOOOOO#O#
|
||||||
|
###O#O#####O#O#
|
||||||
|
#OOO#O....#O#O#
|
||||||
|
#O#O#O###.#O#O#
|
||||||
|
#OOOOO#...#O#O#
|
||||||
|
#O###.#.#.#O#O#
|
||||||
|
#O..#.....#OOO#
|
||||||
|
###############
|
||||||
|
|
||||||
|
In the second example, there are `64` tiles that are part of at least
|
||||||
|
one of the best paths:
|
||||||
|
|
||||||
|
#################
|
||||||
|
#...#...#...#..O#
|
||||||
|
#.#.#.#.#.#.#.#O#
|
||||||
|
#.#.#.#...#...#O#
|
||||||
|
#.#.#.#.###.#.#O#
|
||||||
|
#OOO#.#.#.....#O#
|
||||||
|
#O#O#.#.#.#####O#
|
||||||
|
#O#O..#.#.#OOOOO#
|
||||||
|
#O#O#####.#O###O#
|
||||||
|
#O#O#..OOOOO#OOO#
|
||||||
|
#O#O###O#####O###
|
||||||
|
#O#O#OOO#..OOO#.#
|
||||||
|
#O#O#O#####O###.#
|
||||||
|
#O#O#OOOOOOO..#.#
|
||||||
|
#O#O#O#########.#
|
||||||
|
#O#OOO..........#
|
||||||
|
#################
|
||||||
|
|
||||||
|
Analyze your map further. *How many tiles are part of at least one of
|
||||||
|
the best paths through the maze?*
|
||||||
|
|
||||||
|
Answer:
|
||||||
|
|
||||||
|
Although it hasn\'t changed, you can still [get your puzzle
|
||||||
|
input](16/input).
|
||||||
|
|
87
2024/16/solution.py
Normal file
87
2024/16/solution.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
#!/bin/python3
|
||||||
|
import sys,time,re
|
||||||
|
from pprint import pprint
|
||||||
|
sys.path.insert(0, '../../')
|
||||||
|
from fred import list2int,get_re,nprint,lprint,loadFile,dijkstra,toGrid,dfs,bfs,findInGrid,get_value_in_direction,addTuples,subTuples,create_graph_from_grid,manhattan_distance
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
input_f = 'input'
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 1 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
|
||||||
|
def part1():
|
||||||
|
grid = toGrid(input_f)
|
||||||
|
|
||||||
|
start = findInGrid(grid,'S')
|
||||||
|
end = findInGrid(grid,'E')
|
||||||
|
|
||||||
|
print(start,end)
|
||||||
|
|
||||||
|
def a_star(graph, start, end, heuristic):
|
||||||
|
|
||||||
|
import heapq
|
||||||
|
|
||||||
|
# Priority queue stores (f_score, current_node, current_direction)
|
||||||
|
priority_queue = [(0, start, None)]
|
||||||
|
g_scores = {node: float('inf') for node in graph} # Cost from start to each node
|
||||||
|
g_scores[start] = 0
|
||||||
|
|
||||||
|
f_scores = {node: float('inf') for node in graph}
|
||||||
|
f_scores[start] = heuristic(start, end)
|
||||||
|
|
||||||
|
previous_nodes = {node: None for node in graph}
|
||||||
|
|
||||||
|
while priority_queue:
|
||||||
|
current_f_score, current_node, previous_direction = heapq.heappop(priority_queue)
|
||||||
|
|
||||||
|
if current_node == end:
|
||||||
|
break
|
||||||
|
|
||||||
|
for neighbor, weight in graph[current_node]:
|
||||||
|
current_direction = (
|
||||||
|
neighbor[0] - current_node[0], # Row direction (-1, 0, 1)
|
||||||
|
neighbor[1] - current_node[1] # Col direction (-1, 0, 1)
|
||||||
|
)
|
||||||
|
|
||||||
|
turn_cost = 1000 if previous_direction and current_direction != previous_direction else 0
|
||||||
|
tentative_g_score = g_scores[current_node] + weight + turn_cost
|
||||||
|
|
||||||
|
if tentative_g_score < g_scores[neighbor]:
|
||||||
|
g_scores[neighbor] = tentative_g_score
|
||||||
|
f_scores[neighbor] = tentative_g_score + heuristic(neighbor, end)
|
||||||
|
previous_nodes[neighbor] = current_node
|
||||||
|
heapq.heappush(priority_queue, (f_scores[neighbor], neighbor, current_direction))
|
||||||
|
|
||||||
|
path = []
|
||||||
|
while end is not None:
|
||||||
|
path.append(end)
|
||||||
|
end = previous_nodes[end]
|
||||||
|
path.reverse()
|
||||||
|
|
||||||
|
return path, g_scores[path[-1]]
|
||||||
|
|
||||||
|
|
||||||
|
graph = create_graph_from_grid(grid,start,end,'#')
|
||||||
|
|
||||||
|
path, score = a_star(graph,start,end,manhattan_distance)
|
||||||
|
#print(path)
|
||||||
|
return score #Instead of implementing edge cases, just try with turning (adding 1000) to the result, if that's wrong, just don't add it. I got it right by not turning right away.
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
print('Part 1:',part1(), '\t\t', round((time.time() - start_time)*1000), 'ms')
|
||||||
|
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 2 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
def part2():
|
||||||
|
return
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
print('Part 2:',part2(), '\t\t', round((time.time() - start_time)*1000), 'ms')
|
144
2024/18/18.md
Normal file
144
2024/18/18.md
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
## \-\-- Day 18: RAM Run \-\--
|
||||||
|
|
||||||
|
You and The Historians look a lot more pixelated than you remember.
|
||||||
|
You\'re [inside a computer](/2017/day/2) at the North Pole!
|
||||||
|
|
||||||
|
Just as you\'re about to check out your surroundings, a program runs up
|
||||||
|
to you. \"This region of memory isn\'t safe! The User misunderstood what
|
||||||
|
a [pushdown
|
||||||
|
automaton](https://en.wikipedia.org/wiki/Pushdown_automaton)
|
||||||
|
is and their algorithm is pushing whole *bytes* down on top of us!
|
||||||
|
Run!\"
|
||||||
|
|
||||||
|
The algorithm is fast - it\'s going to cause a byte to fall into your
|
||||||
|
memory space once every
|
||||||
|
[nanosecond](https://www.youtube.com/watch?v=9eyFDBPk4Yw)!
|
||||||
|
Fortunately, you\'re *faster*, and by quickly scanning the algorithm,
|
||||||
|
you create a *list of which bytes will fall* (your puzzle input) in the
|
||||||
|
order they\'ll land in your memory space.
|
||||||
|
|
||||||
|
Your memory space is a two-dimensional grid with coordinates that range
|
||||||
|
from `0` to `70` both horizontally and vertically. However, for the sake
|
||||||
|
of example, suppose you\'re on a smaller grid with coordinates that
|
||||||
|
range from `0` to `6` and the following list of incoming byte positions:
|
||||||
|
|
||||||
|
5,4
|
||||||
|
4,2
|
||||||
|
4,5
|
||||||
|
3,0
|
||||||
|
2,1
|
||||||
|
6,3
|
||||||
|
2,4
|
||||||
|
1,5
|
||||||
|
0,6
|
||||||
|
3,3
|
||||||
|
2,6
|
||||||
|
5,1
|
||||||
|
1,2
|
||||||
|
5,5
|
||||||
|
2,5
|
||||||
|
6,5
|
||||||
|
1,4
|
||||||
|
0,4
|
||||||
|
6,4
|
||||||
|
1,1
|
||||||
|
6,1
|
||||||
|
1,0
|
||||||
|
0,5
|
||||||
|
1,6
|
||||||
|
2,0
|
||||||
|
|
||||||
|
Each byte position is given as an `X,Y` coordinate, where `X` is the
|
||||||
|
distance from the left edge of your memory space and `Y` is the distance
|
||||||
|
from the top edge of your memory space.
|
||||||
|
|
||||||
|
You and The Historians are currently in the top left corner of the
|
||||||
|
memory space (at `0,0`) and need to reach the exit in the bottom right
|
||||||
|
corner (at `70,70` in your memory space, but at `6,6` in this example).
|
||||||
|
You\'ll need to simulate the falling bytes to plan out where it will be
|
||||||
|
safe to run; for now, simulate just the first few bytes falling into
|
||||||
|
your memory space.
|
||||||
|
|
||||||
|
As bytes fall into your memory space, they make that coordinate
|
||||||
|
*corrupted*. Corrupted memory coordinates cannot be entered by you or
|
||||||
|
The Historians, so you\'ll need to plan your route carefully. You also
|
||||||
|
cannot leave the boundaries of the memory space; your only hope is to
|
||||||
|
reach the exit.
|
||||||
|
|
||||||
|
In the above example, if you were to draw the memory space after the
|
||||||
|
first `12` bytes have fallen (using `.` for safe and `#` for corrupted),
|
||||||
|
it would look like this:
|
||||||
|
|
||||||
|
...#...
|
||||||
|
..#..#.
|
||||||
|
....#..
|
||||||
|
...#..#
|
||||||
|
..#..#.
|
||||||
|
.#..#..
|
||||||
|
#.#....
|
||||||
|
|
||||||
|
You can take steps up, down, left, or right. After just 12 bytes have
|
||||||
|
corrupted locations in your memory space, the shortest path from the top
|
||||||
|
left corner to the exit would take `22` steps. Here (marked with `O`) is
|
||||||
|
one such path:
|
||||||
|
|
||||||
|
OO.#OOO
|
||||||
|
.O#OO#O
|
||||||
|
.OOO#OO
|
||||||
|
...#OO#
|
||||||
|
..#OO#.
|
||||||
|
.#.O#..
|
||||||
|
#.#OOOO
|
||||||
|
|
||||||
|
Simulate the first kilobyte (`1024` bytes) falling onto your memory
|
||||||
|
space. Afterward, *what is the minimum number of steps needed to reach
|
||||||
|
the exit?*
|
||||||
|
|
||||||
|
Your puzzle answer was `294`.
|
||||||
|
|
||||||
|
The first half of this puzzle is complete! It provides one gold star: \*
|
||||||
|
|
||||||
|
## \-\-- Part Two \-\-- {#part2}
|
||||||
|
|
||||||
|
The Historians aren\'t as used to moving around in this pixelated
|
||||||
|
universe as you are. You\'re afraid they\'re not going to be fast enough
|
||||||
|
to make it to the exit before the path is completely blocked.
|
||||||
|
|
||||||
|
To determine how fast everyone needs to go, you need to determine *the
|
||||||
|
first byte that will cut off the path to the exit*.
|
||||||
|
|
||||||
|
In the above example, after the byte at `1,1` falls, there is still a
|
||||||
|
path to the exit:
|
||||||
|
|
||||||
|
O..#OOO
|
||||||
|
O##OO#O
|
||||||
|
O#OO#OO
|
||||||
|
OOO#OO#
|
||||||
|
###OO##
|
||||||
|
.##O###
|
||||||
|
#.#OOOO
|
||||||
|
|
||||||
|
However, after adding the very next byte (at `6,1`), there is no longer
|
||||||
|
a path to the exit:
|
||||||
|
|
||||||
|
...#...
|
||||||
|
.##..##
|
||||||
|
.#..#..
|
||||||
|
...#..#
|
||||||
|
###..##
|
||||||
|
.##.###
|
||||||
|
#.#....
|
||||||
|
|
||||||
|
So, in this example, the coordinates of the first byte that prevents the
|
||||||
|
exit from being reachable are `6,1`.
|
||||||
|
|
||||||
|
Simulate more of the bytes that are about to corrupt your memory space.
|
||||||
|
*What are the coordinates of the first byte that will prevent the exit
|
||||||
|
from being reachable from your starting position?* (Provide the answer
|
||||||
|
as two integers separated by a comma with no other characters.)
|
||||||
|
|
||||||
|
Answer:
|
||||||
|
|
||||||
|
Although it hasn\'t changed, you can still [get your puzzle
|
||||||
|
input](18/input).
|
||||||
|
|
76
2024/18/solution.py
Normal file
76
2024/18/solution.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#!/bin/python3
|
||||||
|
import sys,time,re
|
||||||
|
from pprint import pprint
|
||||||
|
sys.path.insert(0, '../../')
|
||||||
|
from fred import list2int,get_re,nprint,lprint,loadFile,bfs,get_value_in_direction,addTuples,grid_valid
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
input_f = 'input'
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 1 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
def part1():
|
||||||
|
instructions = []
|
||||||
|
grid = []
|
||||||
|
w = 70
|
||||||
|
h = 70
|
||||||
|
end = (h,w)
|
||||||
|
start = (0,0)
|
||||||
|
with open(input_f) as file:
|
||||||
|
for line in file:
|
||||||
|
l = list2int(line.rstrip().split(','))
|
||||||
|
instructions.append((l[0],l[1]))
|
||||||
|
#print(instructions)
|
||||||
|
|
||||||
|
grid = [[ '.' for x in range(0,w+1)] for y in range(0,h+1)]
|
||||||
|
|
||||||
|
for i in range(1024):
|
||||||
|
x = instructions[i]
|
||||||
|
grid[x[0]][x[1]] = '#'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def is_goal(node):
|
||||||
|
#print(node)
|
||||||
|
|
||||||
|
return True if node == end else False
|
||||||
|
|
||||||
|
def get_neighbors(node):
|
||||||
|
directions = ['up','down','left','right']
|
||||||
|
offsets = {
|
||||||
|
'up': (-1, 0),
|
||||||
|
'down': (1, 0),
|
||||||
|
'left': (0, -1),
|
||||||
|
'right': (0, 1),
|
||||||
|
}
|
||||||
|
neighbors = []
|
||||||
|
|
||||||
|
# Loop through all the directions
|
||||||
|
for d in directions:
|
||||||
|
tmp = addTuples(offsets[d],node)
|
||||||
|
if get_value_in_direction(grid,node,d) != '#' and grid_valid(tmp[0],tmp[1],grid):
|
||||||
|
neighbors.append((tmp[0],tmp[1]))
|
||||||
|
# Return the list of valid neighbors
|
||||||
|
return neighbors
|
||||||
|
|
||||||
|
goal_nodes, path = bfs((0,0),is_goal,get_neighbors)
|
||||||
|
print(goal_nodes)
|
||||||
|
return len(path[goal_nodes[0]])-1
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
print('Part 1:',part1(), '\t\t', round((time.time() - start_time)*1000), 'ms')
|
||||||
|
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 2 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
def part2():
|
||||||
|
return
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
print('Part 2:',part2(), '\t\t', round((time.time() - start_time)*1000), 'ms')
|
Binary file not shown.
125
fred.py
125
fred.py
@ -2,6 +2,17 @@ import sys,re,heapq
|
|||||||
from itertools import permutations
|
from itertools import permutations
|
||||||
from termcolor import colored
|
from termcolor import colored
|
||||||
|
|
||||||
|
def findInGrid(grid:list,x:str) -> set:
|
||||||
|
"""Find the location of a character in a grid.
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
for r,row in enumerate(grid):
|
||||||
|
for c, char in enumerate(row):
|
||||||
|
if char == x:
|
||||||
|
return (r,c)
|
||||||
|
|
||||||
def loadFile(input_f):
|
def loadFile(input_f):
|
||||||
"""
|
"""
|
||||||
Loads a file and returns its lines as a list.
|
Loads a file and returns its lines as a list.
|
||||||
@ -179,7 +190,6 @@ def dprint(graph: dict):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise RuntimeError(f"An error occurred while printing the dictionary: {e}")
|
raise RuntimeError(f"An error occurred while printing the dictionary: {e}")
|
||||||
|
|
||||||
|
|
||||||
def lprint(x: str, log: bool):
|
def lprint(x: str, log: bool):
|
||||||
"""
|
"""
|
||||||
Prints a string if logging is enabled.
|
Prints a string if logging is enabled.
|
||||||
@ -271,7 +281,10 @@ def nprint(grid, cur: set = None, sign: str = None, positions:list = None):
|
|||||||
for idx, i in enumerate(grid):
|
for idx, i in enumerate(grid):
|
||||||
for jdx, j in enumerate(i):
|
for jdx, j in enumerate(i):
|
||||||
if jdx == 0:
|
if jdx == 0:
|
||||||
prepend = str(idx)+' '
|
if idx < 10:
|
||||||
|
prepend = ' '+str(idx)+' '
|
||||||
|
else:
|
||||||
|
prepend = ''+str(idx)+' '
|
||||||
else:
|
else:
|
||||||
prepend = ''
|
prepend = ''
|
||||||
|
|
||||||
@ -286,7 +299,7 @@ def nprint(grid, cur: set = None, sign: str = None, positions:list = None):
|
|||||||
else:
|
else:
|
||||||
if positions is not None:
|
if positions is not None:
|
||||||
if (idx,jdx) in positions:
|
if (idx,jdx) in positions:
|
||||||
print(prepend+colored(grid[idx][jdx],'red'),end=' ')
|
print(prepend+colored(grid[idx][jdx],'green'),end=' ')
|
||||||
else:
|
else:
|
||||||
print(prepend+grid[idx][jdx], end=' ')
|
print(prepend+grid[idx][jdx], end=' ')
|
||||||
else:
|
else:
|
||||||
@ -296,8 +309,26 @@ def nprint(grid, cur: set = None, sign: str = None, positions:list = None):
|
|||||||
|
|
||||||
for r in range(len(grid[0])):
|
for r in range(len(grid[0])):
|
||||||
if r == 0:
|
if r == 0:
|
||||||
print(' ',end='')
|
print(' 0',end='')
|
||||||
print(r,end=' ')
|
|
||||||
|
else:
|
||||||
|
if r%2 == 0:
|
||||||
|
print(r,end='')
|
||||||
|
else:
|
||||||
|
print(' ',end='')
|
||||||
|
print()
|
||||||
|
for r in range(len(grid[0])):
|
||||||
|
if r == 0:
|
||||||
|
print(' ',end='')
|
||||||
|
|
||||||
|
else:
|
||||||
|
if r%2 != 0:
|
||||||
|
print(r,end='')
|
||||||
|
else:
|
||||||
|
if r != 9:
|
||||||
|
print(' ',end='')
|
||||||
|
else:
|
||||||
|
print('',end='')
|
||||||
print()
|
print()
|
||||||
|
|
||||||
def list2int(x):
|
def list2int(x):
|
||||||
@ -647,6 +678,9 @@ def dfs(grid:list, pos:set) -> list:
|
|||||||
dfs(pos[0], pos[1])
|
dfs(pos[0], pos[1])
|
||||||
return list(visited)
|
return list(visited)
|
||||||
|
|
||||||
|
def manhattan_distance(node, goal):
|
||||||
|
return abs(node[0] - goal[0]) + abs(node[1] - goal[1])
|
||||||
|
|
||||||
# Should probably be added to the regular dfs.
|
# Should probably be added to the regular dfs.
|
||||||
def flood_fill(cells, pos):
|
def flood_fill(cells, pos):
|
||||||
"""
|
"""
|
||||||
@ -677,4 +711,83 @@ def flood_fill(cells, pos):
|
|||||||
dfs(neighbor)
|
dfs(neighbor)
|
||||||
|
|
||||||
dfs(pos)
|
dfs(pos)
|
||||||
return list(visited)
|
return list(visited)
|
||||||
|
|
||||||
|
def create_graph_from_grid(grid, start, end,wall):
|
||||||
|
"""
|
||||||
|
Converts a grid into a graph representation for use in pathfinding algorithms.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- grid: A 2D list representing the grid, where '#' is a wall, and '.' is a path.
|
||||||
|
- start: The coordinates of the start node (row, col).
|
||||||
|
- end: The coordinates of the end node (row, col).
|
||||||
|
- wall: The string of the wall node.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- graph: A dictionary where each key is a node (row, col), and the value is a list of tuples.
|
||||||
|
Each tuple represents (neighbor, weight).
|
||||||
|
"""
|
||||||
|
rows, cols = len(grid), len(grid[0])
|
||||||
|
graph = {}
|
||||||
|
|
||||||
|
# Helper to get neighbors
|
||||||
|
def neighbors(r, c):
|
||||||
|
for dr, dc in [(-1, 0), (1, 0), (0, -1), (0, 1)]: # Up, Down, Left, Right
|
||||||
|
nr, nc = r + dr, c + dc
|
||||||
|
if 0 <= nr < rows and 0 <= nc < cols and grid[nr][nc] != '#':
|
||||||
|
yield (nr, nc)
|
||||||
|
|
||||||
|
for r in range(rows):
|
||||||
|
for c in range(cols):
|
||||||
|
if grid[r][c] != '#': # Only process valid cells
|
||||||
|
graph[(r, c)] = [(neighbor, 1) for neighbor in neighbors(r, c)] # Weight is 1
|
||||||
|
|
||||||
|
return graph
|
||||||
|
|
||||||
|
def a_star(graph, start, end, heuristic):
|
||||||
|
"""
|
||||||
|
A* Algorithm to find the shortest path between two nodes in a graph.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- graph: A dictionary where each key is a node, and the value is a list of tuples.
|
||||||
|
Each tuple represents (neighbor, distance).
|
||||||
|
- start: The starting node (row, col).
|
||||||
|
- end: The destination node (row, col).
|
||||||
|
- heuristic: A function that estimates the cost from a node to the end.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- path: A list of nodes that represent the shortest path from start to end.
|
||||||
|
- total_cost: The total cost of the shortest path.
|
||||||
|
"""
|
||||||
|
priority_queue = [(0, start)] # (f_score, current_node)
|
||||||
|
g_scores = {node: float('inf') for node in graph} # Cost from start to each node
|
||||||
|
g_scores[start] = 0
|
||||||
|
|
||||||
|
f_scores = {node: float('inf') for node in graph} # Estimated total cost (g + h)
|
||||||
|
f_scores[start] = heuristic(start, end)
|
||||||
|
|
||||||
|
previous_nodes = {node: None for node in graph}
|
||||||
|
|
||||||
|
while priority_queue:
|
||||||
|
current_f_score, current_node = heapq.heappop(priority_queue)
|
||||||
|
|
||||||
|
if current_node == end:
|
||||||
|
break
|
||||||
|
|
||||||
|
for neighbor, weight in graph[current_node]:
|
||||||
|
tentative_g_score = g_scores[current_node] + weight
|
||||||
|
|
||||||
|
if tentative_g_score < g_scores[neighbor]:
|
||||||
|
g_scores[neighbor] = tentative_g_score
|
||||||
|
f_scores[neighbor] = tentative_g_score + heuristic(neighbor, end)
|
||||||
|
previous_nodes[neighbor] = current_node
|
||||||
|
heapq.heappush(priority_queue, (f_scores[neighbor], neighbor))
|
||||||
|
|
||||||
|
# Reconstruct the path
|
||||||
|
path = []
|
||||||
|
while end is not None:
|
||||||
|
path.append(end)
|
||||||
|
end = previous_nodes[end]
|
||||||
|
path.reverse()
|
||||||
|
|
||||||
|
return path, g_scores[path[-1]]
|
Loading…
Reference in New Issue
Block a user