part2.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import argparse
  2. import functools
  3. from typing import List, NamedTuple, Set, Tuple
  4. import sys
  5. parser = argparse.ArgumentParser()
  6. parser.add_argument("ifile", type=argparse.FileType('r'))
  7. args = parser.parse_args()
  8. board = [[int(char) for char in line.strip()] for line in args.ifile.readlines()]
  9. def expandMap(board: List[List[int]]) -> List[List[int]]:
  10. map: List[List[int]] = []
  11. # build the top 'bar' of the map
  12. for line in board:
  13. clone = list(line)
  14. for repeat in range(0, 4):
  15. for index in range(0, len(line)):
  16. curr = clone[index + len(line) * repeat]
  17. if curr == 9:
  18. curr = 1
  19. else:
  20. curr += 1
  21. clone.append(curr)
  22. map.append(clone)
  23. for repeat in range(0, 4):
  24. for line_index in range(0, len(board)):
  25. line = []
  26. for col in range(0, len(map[0])):
  27. curr = map[len(board) * repeat + line_index][col]
  28. if curr == 9:
  29. curr = 1
  30. else:
  31. curr += 1
  32. line.append(curr)
  33. map.append(line)
  34. return map
  35. def printMap(board: List[List[int]]):
  36. for line in board:
  37. print("".join(map(str, line)))
  38. MAX_VAL = 10000000000000000000
  39. expanded_map = expandMap(board)
  40. # expanded_map = board
  41. max_x_pos = len(expanded_map[0]) - 1
  42. max_y_pos = len(expanded_map) - 1
  43. sys.setrecursionlimit(2 * (max_x_pos + max_y_pos + 20))
  44. class Point(NamedTuple):
  45. x: int
  46. y: int
  47. best_by_pos = [[MAX_VAL for pos in line] for line in expanded_map]
  48. best_by_pos[0][0] = 0
  49. traversed = [[False for pos in line] for line in expanded_map]
  50. CURR_BEST = MAX_VAL
  51. def lowerNode(costMap: List[List[int]], first: Point, second: Point):
  52. if costMap[first.y][first.x] < costMap[second.y][second.x]:
  53. return first
  54. else:
  55. return second
  56. def nodeSearch(untraversedSet: List[Point], currentCostMap: List[List[int]], edgeCosts: List[List[int]]):
  57. pos = functools.reduce(functools.partial(lowerNode, currentCostMap), untraversedSet[1:], untraversedSet[0])
  58. untraversedSet.remove(pos)
  59. if currentCostMap[pos.y][pos.x] == MAX_VAL:
  60. print("FAILED")
  61. sys.exit()
  62. if pos.x == max_x_pos and pos.y == max_y_pos:
  63. print(currentCostMap[pos.y][pos.x])
  64. sys.exit(1)
  65. # for each neighbor, consider costs
  66. consider = [
  67. Point(pos.x + 1, pos.y),
  68. Point(pos.x - 1, pos.y),
  69. Point(pos.x, pos.y - 1),
  70. Point(pos.x, pos.y + 1)
  71. ]
  72. for other in consider:
  73. if 0 <= other.x <= max_x_pos and 0 <= other.y <= max_y_pos and not traversed[other.y][other.x]:
  74. currentCostMap[other.y][other.x] = min(currentCostMap[other.y][other.x], currentCostMap[pos.y][pos.x] + edgeCosts[other.y][other.x])
  75. if other not in untraversedSet:
  76. untraversedSet.append(other)
  77. traversed[pos.y][pos.x] = True
  78. todo = [Point(0, 0)]
  79. while len(todo) != 0:
  80. nodeSearch(todo, best_by_pos, expanded_map)
  81. for line in traversed:
  82. print("".join(map(lambda x: "*" if x else " ", line)))