import Foundation struct Coordinate: Hashable, Sendable { let r: Int let c: Int var ref: String { var c = c var label = "" repeat { label = String(UnicodeScalar(65 + c % 26)!) + label c = c / 26 - 1 } while c >= 0 return label + String(r + 1) } static func parse(_ text: String) -> Coordinate? { let text = text.trimmingCharacters(in: .whitespacesAndNewlines).uppercased() let letters = text.prefix { $0.isASCII && $0.isLetter } guard !letters.isEmpty, letters.count <= 3, let row = Int(text.dropFirst(letters.count)), row > 0, row <= 5000 else { return nil } let col = letters.utf8.reduce(0) { $0 * 26 + Int($1) - 64 } guard col <= 2000 else { return nil } return Coordinate(r: row - 1, c: col - 1) } } struct CellRange: Equatable, Sendable { let start: Coordinate let end: Coordinate init(_ a: Coordinate, _ b: Coordinate) { start = Coordinate(r: min(a.r, b.r), c: min(a.c, b.c)) end = Coordinate(r: max(a.r, b.r), c: max(a.c, b.c)) } static func parse(_ text: String) -> CellRange? { let parts = text.split(separator: ":", omittingEmptySubsequences: false) guard (1...2).contains(parts.count), let a = Coordinate.parse(String(parts[0])), let b = Coordinate.parse(String(parts.last!)) else { return nil } return CellRange(a, b) } var coordinates: [Coordinate] { (start.r...end.r).flatMap { r in (start.c...end.c).map { Coordinate(r: r, c: $0) } } } var count: Int { (end.r - start.r + 1) * (end.c - start.c + 1) } func contains(_ p: Coordinate) -> Bool { (start.r...end.r).contains(p.r) && (start.c...end.c).contains(p.c) } }