200 lines
6.9 KiB
Swift
200 lines
6.9 KiB
Swift
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 KeyPair : Hashable {
|
|
let a: Key
|
|
let b: 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 var cache: [KeyPair: Set<[Key]>] = [:]
|
|
|
|
static func seq(_ k1: Key, _ k2: Key) -> Set<[Key]> {
|
|
let cacheKey = KeyPair(a: k1, b: k2)
|
|
if let cached = cache[cacheKey] {
|
|
return cached
|
|
}
|
|
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]))
|
|
}
|
|
cache[cacheKey] = Set(seqs)
|
|
return cache[cacheKey]!
|
|
}
|
|
|
|
}
|
|
|
|
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 var cache: [KeyPair: Set<[Key]>] = [
|
|
// <<0 <v- <>- <^. <A.
|
|
// v<- vv0 v>- v^- vA
|
|
// ><- >v- >>0 >^ >A-
|
|
// ^<. ^v- ^> ^^0 ^A-
|
|
// A<. Av A>- A^- AA0
|
|
// Noops
|
|
KeyPair(a: nL, b: nL): [[]],
|
|
KeyPair(a: nR, b: nR): [[]],
|
|
KeyPair(a: nU, b: nU): [[]],
|
|
KeyPair(a: nD, b: nD): [[]],
|
|
KeyPair(a: nA, b: nA): [[]],
|
|
// Only solutions due to gap
|
|
KeyPair(a: nL, b: nU): [[nR, nU]],
|
|
KeyPair(a: nL, b: nA): [[nR, nR, nU]],
|
|
KeyPair(a: nU, b: nL): [[nD, nL]],
|
|
KeyPair(a: nA, b: nL): [[nD, nL, nL]],
|
|
// Only solutions
|
|
KeyPair(a: nL, b: nR): [[nR, nR]],
|
|
KeyPair(a: nR, b: nL): [[nL, nL]],
|
|
KeyPair(a: nL, b: nD): [[nR]],
|
|
KeyPair(a: nD, b: nL): [[nL]],
|
|
KeyPair(a: nU, b: nA): [[nR]],
|
|
KeyPair(a: nA, b: nU): [[nL]],
|
|
KeyPair(a: nD, b: nR): [[nR]],
|
|
KeyPair(a: nR, b: nD): [[nL]],
|
|
KeyPair(a: nA, b: nR): [[nD]],
|
|
KeyPair(a: nR, b: nA): [[nU]],
|
|
KeyPair(a: nU, b: nD): [[nD]],
|
|
KeyPair(a: nD, b: nU): [[nU]],
|
|
// Known short ones. TODO: proper DP this part instead of by hand
|
|
KeyPair(a: nA, b: nD): [[nL, nD]],
|
|
KeyPair(a: nD, b: nA): [[nU, nR]],
|
|
KeyPair(a: nR, b: nU): [[nL, nU]],
|
|
KeyPair(a: nU, b: nR): [[nD, nR]]
|
|
]
|
|
|
|
static func seq(_ k1: Key, _ k2: Key) -> Set<[Key]> {
|
|
let cacheKey = KeyPair(a: k1, b: k2)
|
|
if let cached = cache[cacheKey] {
|
|
return cached
|
|
}
|
|
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]))
|
|
}
|
|
cache[cacheKey] = Set(seqs)
|
|
return cache[cacheKey]!
|
|
}
|
|
}
|
|
|
|
struct CacheKey : Hashable {
|
|
let a: Key
|
|
let b: ArraySlice<Key>
|
|
}
|
|
|
|
var pressCache: [CacheKey: [[Key]]] = [:]
|
|
extension Pad {
|
|
static func press(_ start: Key, _ keys: ArraySlice<Key>) -> [[Key]] {
|
|
if keys.count == 0 {
|
|
return [[]]
|
|
}
|
|
if let cached = pressCache[CacheKey(a: start, b: keys)] {
|
|
return cached
|
|
}
|
|
pressCache[CacheKey(a: start, b: keys)] =
|
|
seq(start, keys[keys.startIndex]).flatMap { firstSeq in
|
|
press(keys[keys.startIndex], keys.dropFirst()).map { restSeq in
|
|
firstSeq + [nA] + restSeq
|
|
}
|
|
}
|
|
return pressCache[CacheKey(a: start, b: keys)]!
|
|
}
|
|
}
|
|
|
|
func readInput(_ filePath: String) throws -> [[Key]] {
|
|
return try String(contentsOfFile: filePath, encoding: .ascii)
|
|
.split(separator: "\n").map { Array($0).map(String.init) }
|
|
}
|
|
/*
|
|
Dirpad.press(nA, "<AAv<AA>>^A".map(String.init)[...])
|
|
.map { $0.joined() }.forEach { print("<AAv<AA>>^A: \($0.count): \($0)".replacingOccurrences(of: "A", with: "|")) }
|
|
Dirpad.press(nA, "v<<AA>^AA>A".map(String.init)[...])
|
|
.map { $0.joined() }.forEach { print("v<<AA>^AA>A: \($0.count): \($0)".replacingOccurrences(of: "A", with: "|")) }
|
|
*/
|
|
|
|
|
|
//let answer = try readInput(CommandLine.arguments[1]).map { passwd in
|
|
// Numpad.press(nA, passwd[...]).flatMap { dirSeq1 in
|
|
let _ = [["v", "A"]].map { passwd in
|
|
Dirpad.press(nA, passwd[...]).forEach { dirSeq1 in
|
|
Dirpad.press(nA, dirSeq1[...]).forEach { dirSeq2 in
|
|
Dirpad.press(nA, dirSeq2[...]).forEach { dirSeq3 in
|
|
Dirpad.press(nA, dirSeq3[...]).forEach { dirSeq4 in
|
|
Dirpad.press(nA, dirSeq4[...]).forEach { dirSeq5 in
|
|
//Dirpad.press(nA, dirSeq4[...]).forEach { dirSeq6 in
|
|
let out: String = (
|
|
"\(passwd.joined()) " +
|
|
"\(dirSeq1.joined()) " +
|
|
"\(dirSeq2.joined()) " +
|
|
"\(dirSeq3.joined()) " +
|
|
"\(dirSeq4.joined()) " +
|
|
"\(dirSeq5.count) " +
|
|
// "\(dirSeq6.count) " +
|
|
""
|
|
).replacingOccurrences(of: "A", with: "|")
|
|
print("\(dirSeq5.count)" + out)
|
|
//}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var answer = 0
|
|
for passwd in try readInput(CommandLine.arguments[1]) {
|
|
var seq = Numpad.press(nA, passwd[...])
|
|
seq.map { $0.joined() }.forEach { print("\($0.count): \($0)") }
|
|
print()
|
|
for _ in 0..<25 {
|
|
let tmpSeq = seq.flatMap { seq in Dirpad.press(nA, seq[...]) }
|
|
let minLen = seq.map { $0.count }.min()!
|
|
seq = tmpSeq.filter { $0.count > minLen }
|
|
//seq.map { $0.joined() }.forEach { print("\($0.count): \($0)") }
|
|
//print()
|
|
}
|
|
let r = seq.map { $0.count }.min()! * Int(passwd.joined().dropLast())!
|
|
//print("\(passwd.joined()): \(r)")
|
|
answer += r
|
|
}
|
|
print(answer)
|
|
|