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