Skip to content

Instantly share code, notes, and snippets.

@JL-Cox
Last active December 4, 2019 01:28
Show Gist options
  • Save JL-Cox/03d2af823bdfb8c6ab1d2e03368379e1 to your computer and use it in GitHub Desktop.
Save JL-Cox/03d2af823bdfb8c6ab1d2e03368379e1 to your computer and use it in GitHub Desktop.
Advent Of Code - 2019 - Day3 Puzzle2 (Complete)
import os
import re
from time import sleep
class bc:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
BLACK = "\033[30m"
RED = "\033[31m"
GREEN = "\033[32m"
YELLOW = "\033[33m"
BLUE = "\033[34m"
MAGENTA = "\033[35m"
CYAN = "\033[36m"
WHITE = "\033[37m"
# Actual Input
line_a = "R995,U982,R941,U681,L40,D390,R223,U84,L549,U568,R693,D410,R779,U33,L54,D18,L201,U616,R583,D502,R307,U46,L726,D355,L62,D973,R134,U619,L952,U669,L28,U729,L622,D821,R814,D149,L713,U380,R720,U438,L112,U587,R161,U789,R959,U254,R51,U648,R259,U555,R863,U610,L33,D97,L825,D489,R836,D626,L849,D262,L380,U831,R650,U832,R339,D538,L49,D808,L873,D33,L405,D655,R884,D630,R589,D291,L675,D210,L211,D325,L934,D515,R896,U97,L639,U654,L301,U507,L642,D416,L325,U696,L3,U999,R88,D376,L187,U107,R394,U273,R117,D872,R162,D496,L599,D855,L961,U830,L156,U999,L896,D380,L476,U100,R848,U547,L266,D490,L87,D376,L428,U265,R645,U584,L623,D658,L103,U946,R162,U678,R532,D761,L141,D48,L487,D246,L85,D680,R859,D345,L499,D194,L815,D742,R700,D141,L482,D442,L943,D110,L892,D486,L581,U733,L109,D807,L474,U866,R537,U217,R237,U915,R523,D394,L509,U333,R734,U511,R482,D921,R658,U860,R112,U527,L175,D619,R140,D402,L254,D956,L556,U447,L518,U60,L306,U88,R311,U654,L551,D38,R750,U835,L784,U648,L374,U211,L635,U429,R129,U849,R411,D135,L980,U40,R480,D91,R881,D292,R474,D956,L89,D640,L997,D397,L145,D126,R936,U135,L167,U289,R560,D745,L699,U978,L459,D947,L782,U427,L784,D561,R985,D395,L358,D928,R697,U561,L432,U790,R112,D474,R852,U862,R721,D337,L355,U598,L94,D951,L903,D175,R981,D444,L690,D729,L537,D458,R883,U152,R125,D363,L90,U260,R410,D858,L825,U185,R502,D648,R793,D600,L589,U931,L772,D498,L871,U326,L587,D789,L934,D889,R621,U689,R454,U475,L166,U85,R749,D253,R234,D96,R367,D33,R831,D783,R577,U402,R482,D741,R737,D474,L666".split(',')
line_b = "L996,D167,R633,D49,L319,D985,L504,U273,L330,U904,R741,U886,L719,D73,L570,U982,R121,U878,R36,U1,R459,D368,R229,D219,R191,U731,R493,U529,R53,D613,R690,U856,L470,D722,R464,D378,L187,U540,R990,U942,R574,D991,R29,D973,R905,D63,R745,D444,L546,U939,L848,U860,R877,D181,L392,D798,R564,D189,R14,U120,R118,D350,R798,U462,R335,D497,R916,D722,R398,U91,L284,U660,R759,U676,L270,U69,L774,D850,R440,D669,L994,U187,R698,U864,R362,U523,L128,U89,R272,D40,L134,U571,L594,D737,L830,D956,L213,D97,R833,U454,R319,U809,L506,D792,R746,U283,R858,D743,R107,U499,R102,D71,R822,U9,L547,D915,L717,D783,L53,U871,R920,U284,R378,U312,R970,D316,R243,D512,R439,U530,R246,D824,R294,D726,R541,D250,R859,D134,R893,U631,L288,D151,L796,D759,R17,D656,L562,U136,R861,U42,L66,U552,R240,D121,L966,U288,L810,D104,R332,U667,L63,D463,R527,D27,R238,D401,L397,D888,R168,U808,L976,D462,R299,U385,L183,U303,L121,U385,R260,U80,R420,D532,R725,U500,L376,U852,R98,D597,L10,D441,L510,D592,L652,D230,L290,U41,R521,U726,R444,U440,L192,D255,R690,U141,R21,U942,L31,U894,L994,U472,L460,D357,R150,D721,R125,D929,R473,U707,R670,D118,R255,U287,R290,D374,R223,U489,R533,U49,L833,D805,L549,D291,R288,D664,R639,U866,R205,D746,L832,U864,L774,U610,R186,D56,R517,U294,L935,D304,L581,U899,R749,U741,R569,U282,R460,D925,L431,D168,R506,D949,L39,D472,R379,D125,R243,U335,L310,D762,R412,U426,L584,D981,L971,U575,L129,U885,L946,D221,L779,U902,R251,U75,L729,D956,L211,D130,R7,U664,L915,D928,L613,U740,R572,U733,R277,U7,R953,D962,L635,U641,L199".split(',')
# Test Input
# line_a = "R75,D30,R83,U83,L12,D49,R71,U7,L72,U62,R66,U55,R34,D71,R55,D58,R83".split(',')
# line_b = "R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51,U98,R91,D20,R16,D67,R40,U7,R15,U6,R7".split(',')
# line_a = "R8,U5,L5,D3".split(',')
# line_b = "U7,R6,D4,L4".split(',')
# Spits Out Grid Based on Height and Width
def create_grid(w, h, letter):
grid = []
last_progress = int((len(grid) / (h / 20)))
on = "|"
off = "."
os.system('clear')
for height in range(h):
current_progress = int((len(grid) / (h / 20)))
row = []
for width in range(w):
row.append(".")
# Only update progress bar when value changes
if current_progress > last_progress:
last_progress = current_progress
os.system('clear')
print(bc.HEADER + f"Building Grid {letter}:" + bc.ENDC)
print(bc.BOLD + f"[" + bc.ENDC + bc.OKGREEN + f"{current_progress*on}" + bc.BLUE + f"{(20-current_progress)*off}" + bc.ENDC + bc.BOLD + f"]" + bc.ENDC)
grid.append(row)
os.system('clear')
print(bc.OKGREEN + bc.BOLD + f"Grid {letter} complete!" + bc.ENDC)
sleep(1)
current_progress = int((len(grid) / (h / 20)))
print(f"[{current_progress*on}{(20-current_progress)*off}]")
return grid
# Find how far each line goes.
# These numbers are used to build the grid and avoid index errors
def find_path_dimensions(line):
x, high_x, low_x = 0, 0, 0
y, high_y, low_y = 0, 0, 0
for movement in line:
distance = int(re.findall("\d+", movement)[0])
if movement[0] == "L":
y -= distance
if y < low_y:
low_y = y
elif movement[0] == "R":
y += distance
if y > high_y:
high_y = y
elif movement[0] == "U":
x += distance
if x > high_x:
high_x = x
elif movement[0] == "D":
x -= distance
if x < low_x:
low_x = x
else:
print("Something went wrong!")
print(f"x: {low_x} -> {high_x}")
print(f"y: {low_y} -> {high_y}")
return high_x, low_x, high_y, low_y
# Take each set of instructions and draw their paths
# This is done individually and then a third blank map is created
def draw_lines(line, line_grid):
half_mark = (int(len(line_grid[0])/2), int(len(line_grid)/2))
x, y = 0, 1
x_y = [half_mark[x], half_mark[y]]
line_grid[x_y[y]][x_y[x]] = "O"
for movement in line:
direction = movement[0]
distance = int(re.findall("\d+", movement)[0])
if direction == "L":
for step in range(1, distance + 1):
line_grid[x_y[y]][x_y[x] - step] = "-"
x_y[x] = x_y[x] - distance
line_grid[x_y[y]][x_y[x]] = "+"
elif direction == "R":
for step in range(1, distance + 1):
line_grid[x_y[y]][x_y[x] + step] = "-"
x_y[x] = x_y[x] + distance
line_grid[x_y[y]][x_y[x]] = "+"
elif direction == "U":
for step in range(1, distance + 1):
line_grid[x_y[y] - step][x_y[x]] = "|"
x_y[y] = x_y[y] - distance
line_grid[x_y[y]][x_y[x]] = "+"
elif direction == "D":
for step in range(1, distance + 1):
line_grid[x_y[y] + step][x_y[x]] = "|"
x_y[y] = x_y[y] + distance
line_grid[x_y[y]][x_y[x]] = "+"
else:
print("Something went wrong. :/")
return line_grid
# The blank map created earlier is used to draw both paths
# and find the intersections
def compare_grids(grid_1, grid_2, grid_3, origin):
directionals = ["-","|","+"]
intersections = []
distances = []
for row in range(len(grid_1)):
for column in range(len(grid_1[0])):
if grid_1[row][column] in directionals and grid_2[row][column] in directionals:
grid_3[row][column] = "X"
intersections.append((row, column))
elif grid_1[row][column] != ".":
grid_3[row][column] = grid_1[row][column]
elif grid_2[row][column] != ".":
grid_3[row][column] = grid_2[row][column]
for intersection in intersections:
distances.append(abs(intersection[0] - origin[0]) + abs(intersection[1] - origin[1]))
return grid_3, min(distances), intersections
# Puzzle B's Method
# Take all the data, retrace the steps and count the steps to each "X"
def find_lowest_steps(line_a, line_b, answer_grid, intersections, starting_point):
y, x = 0, 1
a_int_steps = {}
b_int_steps = {}
a_step_count = 0
b_step_count = 0
a_xy = [starting_point[y], starting_point[x]]
b_xy = [starting_point[y], starting_point[x]]
# Find Line_A's Steps
for move in line_a:
direction = move[0]
distance = int(re.findall("\d+", move)[0])
if direction == "L": # DIR
for step in range(1, distance + 1): # STEP
current_cursor = answer_grid[a_xy[y]][a_xy[x] - step]
current_coordinates = (a_xy[y], a_xy[x] - step)
a_step_count += 1
if current_cursor == "X" and current_coordinates not in a_int_steps: # CHECK
a_int_steps[current_coordinates] = a_step_count # ADD TO DICT
a_xy[x] = a_xy[x] - distance # ADJUST CURSOR
elif direction == "R":
for step in range(1, distance + 1):
current_cursor = answer_grid[a_xy[y]][a_xy[x] + step]
current_coordinates = (a_xy[y], a_xy[x] + step)
a_step_count += 1
if current_cursor == "X" and current_coordinates not in a_int_steps: # CHECK
a_int_steps[current_coordinates] = a_step_count
a_xy[x] = a_xy[x] + distance
elif direction == "U":
for step in range(1, distance + 1):
current_cursor = answer_grid[a_xy[y] - step][a_xy[x]]
current_coordinates = (a_xy[y] - step, a_xy[x])
a_step_count += 1
if current_cursor == "X" and current_coordinates not in a_int_steps: # CHECK
a_int_steps[current_coordinates] = a_step_count
a_xy[y] = a_xy[y] - distance
elif direction == "D":
for step in range(1, distance + 1):
current_cursor = answer_grid[a_xy[y] + step][a_xy[x]]
current_coordinates = (a_xy[y] + step, a_xy[x])
a_step_count += 1
if current_cursor == "X" and current_coordinates not in a_int_steps: # CHECK
a_int_steps[current_coordinates] = a_step_count
a_xy[y] = a_xy[y] + distance
# Find Line_B's Steps
for move in line_b:
direction = move[0]
distance = int(re.findall("\d+", move)[0])
if direction == "L": # DIR
for step in range(1, distance + 1): # STEP
current_cursor = answer_grid[b_xy[y]][b_xy[x] - step]
current_coordinates = (b_xy[y], b_xy[x] - step)
b_step_count += 1
if current_cursor == "X" and current_coordinates not in b_int_steps: # CHECK
b_int_steps[current_coordinates] = b_step_count # ADD TO DICT
b_xy[x] = b_xy[x] - distance # ADJUST CURSOR
elif direction == "R":
for step in range(1, distance + 1):
current_cursor = answer_grid[b_xy[y]][b_xy[x] + step]
current_coordinates = (b_xy[y], b_xy[x] + step)
b_step_count += 1
if current_cursor == "X" and current_coordinates not in b_int_steps: # CHECK
b_int_steps[current_coordinates] = b_step_count
b_xy[x] = b_xy[x] + distance
elif direction == "U":
for step in range(1, distance + 1):
current_cursor = answer_grid[b_xy[y] - step][b_xy[x]]
current_coordinates = (b_xy[y] - step, b_xy[x])
b_step_count += 1
if current_cursor == "X" and current_coordinates not in b_int_steps: # CHECK
b_int_steps[current_coordinates] = b_step_count
b_xy[y] = b_xy[y] - distance
elif direction == "D":
for step in range(1, distance + 1):
current_cursor = answer_grid[b_xy[y] + step][b_xy[x]]
current_coordinates = (b_xy[y] + step, b_xy[x])
b_step_count += 1
if current_cursor == "X" and current_coordinates not in b_int_steps: # CHECK
b_int_steps[current_coordinates] = b_step_count
b_xy[y] = b_xy[y] + distance
lowest_sum = 100000000000000
for key in a_int_steps:
sum_of_steps = a_int_steps[key] + b_int_steps[key]
if sum_of_steps < lowest_sum:
lowest_sum = sum_of_steps
return lowest_sum
# Run Program
os.system('clear')
print(bc.HEADER + "Calculating grid dimensions!\n" + bc.ENDC)
sleep(2)
# Calculate Distance Traveled By Each Line
print(bc.CYAN + "Line A:" + bc.ENDC)
line_a_path = find_path_dimensions(line_a)
print(bc.MAGENTA + "\nLine B:" + bc.ENDC)
line_b_path = find_path_dimensions(line_b)
sleep(2)
# Calculate Grid Dimensions
total_width = line_a_path[0] + abs(line_a_path[1]) + line_b_path[0] + abs(line_b_path[1])
total_height = line_a_path[2] + abs(line_a_path[3]) + line_b_path[2] + abs(line_b_path[3])
# Display Grid Dimensions
os.system('clear')
print(bc.HEADER + f"Grid Dimensions: ({total_width}, {total_height})" + bc.ENDC)
sleep(2)
# Build Grids
grid_a = create_grid(total_width+(int(total_height/2)), total_height+int(total_width/2), "A")
grid_b = create_grid(total_width+(int(total_height/2)), total_height+int(total_width/2), "B")
grid_c = create_grid(total_width+(int(total_height/2)), total_height+int(total_width/2), "C")
# Calculate Origin (y, x)
origin_coordinates = (int(len(grid_a) / 2), int(len(grid_a[0]) / 2))
# Build Line A Grid
os.system('clear')
print(bc.OKGREEN + "Grids built!" + bc.ENDC)
print(bc.HEADER + "Building Line_A_Grid..." + bc.ENDC)
line_a_grid = draw_lines(line_a, grid_a)
# Build Line B Grid
os.system('clear')
print(bc.OKGREEN + "Grids built!" + bc.ENDC)
print(bc.OKGREEN + "Line_A_Grid built!" + bc.ENDC)
print(bc.HEADER + "Building Line_B_Grid..." + bc.ENDC)
line_b_grid = draw_lines(line_b, grid_b)
# Build Line C Grid, Retrieve Answer
os.system('clear')
print(bc.OKGREEN + "Grids built!" + bc.ENDC)
print(bc.OKGREEN + "Line_A_Grid built!" + bc.ENDC)
print(bc.OKGREEN + "Line_B_Grid built!" + bc.ENDC)
print(bc.HEADER + "Comparing grids..." + bc.ENDC)
compare_results = compare_grids(grid_a, grid_b, grid_c, origin_coordinates)
line_c_grid = compare_results[0]
p1_answer = compare_results[1]
print(bc.OKGREEN + bc.BOLD + f"P1 Answer: {p1_answer}" + bc.ENDC)
#################### PART 2 ########################
intersection_list = compare_results[2]
step_counts = find_lowest_steps(line_a, line_b, line_c_grid, intersection_list, origin_coordinates)
p2_answer = step_counts
print(bc.OKGREEN + bc.BOLD + f"P2 Answer: {p2_answer}" + bc.ENDC)
exit()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment