114 lines
3.3 KiB
Swift
114 lines
3.3 KiB
Swift
|
import Foundation
|
||
|
|
||
|
let input = """
|
||
|
L5, R1, R4, L5, L4, R3, R1, L1, R4, R5, L1, L3, R4, L2, L4, R2, L4, L1, R3, R1, R1, L1, R1, L5, R5, R2, L5, R2, R1, L2, L4, L4, R191, R2, R5, R1, L1, L2, R5, L2, L3, R4, L1, L1, R1, R50, L1, R1, R76, R5, R4, R2, L5, L3, L5, R2, R1, L1, R2, L3, R4, R2, L1, L1, R4, L1, L1, R185, R1, L5, L4, L5, L3, R2, R3, R1, L5, R1, L3, L2, L2, R5, L1, L1, L3, R1, R4, L2, L1, L1, L3, L4, R5, L2, R3, R5, R1, L4, R5, L3, R3, R3, R1, R1, R5, R2, L2, R5, L5, L4, R4, R3, R5, R1, L3, R1, L2, L2, R3, R4, L1, R4, L1, R4, R3, L1, L4, L1, L5, L2, R2, L1, R1, L5, L3, R4, L1, R5, L5, L5, L1, L3, R1, R5, L2, L4, L5, L1, L1, L2, R5, R5, L4, R3, L2, L1, L3, L4, L5, L5, L2, R4, R3, L5, R4, R2, R1, L5
|
||
|
"""
|
||
|
|
||
|
enum Direction {
|
||
|
case north
|
||
|
case east
|
||
|
case south
|
||
|
case west
|
||
|
|
||
|
func turnLeft() -> Direction {
|
||
|
switch self {
|
||
|
case .north: return .west
|
||
|
case .east: return .north
|
||
|
case .south: return .east
|
||
|
case .west: return .south
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func turnRight() -> Direction {
|
||
|
switch self {
|
||
|
case .north: return .east
|
||
|
case .east: return .south
|
||
|
case .south: return .west
|
||
|
case .west: return .north
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func move(units: Int) -> (north: Int, east: Int) {
|
||
|
switch self {
|
||
|
case .north: return (units, 0)
|
||
|
case .east: return (0, units)
|
||
|
case .south: return (-units, 0)
|
||
|
case .west: return (0, -units)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct Position: Hashable {
|
||
|
var heading: Direction = .north
|
||
|
var north: Int = 0
|
||
|
var east: Int = 0
|
||
|
|
||
|
mutating func move(left: Bool, units: Int) -> [Position] {
|
||
|
heading = left ? heading.turnLeft() : heading.turnRight()
|
||
|
let (north, east) = heading.move(units: 1)
|
||
|
|
||
|
var result: [Position] = []
|
||
|
for _ in 0..<units {
|
||
|
self.north += north
|
||
|
self.east += east
|
||
|
result.append(self)
|
||
|
}
|
||
|
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
static func == (lhs: Position, rhs: Position) -> Bool {
|
||
|
lhs.north == rhs.north && lhs.east == rhs.east
|
||
|
}
|
||
|
|
||
|
func hash(into hasher: inout Hasher) {
|
||
|
hasher.combine(north)
|
||
|
hasher.combine(east)
|
||
|
}
|
||
|
|
||
|
var distance: Int {
|
||
|
abs(north) + abs(east)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
let scanner = Scanner(string: input)
|
||
|
|
||
|
extension Scanner {
|
||
|
func scanDirection() -> Bool {
|
||
|
if scanString("L") != nil { return true }
|
||
|
if scanString("R") != nil { return false }
|
||
|
fatalError("Invalid direction")
|
||
|
}
|
||
|
|
||
|
func scanMove() -> (Bool, Int) {
|
||
|
let direction = scanDirection()
|
||
|
guard let units = scanInt() else {
|
||
|
fatalError("Invalid distance")
|
||
|
}
|
||
|
|
||
|
guard isAtEnd || scanString(",") != nil else {
|
||
|
fatalError("Missing ,")
|
||
|
}
|
||
|
|
||
|
return (direction, units)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var position = Position()
|
||
|
var visited: Set<Position> = [position]
|
||
|
var foundPart2 = false
|
||
|
while !scanner.isAtEnd {
|
||
|
let (direction, units) = scanner.scanMove()
|
||
|
let path = position.move(left: direction, units: units)
|
||
|
|
||
|
for position in path {
|
||
|
if !foundPart2 && !visited.insert(position).inserted {
|
||
|
print("Part 2: Visited again: \(position.distance): \(position.north)n, \(position.east)e")
|
||
|
foundPart2 = true
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
print("Part 1:", position.distance)
|