Last active
December 4, 2019 01:28
-
-
Save JL-Cox/03d2af823bdfb8c6ab1d2e03368379e1 to your computer and use it in GitHub Desktop.
Advent Of Code - 2019 - Day3 Puzzle2 (Complete)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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