You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
5.2 KiB
138 lines
5.2 KiB
from queue import PriorityQueue |
|
import sys |
|
import copy |
|
|
|
class grid: |
|
def __init__(self): |
|
self.y = [] |
|
self.attempts = 0 |
|
self.solutions = 0 |
|
self.current_smallest_solution_level = None |
|
self.point_costs = {(0, 0): 0} |
|
self.next_point_queue = PriorityQueue() |
|
self.next_point_queue.put((0, (0, 0))) |
|
self.visited = {} |
|
|
|
def addline(self, line): |
|
self.y.append([int(i) for i in line]) |
|
self.maxy = len(self.y) - 1 |
|
self.maxx = len(self.y[0]) - 1 |
|
|
|
# print(self.maxx) |
|
# print(self.maxy) |
|
|
|
def largegrid(self): |
|
for f in self.y: |
|
temp = copy.copy(f) |
|
for i in range(1, 5): |
|
for t in range(len(temp)): |
|
temp[t] += 1 |
|
if temp[t] > 9: |
|
temp[t] -= 9 |
|
f.extend(temp) |
|
temp2 = copy.copy(self.y) |
|
for i in range(1, 5): |
|
temp3 = copy.copy(temp2) |
|
for f in temp3: |
|
self.y.append([(g+i-1) % 9 + 1 for g in f]) |
|
self.maxy = len(self.y) - 1 |
|
self.maxx = len(self.y[0]) - 1 |
|
|
|
# def initialpath(self): |
|
|
|
def findpath(self): |
|
while not self.next_point_queue.empty(): |
|
level, poi = self.next_point_queue.get() |
|
if self.visited.get(poi, False): |
|
continue |
|
self.visited[poi] = True |
|
self.attempts += 1 |
|
if self.attempts % 100000 == 0: |
|
print('Attempt %d, solutions: %d, cost: %d, visited: %d, queued: %d' % ( |
|
self.attempts, self.solutions, self.current_smallest_solution_level or -1, |
|
len(self.visited), self.next_point_queue.qsize())) |
|
|
|
neighbors = self.get_neighbors(poi, level) |
|
|
|
for i in neighbors: |
|
next_level = level + int(self.y[i[0]][i[1]]) |
|
if (self.current_smallest_solution_level is not None and |
|
next_level > self.current_smallest_solution_level): |
|
# We already found a solution that was overall less risky |
|
# than the current path, so who cares. |
|
continue |
|
if i == (self.maxy, self.maxx): |
|
self.solutions += 1 |
|
if (self.current_smallest_solution_level is None or |
|
next_level < self.current_smallest_solution_level): |
|
self.current_smallest_solution_level = next_level |
|
# print('Found solution: ', i, ', orig level ', level) |
|
continue |
|
elif self.visited.get(i, False) and (i in self.point_costs and self.point_costs[i] <= next_level): |
|
# We already visited the point on a cheaper path. |
|
continue |
|
else: |
|
# print('Path: %s, next: %s' % (repr(path), i)) |
|
self.point_costs[i] = next_level |
|
self.next_point_queue.put((next_level, i)) |
|
|
|
# Try to find a path from the current point to the end by going down and right |
|
# alternatingly, so we can restrict the search to paths less costly than the |
|
# current one. |
|
next_level = level |
|
while poi != (self.maxx, self.maxy): |
|
if poi[0] < self.maxx: |
|
poi = (poi[0] + 1, poi[1]) |
|
next_level += int(self.y[poi[0]][poi[1]]) |
|
if poi in self.point_costs and next_level > self.point_costs[poi]: |
|
break |
|
self.point_costs[poi] = next_level |
|
|
|
if poi[1] < self.maxy: |
|
poi = (poi[0], poi[1] + 1) |
|
next_level += int(self.y[poi[0]][poi[1]]) |
|
if poi in self.point_costs and next_level > self.point_costs[poi]: |
|
break |
|
self.point_costs[poi] = next_level |
|
|
|
if poi == (self.maxx, self.maxy): |
|
self.solutions += 1 |
|
if (self.current_smallest_solution_level is None or |
|
next_level < self.current_smallest_solution_level): |
|
self.current_smallest_solution_level = next_level |
|
|
|
|
|
def get_neighbors(self, poi, level): |
|
nex = {} |
|
rv = [] |
|
if poi[0] != self.maxy: |
|
nex.setdefault(self.y[poi[0] + 1][poi[1]], list()).append((poi[0] + 1, poi[1])) |
|
if poi[1] != self.maxx: |
|
nex.setdefault(self.y[poi[0]][poi[1] + 1], list()).append((poi[0], poi[1] + 1)) |
|
if poi[0] != 0: |
|
nex.setdefault(self.y[poi[0] - 1][poi[1]], list()).append((poi[0] - 1, poi[1])) |
|
if poi[1] != 0: |
|
nex.setdefault(self.y[poi[0]][poi[1] - 1], list()).append((poi[0], poi[1] - 1)) |
|
|
|
order = sorted(nex.keys()) |
|
|
|
for j in order: |
|
for p in nex[j]: |
|
if (p not in self.visited and |
|
(p not in self.point_costs or self.point_costs[p] >= level + j)): |
|
rv.append(p) |
|
|
|
return rv |
|
|
|
gri = grid() |
|
|
|
with open(sys.argv[1], 'r') as f: |
|
for i in f.readlines(): |
|
gri.addline(i.strip()) |
|
gri.largegrid() |
|
#for f in gri.y: |
|
# print("".join(map(str, f))) |
|
|
|
gri.findpath() |
|
|
|
print(gri.current_smallest_solution_level) |