parent
f5c7fe9189
commit
36f95e6f49
@ -0,0 +1,301 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 6: Chronal Coordinates"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct GridPoint: Equatable, Comparable {
|
||||
var X = 0
|
||||
var Y = 0
|
||||
|
||||
static func == (lhs: GridPoint, rhs: GridPoint) -> Bool {
|
||||
return (lhs.X == rhs.X) && (lhs.Y == rhs.Y)
|
||||
}
|
||||
|
||||
static func < (lhs: GridPoint, rhs: GridPoint) -> Bool {
|
||||
return (lhs.X + lhs.Y) < (rhs.X + rhs.Y)
|
||||
}
|
||||
}
|
||||
|
||||
class Coordinates {
|
||||
var points: [GridPoint] = []
|
||||
var dimensions: GridPoint
|
||||
|
||||
init(withString str: String) {
|
||||
var maxX = 0
|
||||
var maxY = 0
|
||||
dimensions = GridPoint(X: 0, Y: 0)
|
||||
let coordStrArray = str.components(separatedBy: "\n")
|
||||
for elem in coordStrArray {
|
||||
let coord = elem.components(separatedBy: ", ")
|
||||
guard coord.count > 1 else { return }
|
||||
guard let x = Int(coord[0]), let y = Int(coord[1]) else { return }
|
||||
points.append(GridPoint(X: x, Y: y))
|
||||
maxX = max(maxX, x)
|
||||
maxY = max(maxY, y)
|
||||
}
|
||||
dimensions = GridPoint(X: maxX+1, Y: maxY)
|
||||
}
|
||||
|
||||
func distance(from: GridPoint, to: GridPoint) -> Int {
|
||||
let retVal = abs(from.X - to.X) + abs(from.Y - to.Y)
|
||||
return retVal
|
||||
}
|
||||
|
||||
// Given any gridpoint, find the LocPoint with the min distance to it (returned as Int (index))
|
||||
func findLocWithMinDistance(toPoint measurePt: GridPoint) -> (dist: Int, index: Int) {
|
||||
var minDist = dimensions.X + dimensions.Y // max distance
|
||||
var minIndex = 0
|
||||
var dist: [Int: Int] = [:]
|
||||
for locIndex in 0..<points.count {
|
||||
dist[locIndex] = distance(from: points[locIndex], to: measurePt)
|
||||
if dist[locIndex] ?? -1 < minDist {
|
||||
minDist = dist[locIndex] ?? -1
|
||||
minIndex = locIndex
|
||||
}
|
||||
}
|
||||
let duplicate = dist.filter { $0.value == minDist }.count > 1
|
||||
return (dist: duplicate ? -1 : minDist, index: minIndex)
|
||||
}
|
||||
|
||||
// Given any gridpoint, find the LocPoint with the min distance to it (returned as Int (index))
|
||||
func findSumOfAllDistances(toPoint measurePt: GridPoint) -> Int {
|
||||
var sum = 0
|
||||
for locIndex in 0..<points.count {
|
||||
sum += distance(from: points[locIndex], to: measurePt)
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
// Fill out the grid
|
||||
func fillGridWithMinDistIndicies() -> [Int] {
|
||||
var retVal: [Int] = []
|
||||
for j in 0...dimensions.Y {
|
||||
for i in 0...dimensions.X {
|
||||
let index = findLocWithMinDistance(toPoint: GridPoint(X: i, Y: j))
|
||||
if index.dist < 0 {
|
||||
retVal.append(-1) // indicate duplicate
|
||||
} else {
|
||||
retVal.append(index.index)
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
// Fill out the grid
|
||||
func fillGridWithSumLessThan(value nearestSum: Int) -> [Bool] {
|
||||
var retVal: [Bool] = []
|
||||
for j in 0...dimensions.Y {
|
||||
for i in 0...dimensions.X {
|
||||
retVal.append(findSumOfAllDistances(toPoint: GridPoint(X: i, Y: j)) < nearestSum)
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func solveForPart1(print printMap: Bool) -> Int {
|
||||
var map = fillGridWithMinDistIndicies()
|
||||
var infinite: [Int : Int] = [:]
|
||||
let maxX = dimensions.X
|
||||
let maxY = dimensions.Y
|
||||
for j in 0...dimensions.Y {
|
||||
for i in 0...dimensions.X {
|
||||
let idx = j * (dimensions.X + 1) + i
|
||||
if i == 0 || j == 0 || i == maxX || j == maxY && infinite[idx] == nil {
|
||||
infinite[map[idx]] = 1
|
||||
}
|
||||
if printMap {
|
||||
if map[idx] < 0 {
|
||||
print("..", terminator: "")
|
||||
} else {
|
||||
print(NSString(format:"%2d", map[idx]), terminator: "")
|
||||
}
|
||||
}
|
||||
}
|
||||
if printMap { print("") }
|
||||
}
|
||||
if printMap { print("infinite = \(infinite)") }
|
||||
var maxArea = 0
|
||||
for locIdx in 0..<points.count {
|
||||
if infinite[locIdx] == nil {
|
||||
let area = map.filter { $0 == locIdx }.count
|
||||
maxArea = max(maxArea, area)
|
||||
}
|
||||
}
|
||||
return maxArea
|
||||
}
|
||||
|
||||
func solveForPart2(print printMap: Bool, withValue nearestSum: Int) -> Int {
|
||||
let map = fillGridWithSumLessThan(value: nearestSum)
|
||||
for j in 0...dimensions.Y {
|
||||
for i in 0...dimensions.X {
|
||||
let idx = j * (dimensions.X + 1) + i
|
||||
if printMap {
|
||||
if map[idx] {
|
||||
print("#", terminator: "")
|
||||
} else {
|
||||
print(".", terminator: "")
|
||||
}
|
||||
}
|
||||
}
|
||||
if printMap { print("") }
|
||||
}
|
||||
return map.filter { $0 == true }.count
|
||||
}
|
||||
}
|
||||
|
||||
class Day06: AOCDay {
|
||||
lazy var tests: (() -> ()) = day06Tests
|
||||
lazy var final: (() -> ()) = day06Final
|
||||
|
||||
let testData = """
|
||||
1, 1
|
||||
1, 6
|
||||
8, 3
|
||||
3, 4
|
||||
5, 5
|
||||
8, 9
|
||||
"""
|
||||
|
||||
func printGrid() {
|
||||
let coor = Coordinates(withString: testData)
|
||||
for j in 0...coor.dimensions.Y {
|
||||
for i in 0...coor.dimensions.X {
|
||||
if let index = coor.points.firstIndex(of: GridPoint(X: i, Y: j)) {
|
||||
print(" \(index) ", terminator: "")
|
||||
} else {
|
||||
print(" . ", terminator: "")
|
||||
}
|
||||
}
|
||||
print("")
|
||||
}
|
||||
print("")
|
||||
}
|
||||
|
||||
func testCoordinatesInit() {
|
||||
let coor = Coordinates(withString: testData)
|
||||
guard coor.points.count == 6 else {
|
||||
XCTAssertEqual(test: "testCoordinatesInit count", withExpression: (false))
|
||||
return
|
||||
}
|
||||
XCTAssertEqual(test: "testCoordinatesInit A", withExpression: (coor.points[0] == GridPoint(X: 1, Y: 1)))
|
||||
XCTAssertEqual(test: "testCoordinatesInit D", withExpression: (coor.points[3] == GridPoint(X: 3, Y: 4)))
|
||||
XCTAssertEqual(test: "testCoordinatesInit F", withExpression: (coor.points[5] == GridPoint(X: 8, Y: 9)))
|
||||
}
|
||||
|
||||
func testDistanceAtoAll() {
|
||||
let coor = Coordinates(withString: testData)
|
||||
guard coor.points.count == 6 else {
|
||||
XCTAssertEqual(test: "testDistanceAtoAll count", withExpression: (false))
|
||||
return
|
||||
}
|
||||
var dist = coor.distance(from: coor.points[0], to: coor.points[1])
|
||||
XCTAssertEqual(test: "testDistanceAtoAll A to B", withExpression: (dist == 5))
|
||||
dist = coor.distance(from: coor.points[0], to: coor.points[2])
|
||||
XCTAssertEqual(test: "testDistanceAtoAll A to C", withExpression: (dist == 9))
|
||||
dist = coor.distance(from: coor.points[0], to: coor.points[3])
|
||||
XCTAssertEqual(test: "testDistanceAtoAll A to D", withExpression: (dist == 5))
|
||||
dist = coor.distance(from: coor.points[0], to: coor.points[4])
|
||||
XCTAssertEqual(test: "testDistanceAtoAll A to E", withExpression: (dist == 8))
|
||||
dist = coor.distance(from: coor.points[0], to: coor.points[5])
|
||||
XCTAssertEqual(test: "testDistanceAtoAll A to F", withExpression: (dist == 15))
|
||||
}
|
||||
|
||||
func testFindLocWithMinDistance() {
|
||||
let coor = Coordinates(withString: testData)
|
||||
var nearest = coor.findLocWithMinDistance(toPoint: GridPoint(X: 0, Y: 0))
|
||||
XCTAssertEqual(test: "testFindLocWithMinDistance (0, 0)", withExpression: (nearest.index == 0))
|
||||
nearest = coor.findLocWithMinDistance(toPoint: GridPoint(X: 6, Y: 1))
|
||||
XCTAssertEqual(test: "testFindLocWithMinDistance (6, 1)", withExpression: (nearest.index == 2))
|
||||
}
|
||||
|
||||
func testSolveForPart1() {
|
||||
let coor = Coordinates(withString: testData)
|
||||
let answer = coor.solveForPart1(print: false)
|
||||
XCTAssertEqual(test: "testSolveForPart1", withExpression: (answer == 17))
|
||||
}
|
||||
|
||||
func testFindSumOfAllDistances() {
|
||||
let coor = Coordinates(withString: testData)
|
||||
let sum = coor.findSumOfAllDistances(toPoint: GridPoint(X: 4, Y: 3))
|
||||
XCTAssertEqual(test: "testFindSumOfAllDistances (4, 3)", withExpression: (sum == 30))
|
||||
}
|
||||
|
||||
func testSolveForPart2() {
|
||||
let coor = Coordinates(withString: testData)
|
||||
let answer = coor.solveForPart2(print: false , withValue: 32)
|
||||
XCTAssertEqual(test: "testSolveForPart2", withExpression: (answer == 16))
|
||||
}
|
||||
|
||||
func day06Tests() {
|
||||
printGrid()
|
||||
testCoordinatesInit()
|
||||
testDistanceAtoAll()
|
||||
testFindLocWithMinDistance()
|
||||
testSolveForPart1()
|
||||
testFindSumOfAllDistances()
|
||||
testSolveForPart2()
|
||||
}
|
||||
|
||||
func day06Final() {
|
||||
let coor = Coordinates(withString: finalData)
|
||||
var answer = coor.solveForPart1(print: false)
|
||||
print("Answer to part 1 is: \(answer)")
|
||||
answer = coor.solveForPart2(print: false, withValue: 10000)
|
||||
print("Answer to part 2 is: \(answer)")
|
||||
}
|
||||
|
||||
let finalData = """
|
||||
342, 203
|
||||
79, 64
|
||||
268, 323
|
||||
239, 131
|
||||
246, 87
|
||||
161, 93
|
||||
306, 146
|
||||
43, 146
|
||||
57, 112
|
||||
241, 277
|
||||
304, 303
|
||||
143, 235
|
||||
253, 318
|
||||
97, 103
|
||||
200, 250
|
||||
67, 207
|
||||
345, 149
|
||||
133, 222
|
||||
232, 123
|
||||
156, 359
|
||||
80, 224
|
||||
51, 145
|
||||
138, 312
|
||||
339, 294
|
||||
297, 256
|
||||
163, 311
|
||||
241, 321
|
||||
126, 66
|
||||
145, 171
|
||||
359, 184
|
||||
241, 58
|
||||
108, 312
|
||||
117, 118
|
||||
101, 180
|
||||
58, 290
|
||||
324, 42
|
||||
141, 190
|
||||
270, 149
|
||||
209, 294
|
||||
296, 345
|
||||
68, 266
|
||||
233, 281
|
||||
305, 183
|
||||
245, 230
|
||||
161, 295
|
||||
335, 352
|
||||
93, 66
|
||||
227, 59
|
||||
264, 249
|
||||
116, 173
|
||||
"""
|
||||
}
|
||||
Loading…
Reference in New Issue