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.. 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] 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)