import Foundation typealias Key = String let (nA, nEmpty) = ("A", "") let (n7, n8, n9, n4, n5, n6, n1, n2, n3, n0) = ("7", "8", "9", "4", "5", "6", "1", "2", "3", "0") let (nL, nR, nU, nD) = ("<", ">", "^", "v") protocol Pad { static func seq(_ k1: Key, _ k2: Key) -> Set<[Key]> } struct Numpad : Pad { static let pos: [Key: (Int, Int)] = [ n7: (0, 0), n8: (0, 1), n9: (0, 2), n4: (1, 0), n5: (1, 1), n6: (1, 2), n1: (2, 0), n2: (2, 1), n3: (2, 2), n0: (3, 1), nA: (3, 2) ] static func seq(_ k1: Key, _ k2: Key) -> Set<[Key]> { let (pos1, pos2) = (pos[k1]!, pos[k2]!) let verKey = pos1.0 < pos2.0 ? nD : nU let horKey = pos1.1 < pos2.1 ? nR : nL let seqs: [[Key]] = [ // ??? Array(repeating: verKey, count: abs(pos1.0 - pos2.0)) + Array(repeating: horKey, count: abs(pos1.1 - pos2.1)), Array(repeating: horKey, count: abs(pos1.1 - pos2.1)) + Array(repeating: verKey, count: abs(pos1.0 - pos2.0)) ].filter { seq in (k1 != n1 || !seq.starts(with: [nD])) && (k1 != n4 || !seq.starts(with: [nD, nD])) && (k1 != n7 || !seq.starts(with: [nD, nD, nD])) && (k1 != n0 || !seq.starts(with: [nL])) && (k1 != nA || !seq.starts(with: [nL, nL])) } return Set(seqs) } } struct Dirpad : Pad { static let pos: [Key: (Int, Int)] = [ nU: (0, 1), nA: (0, 2), nL: (1, 0), nD: (1, 1), nR: (1, 2) ] static func seq(_ k1: Key, _ k2: Key) -> Set<[Key]> { let (pos1, pos2) = (pos[k1]!, pos[k2]!) let verKey = pos1.0 < pos2.0 ? nD : nU let horKey = pos1.1 < pos2.1 ? nR : nL let seqs: [[Key]] = [ // ??? Array(repeating: verKey, count: abs(pos1.0 - pos2.0)) + Array(repeating: horKey, count: abs(pos1.1 - pos2.1)), Array(repeating: horKey, count: abs(pos1.1 - pos2.1)) + Array(repeating: verKey, count: abs(pos1.0 - pos2.0)) ].filter { seq in (k1 != nU || !seq.starts(with: [nL])) && (k1 != nA || !seq.starts(with: [nL, nL])) && (k1 != nL || !seq.starts(with: [nU])) } return Set(seqs) } } extension Pad { static func press(_ start: Key, _ keys: ArraySlice) -> [[Key]] { if keys.count == 0 { return [[]] } return seq(start, keys[keys.startIndex]).flatMap { firstSeq in press(keys[keys.startIndex], keys.dropFirst()).map { restSeq in firstSeq + [nA] + restSeq } } } } func readInput(_ filePath: String) throws -> [[Key]] { return try String(contentsOfFile: filePath, encoding: .ascii) .split(separator: "\n").map { Array($0).map(String.init) } } let answer = try readInput(CommandLine.arguments[1]).map { passwd in Numpad.press(nA, passwd[...]).flatMap { dirSeq1 in Dirpad.press(nA, dirSeq1[...]).flatMap { dirSeq2 in Dirpad.press(nA, dirSeq2[...]) } }.map { $0.count }.min()! * Int(passwd.joined().dropLast())! }.reduce(0, +) print(answer) //}.forEach { line in // print() // line.map { $0.joined() }.forEach { print("\($0.count): \($0)") } //} /* Numpad.press(nA, [n0, n2, n9, nA]) .map { $0.joined() }.forEach { print("\($0.count): \($0)") } print() Dirpad.press(nA, "AvvvA".map(String.init)[...]) .map { $0.joined() }.forEach { print("\($0.count): \($0)") } print() */