new structure for 2018, added license information
This commit is contained in:
99
2018/06/README.md
Normal file
99
2018/06/README.md
Normal file
@ -0,0 +1,99 @@
|
||||
# 2018 Day 6: Chronal Coordinates
|
||||
Copyright (c) Eric Wastl
|
||||
#### [Direct Link](https://adventofcode.com/2018/day/6)
|
||||
|
||||
## Part 1
|
||||
|
||||
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](https://en.wikipedia.org/wiki/Taxicab_geometry), determine the **area** around each coordinate by counting the number of [integer](https://en.wikipedia.org/wiki/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?
|
||||
|
||||
## Part 2
|
||||
|
||||
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](https://en.wikipedia.org/wiki/Taxicab_geometry) 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](https://en.wikipedia.org/wiki/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?**
|
110
2018/06/code.py
Normal file
110
2018/06/code.py
Normal file
@ -0,0 +1,110 @@
|
||||
""" https://adventofcode.com/2018/day/6 """
|
||||
|
||||
def readFile():
|
||||
with open(f"{__file__.rstrip('code.py')}input.txt", "r") as f:
|
||||
lines = [line[:-1].split(", ") for line in f.readlines()]
|
||||
return [Point(int(line[0]), int(line[1])) for line in lines]
|
||||
|
||||
class Point:
|
||||
n = 0
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.name = str(Point.n).zfill(3)
|
||||
Point.n += 1
|
||||
self.coords = (x, y)
|
||||
self.isInfinite = False
|
||||
|
||||
def getDistance(self, x, y):
|
||||
return abs(self.x - x) + abs(self.y - y)
|
||||
|
||||
def getMinimumOfDict(data : dict):
|
||||
minVal = None
|
||||
minID = None
|
||||
for d in data:
|
||||
if minVal is None or data[d] < minVal:
|
||||
minVal = data[d]
|
||||
minID = d
|
||||
return minVal, minID
|
||||
|
||||
def part1(vals):
|
||||
x, y = [val.x for val in vals], [val.y for val in vals]
|
||||
minx, maxx, miny, maxy = min(x), max(x), min(y), max(y)
|
||||
|
||||
field = []
|
||||
for y in range(miny, maxy + 1):
|
||||
field.append([-1 for x in range(minx, maxx + 1)])
|
||||
|
||||
for y in range(miny, maxy + 1):
|
||||
for x in range(minx, maxx + 1):
|
||||
dist = {}
|
||||
for val in vals:
|
||||
dist[val.name] = val.getDistance(x, y)
|
||||
minDist, point = getMinimumOfDict(dist)
|
||||
|
||||
if sum(value == minDist for value in dist.values()) == 1:
|
||||
field[y-miny][x-minx] = point
|
||||
|
||||
points = {}
|
||||
for y in range(miny, maxy + 1):
|
||||
for x in range(minx, maxx + 1):
|
||||
id = field[y-miny][x-minx]
|
||||
if id == -1:
|
||||
continue
|
||||
if id in points:
|
||||
points[id]["value"] += 1
|
||||
if not points[id]["border"]:
|
||||
points[id]["border"] = x == minx or x == maxx or y == miny or y == maxy
|
||||
else:
|
||||
points[id] = {
|
||||
"value": 1,
|
||||
"border": x == minx or x == maxx or y == miny or y == maxy
|
||||
}
|
||||
|
||||
result = -1
|
||||
for point in points:
|
||||
if points[point]["border"]:
|
||||
continue
|
||||
if points[point]["value"] > result:
|
||||
result = points[point]["value"]
|
||||
|
||||
return result
|
||||
|
||||
class Location:
|
||||
maxDist = 0
|
||||
def __init__(self, x, y):
|
||||
self.distance = 0
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.inRegion = True
|
||||
|
||||
def addDistance(self, point):
|
||||
self.distance += point.getDistance(self.x, self.y)
|
||||
if self.distance >= Location.maxDist:
|
||||
self.inRegion = False
|
||||
|
||||
def part2(vals, maxDist):
|
||||
x, y = [val.x for val in vals], [val.y for val in vals]
|
||||
minx, maxx, miny, maxy = min(x), max(x), min(y), max(y)
|
||||
Location.maxDist = maxDist
|
||||
|
||||
locations = []
|
||||
for j in range(miny, maxy + 1):
|
||||
for i in range(minx, maxx + 1):
|
||||
loc = Location(i, j)
|
||||
for point in vals:
|
||||
loc.addDistance(point)
|
||||
locations.append(loc)
|
||||
|
||||
count = 0
|
||||
for loc in locations:
|
||||
if loc.inRegion:
|
||||
count += 1
|
||||
return count
|
||||
|
||||
if __name__ == "__main__":
|
||||
vals, maxDist = readFile(), 10000
|
||||
#vals, maxDist = [Point(1, 1), Point(1, 6), Point(8, 3), Point(3, 4),
|
||||
# Point(5, 5), Point(8, 9)], 32
|
||||
print(f"Part 1: {part1(vals)}")
|
||||
print(f"Part 2: {part2(vals, maxDist)}")
|
50
2018/06/input.txt
Normal file
50
2018/06/input.txt
Normal file
@ -0,0 +1,50 @@
|
||||
118, 274
|
||||
102, 101
|
||||
216, 203
|
||||
208, 251
|
||||
309, 68
|
||||
330, 93
|
||||
91, 179
|
||||
298, 278
|
||||
201, 99
|
||||
280, 272
|
||||
141, 312
|
||||
324, 290
|
||||
41, 65
|
||||
305, 311
|
||||
198, 68
|
||||
231, 237
|
||||
164, 224
|
||||
103, 189
|
||||
216, 207
|
||||
164, 290
|
||||
151, 91
|
||||
166, 250
|
||||
129, 149
|
||||
47, 231
|
||||
249, 100
|
||||
262, 175
|
||||
299, 237
|
||||
62, 288
|
||||
228, 219
|
||||
224, 76
|
||||
310, 173
|
||||
80, 46
|
||||
312, 65
|
||||
183, 158
|
||||
272, 249
|
||||
57, 141
|
||||
331, 191
|
||||
163, 359
|
||||
271, 210
|
||||
142, 137
|
||||
349, 123
|
||||
55, 268
|
||||
160, 82
|
||||
180, 70
|
||||
231, 243
|
||||
133, 353
|
||||
246, 315
|
||||
164, 206
|
||||
229, 97
|
||||
268, 94
|
2
2018/06/solution.txt
Normal file
2
2018/06/solution.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Part 1: 3251
|
||||
Part 2: 47841
|
Reference in New Issue
Block a user