Skip to content

Instantly share code, notes, and snippets.

@aglee
Last active December 6, 2018 16:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aglee/6b69e553d3d79a9e31080daebbb84e72 to your computer and use it in GitHub Desktop.
Save aglee/6b69e553d3d79a9e31080daebbb84e72 to your computer and use it in GitHub Desktop.
Advent of Code 2018 day 06
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