Solution to problem 6 in Python
This commit is contained in:
parent
b8b0f026f1
commit
78c98449ec
196
src/Year_2018/P6.py
Normal file
196
src/Year_2018/P6.py
Normal file
@ -0,0 +1,196 @@
|
||||
# --- Day 6: Chronal Coordinates ---
|
||||
|
||||
# The device on your wrist beeps several times, and once again you feel like
|
||||
# you're falling.
|
||||
|
||||
# "Situation critical," the device announces. "Destination indeterminate.
|
||||
# Chronal interference detected. Please specify new target coordinates."
|
||||
|
||||
# The device then produces a list of coordinates (your puzzle input). Are they
|
||||
# places it thinks are safe or dangerous? It recommends you check manual page
|
||||
# 729. The Elves did not give you a manual.
|
||||
|
||||
# If they're dangerous, maybe you can minimize the danger by finding the
|
||||
# coordinate that gives the largest distance from the other points.
|
||||
|
||||
# Using only the Manhattan distance, determine the area around each coordinate
|
||||
# by counting the number of integer X,Y locations that are closest to that
|
||||
# coordinate (and aren't tied in distance to any other coordinate).
|
||||
|
||||
# Your goal is to find the size of the largest area that isn't infinite. For
|
||||
# example, consider the following list of coordinates:
|
||||
|
||||
# 1, 1
|
||||
# 1, 6
|
||||
# 8, 3
|
||||
# 3, 4
|
||||
# 5, 5
|
||||
# 8, 9
|
||||
|
||||
# If we name these coordinates A through F, we can draw them on a grid, putting
|
||||
# 0,0 at the top left:
|
||||
|
||||
# ..........
|
||||
# .A........
|
||||
# ..........
|
||||
# ........C.
|
||||
# ...D......
|
||||
# .....E....
|
||||
# .B........
|
||||
# ..........
|
||||
# ..........
|
||||
# ........F.
|
||||
|
||||
# This view is partial - the actual grid extends infinitely in all directions.
|
||||
# Using the Manhattan distance, each location's closest coordinate can be
|
||||
# determined, shown here in lowercase:
|
||||
|
||||
# aaaaa.cccc
|
||||
# aAaaa.cccc
|
||||
# aaaddecccc
|
||||
# aadddeccCc
|
||||
# ..dDdeeccc
|
||||
# bb.deEeecc
|
||||
# bBb.eeee..
|
||||
# bbb.eeefff
|
||||
# bbb.eeffff
|
||||
# bbb.ffffFf
|
||||
|
||||
# Locations shown as . are equally far from two or more coordinates, and so
|
||||
# they don't count as being closest to any.
|
||||
|
||||
# In this example, the areas of coordinates A, B, C, and F are infinite - while
|
||||
# not shown here, their areas extend forever outside the visible grid. However,
|
||||
# the areas of coordinates D and E are finite: D is closest to 9 locations, and
|
||||
# E is closest to 17 (both including the coordinate's location itself).
|
||||
# Therefore, in this example, the size of the largest area is 17.
|
||||
|
||||
# What is the size of the largest area that isn't infinite?
|
||||
|
||||
from collections import defaultdict
|
||||
from copy import copy
|
||||
|
||||
with open("files/P6.txt") as f:
|
||||
puzzle = [
|
||||
tuple(map(int, line.split(", ")))
|
||||
for line in f.read().strip().split("\n")
|
||||
]
|
||||
|
||||
|
||||
def manhattan_dist(coordinate, x, y):
|
||||
return abs(coordinate[0] - x) + abs(coordinate[1] - y)
|
||||
|
||||
|
||||
def part_1():
|
||||
coordinates = copy(puzzle)
|
||||
|
||||
# Max/min coordinates
|
||||
max_first = max(coordinates, key=lambda e: (e[0], e[0]))[0]
|
||||
max_second = max(coordinates, key=lambda e: (e[1], e[1]))[1]
|
||||
min_first = min(coordinates, key=lambda e: (e[0], e[0]))[0]
|
||||
min_second = min(coordinates, key=lambda e: (e[1], e[1]))[1]
|
||||
|
||||
# Holds total area per coordinate region
|
||||
areas = defaultdict(int)
|
||||
|
||||
# Holds disqualified (infinite) regions
|
||||
infiniteCoordinates = set()
|
||||
|
||||
for x in range(min_first, max_first + 1):
|
||||
for y in range(min_second, max_second + 1):
|
||||
# Holds distances mapped to coordinates
|
||||
distances = defaultdict(list)
|
||||
|
||||
for coordinate in coordinates:
|
||||
distances[manhattan_dist(coordinate, x, y)].append(coordinate)
|
||||
|
||||
shortestDistance = min(distances.keys())
|
||||
|
||||
if len(distances[shortestDistance]) == 1:
|
||||
areas[distances[shortestDistance][0]] += 1
|
||||
|
||||
# Borders also indicate infinite regions
|
||||
if (
|
||||
y == min_second
|
||||
or y == max_second
|
||||
or x == min_first
|
||||
or x == max_first
|
||||
):
|
||||
infiniteCoordinates |= set(distances[shortestDistance])
|
||||
|
||||
# Remove disqualified (infinite) regions
|
||||
for coordinate in infiniteCoordinates:
|
||||
del areas[coordinate]
|
||||
|
||||
print(f"The size of the largest area is {max(areas.values())}")
|
||||
|
||||
|
||||
# --- Part Two ---
|
||||
|
||||
# On the other hand, if the coordinates are safe, maybe the best you can do is
|
||||
# try to find a region near as many coordinates as possible.
|
||||
|
||||
# For example, suppose you want the sum of the Manhattan distance to all of the
|
||||
# coordinates to be less than 32. For each location, add up the distances to all
|
||||
# of the given coordinates; if the total of those distances is less than 32,
|
||||
# that location is within the desired region. Using the same coordinates as
|
||||
# above, the resulting region looks like this:
|
||||
|
||||
# ..........
|
||||
# .A........
|
||||
# ..........
|
||||
# ...###..C.
|
||||
# ..#D###...
|
||||
# ..###E#...
|
||||
# .B.###....
|
||||
# ..........
|
||||
# ..........
|
||||
# ........F.
|
||||
|
||||
# In particular, consider the highlighted location 4,3 located at the top middle
|
||||
# of the region. Its calculation is as follows, where abs() is the absolute
|
||||
# value function:
|
||||
|
||||
# Distance to coordinate A: abs(4-1) + abs(3-1) = 5
|
||||
# Distance to coordinate B: abs(4-1) + abs(3-6) = 6
|
||||
# Distance to coordinate C: abs(4-8) + abs(3-3) = 4
|
||||
# Distance to coordinate D: abs(4-3) + abs(3-4) = 2
|
||||
# Distance to coordinate E: abs(4-5) + abs(3-5) = 3
|
||||
# Distance to coordinate F: abs(4-8) + abs(3-9) = 10
|
||||
# Total distance: 5 + 6 + 4 + 2 + 3 + 10 = 30
|
||||
|
||||
# Because the total distance to all coordinates (30) is less than 32, the
|
||||
# location is within the region.
|
||||
|
||||
# This region, which also includes coordinates D and E, has a total size of 16.
|
||||
|
||||
# Your actual region will need to be much larger than this example, though,
|
||||
# instead including all locations with a total distance of less than 10000.
|
||||
|
||||
# What is the size of the region containing all locations which have a total
|
||||
# distance to all given coordinates of less than 10000?
|
||||
|
||||
|
||||
def part_2():
|
||||
coordinates = copy(puzzle)
|
||||
|
||||
# Max coordinates
|
||||
max_x = max(coordinates, key=lambda e: (e[0], e[0]))[0]
|
||||
max_y = max(coordinates, key=lambda e: (e[1], e[1]))[1]
|
||||
|
||||
size = 0
|
||||
for x in range(max_x + 1):
|
||||
for y in range(max_y + 1):
|
||||
total_dist = 0
|
||||
for coordinate in coordinates:
|
||||
distance = manhattan_dist(coordinate, x, y)
|
||||
total_dist += distance
|
||||
if total_dist < 10_000:
|
||||
size += 1
|
||||
|
||||
print(f"The size of the region is {size}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
part_1()
|
||||
part_2()
|
Loading…
Reference in New Issue
Block a user