Last active
December 6, 2018 16:36
-
-
Save aglee/6b69e553d3d79a9e31080daebbb84e72 to your computer and use it in GitHub Desktop.
Advent of Code 2018 day 06
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 Foundation | |
let commandURL = URL(fileURLWithPath: CommandLine.arguments[0]) | |
let inputFileURL = commandURL.deletingLastPathComponent().appendingPathComponent("input.txt") | |
let inputText = try! String(contentsOf: inputFileURL, encoding: .utf8).trimmingCharacters(in: .whitespacesAndNewlines) | |
let inputLines = inputText.split(separator: "\n") | |
// I will call the input coordinates "pins", as in pins on a map (is clearer to my mind than "coordinates"). | |
// I will call the index of a pin in allPins its "pinID". | |
// Load the input coordinates into an array of "pins", and keep track of their bounding box. | |
var allPins = Array<(Int, Int)>() | |
var minPinX = 500 | |
var maxPinX = -1 | |
var minPinY = 500 | |
var maxPinY = -1 | |
for line in inputLines { | |
let line = line as NSString | |
let xy = line.components(separatedBy: ", ").map { Int($0)! } | |
let (x, y) = (xy[0], xy[1]) | |
minPinX = min(x, minPinX) | |
maxPinX = max(x, maxPinX) | |
minPinY = min(y, minPinY) | |
maxPinY = max(y, maxPinY) | |
allPins.append((x, y)) | |
} | |
// Initialize the grid with what I will call "level 0", i.e., the set of points | |
// whose distance from the nearest pin is 0, which is just the pins themselves. | |
class PointInfo { | |
var nearestPinID: Int? | |
let distance: Int | |
init(nearestPinID: Int?, distance: Int) { | |
self.nearestPinID = nearestPinID | |
self.distance = distance | |
} | |
} | |
var grid: [[PointInfo?]] = Array(repeating: Array(repeating: nil, count: maxPinX+1), count: maxPinY+1) | |
for (i, (x, y)) in allPins.enumerated() { | |
grid[y][x] = PointInfo(nearestPinID: i, distance: 0) | |
} | |
// Keep finding the next "level", i.e. points whose distance from the nearest pin is 1, 2, 3, ..., | |
// until all points in the grid are filled in, i.e. there are no more neighbors to consider. | |
func isInBounds(_ x: Int, _ y: Int) -> Bool { | |
return y >= 0 && y < grid.count && x >= 0 && x < grid[y].count | |
} | |
var currentLevel = allPins | |
var newDistance = 1 | |
while currentLevel.count > 0 { | |
var nextLevel = Array<(Int, Int)>() | |
for (x, y) in currentLevel { | |
guard let pointInfo = grid[y][x] else { | |
fatalError("Expected non-nil PointInfo at \((x, y))") | |
} | |
for (dx, dy) in [(0, 1), (1, 0), (0, -1), (-1, 0)] { | |
let (nx, ny) = (x + dx, y + dy) | |
if isInBounds(nx, ny) { | |
if let neighborInfo = grid[ny][nx] { | |
if neighborInfo.distance == newDistance && neighborInfo.nearestPinID != pointInfo.nearestPinID { | |
// A point that is equidistant from more than one pin has no nearestPinID. | |
neighborInfo.nearestPinID = nil | |
} | |
} else { | |
grid[ny][nx] = PointInfo(nearestPinID: pointInfo.nearestPinID, distance: newDistance) | |
nextLevel.append((nx, ny)) | |
} | |
} | |
} | |
} | |
newDistance += 1 | |
currentLevel = nextLevel | |
} | |
// See which pinID appears the most times as a `nearestPinID`. | |
// Iterate over points that are strictly inside the bounding box of all the pins. | |
// Any point on the edge of the bounding box has infinite "area", e.g. any point | |
// on the right edge of that box includes all points to the right of itself in its area. | |
var counts = Array(repeating: 0, count: allPins.count) | |
for y in minPinY+1 ... maxPinY-1 { | |
for x in minPinX+1 ... maxPinX-1 { | |
if let nearestPinID = grid[y][x]?.nearestPinID { | |
counts[nearestPinID] += 1 | |
} | |
} | |
} | |
print("max is \(counts.max()!)") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment