Compare commits

...

2 Commits

Author SHA1 Message Date
78c98449ec Solution to problem 6 in Python 2023-08-27 16:19:21 +02:00
b8b0f026f1 Input file for problem 6 2023-08-27 16:18:49 +02:00
2 changed files with 246 additions and 0 deletions

196
src/Year_2018/P6.py Normal file
View 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()

View File

@@ -0,0 +1,50 @@
300, 90
300, 60
176, 327
108, 204
297, 303
101, 236
70, 102
336, 153
260, 265
228, 221
119, 267
310, 302
291, 164
190, 202
298, 228
292, 262
53, 251
176, 64
170, 160
71, 42
314, 51
71, 88
319, 150
192, 322
270, 88
165, 203
262, 340
301, 327
135, 324
97, 250
161, 231
305, 344
295, 213
320, 219
172, 269
151, 150
215, 128
167, 102
158, 138
307, 353
358, 335
163, 329
234, 147
58, 298
228, 50
151, 334
108, 176
335, 235
296, 263
80, 233