This commit is contained in:
2024-12-21 23:42:57 -08:00
parent 9a19ca9251
commit 4c2c6244db

View File

@@ -15,7 +15,7 @@ struct KeyPair : Hashable {
let b: Key let b: Key
} }
struct Numpad : Pad { struct Numpad {
static let pos: [Key: (Int, Int)] = [ static let pos: [Key: (Int, Int)] = [
n7: (0, 0), n8: (0, 1), n9: (0, 2), n7: (0, 0), n8: (0, 1), n9: (0, 2),
n4: (1, 0), n5: (1, 1), n6: (1, 2), n4: (1, 0), n5: (1, 1), n6: (1, 2),
@@ -48,94 +48,70 @@ struct Numpad : Pad {
return cache[cacheKey]! return cache[cacheKey]!
} }
static func press(_ start: Key, _ keys: ArraySlice<Key>) -> [[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
}
}
}
} }
struct Dirpad : Pad { struct Dirpad {
static let pos: [Key: (Int, Int)] = [ static let pos: [Key: (Int, Int)] = [
nU: (0, 1), nA: (0, 2), nU: (0, 1), nA: (0, 2),
nL: (1, 0), nD: (1, 1), nR: (1, 2) nL: (1, 0), nD: (1, 1), nR: (1, 2)
] ]
static var cache: [KeyPair: Set<[Key]>] = [ static var cache: [KeyPair: [Key]] = [
// <<0 <v- <>- <^. <A. // <<0 <v- <>- <^. <A.
// v<- vv0 v>- v^- vA // v<- vv0 v>- v^- vA
// ><- >v- >>0 >^ >A- // ><- >v- >>0 >^ >A-
// ^<. ^v- ^> ^^0 ^A- // ^<. ^v- ^> ^^0 ^A-
// A<. Av A>- A^- AA0 // A<. Av A>- A^- AA0
// Noops // Noops
KeyPair(a: nL, b: nL): [[]], KeyPair(a: nL, b: nL): [],
KeyPair(a: nR, b: nR): [[]], KeyPair(a: nR, b: nR): [],
KeyPair(a: nU, b: nU): [[]], KeyPair(a: nU, b: nU): [],
KeyPair(a: nD, b: nD): [[]], KeyPair(a: nD, b: nD): [],
KeyPair(a: nA, b: nA): [[]], KeyPair(a: nA, b: nA): [],
// Only solutions due to gap // Only solutions due to gap
KeyPair(a: nL, b: nU): [[nR, nU]], KeyPair(a: nL, b: nU): [nR, nU],
KeyPair(a: nL, b: nA): [[nR, nR, nU]], KeyPair(a: nL, b: nA): [nR, nR, nU],
KeyPair(a: nU, b: nL): [[nD, nL]], KeyPair(a: nU, b: nL): [nD, nL],
KeyPair(a: nA, b: nL): [[nD, nL, nL]], KeyPair(a: nA, b: nL): [nD, nL, nL],
// Only solutions // Only solutions
KeyPair(a: nL, b: nR): [[nR, nR]], KeyPair(a: nL, b: nR): [nR, nR],
KeyPair(a: nR, b: nL): [[nL, nL]], KeyPair(a: nR, b: nL): [nL, nL],
KeyPair(a: nL, b: nD): [[nR]], KeyPair(a: nL, b: nD): [nR],
KeyPair(a: nD, b: nL): [[nL]], KeyPair(a: nD, b: nL): [nL],
KeyPair(a: nU, b: nA): [[nR]], KeyPair(a: nU, b: nA): [nR],
KeyPair(a: nA, b: nU): [[nL]], KeyPair(a: nA, b: nU): [nL],
KeyPair(a: nD, b: nR): [[nR]], KeyPair(a: nD, b: nR): [nR],
KeyPair(a: nR, b: nD): [[nL]], KeyPair(a: nR, b: nD): [nL],
KeyPair(a: nA, b: nR): [[nD]], KeyPair(a: nA, b: nR): [nD],
KeyPair(a: nR, b: nA): [[nU]], KeyPair(a: nR, b: nA): [nU],
KeyPair(a: nU, b: nD): [[nD]], KeyPair(a: nU, b: nD): [nD],
KeyPair(a: nD, b: nU): [[nU]], KeyPair(a: nD, b: nU): [nU],
// Known short ones. TODO: proper DP this part instead of by hand // Known short ones. TODO: proper DP this part instead of by hand
KeyPair(a: nA, b: nD): [[nL, nD]], KeyPair(a: nA, b: nD): [nL, nD],
KeyPair(a: nD, b: nA): [[nU, nR]], KeyPair(a: nD, b: nA): [nU, nR],
KeyPair(a: nR, b: nU): [[nL, nU]], KeyPair(a: nR, b: nU): [nL, nU],
KeyPair(a: nU, b: nR): [[nD, nR]] KeyPair(a: nU, b: nR): [nD, nR]
] ]
static func seq(_ k1: Key, _ k2: Key) -> Set<[Key]> { static func seq(_ k1: Key, _ k2: Key) -> [Key] {
let cacheKey = KeyPair(a: k1, b: k2) return cache[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 { static func press(_ start: Key, _ keys: ArraySlice<Key>) -> [Key] {
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 { if keys.count == 0 {
return [[]] return []
} }
if let cached = pressCache[CacheKey(a: start, b: keys)] { return seq(start, keys[keys.startIndex]) + [nA] +
return cached press(keys[keys.startIndex], keys.dropFirst())
}
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)]!
} }
} }
@@ -143,57 +119,60 @@ func readInput(_ filePath: String) throws -> [[Key]] {
return try String(contentsOfFile: filePath, encoding: .ascii) return try String(contentsOfFile: filePath, encoding: .ascii)
.split(separator: "\n").map { Array($0).map(String.init) } .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: "|")) }
*/
extension Array {
func combos(l: Int) -> [[Element]] {
guard count > 0 else { return [[]] }
if l == 0 { return [[]] }
return flatMap { e in
combos(l: l - 1).map { $0 + [e] }
}
}
func combos(maxl: Int) -> [[Element]] {
return (0...maxl).flatMap { combos(l: $0) }
}
}
//let answer = try readInput(CommandLine.arguments[1]).map { passwd in struct LKs : Hashable {
// Numpad.press(nA, passwd[...]).flatMap { dirSeq1 in let l: Int
let _ = [["v", "A"]].map { passwd in let ks: [Key]
Dirpad.press(nA, passwd[...]).forEach { dirSeq1 in }
Dirpad.press(nA, dirSeq1[...]).forEach { dirSeq2 in
Dirpad.press(nA, dirSeq2[...]).forEach { dirSeq3 in // Returns a map of a sequence of pressed starting at A and ending at A
Dirpad.press(nA, dirSeq3[...]).forEach { dirSeq4 in // to how many key presses total for that
Dirpad.press(nA, dirSeq4[...]).forEach { dirSeq5 in func bestLevel1() -> [LKs: Int] {
//Dirpad.press(nA, dirSeq4[...]).forEach { dirSeq6 in var res: [LKs: Int] = [:]
let out: String = ( [nL, nR, nU, nD].combos(maxl: 3).forEach { seq in
"\(passwd.joined()) " + res[LKs(l: 1, ks: seq)] = Dirpad.press(nA, seq + [nA]).count
"\(dirSeq1.joined()) " +
"\(dirSeq2.joined()) " +
"\(dirSeq3.joined()) " +
"\(dirSeq4.joined()) " +
"\(dirSeq5.count) " +
// "\(dirSeq6.count) " +
""
).replacingOccurrences(of: "A", with: "|")
print("\(dirSeq5.count)" + out)
//}
}
}
}
}
} }
return res
}
func best(maxLevel: Int) -> [LKs: Int] {
var res = bestLevel1()
if maxLevel == 1 { return res }
(2...maxLevel).forEach { level in
[nL, nR, nU, nD].combos(maxl: 3).forEach { seq in
res[LKs(l: level, ks: Array(seq))] = Dirpad.press(nA, seq + [nA])
.split(separator: "A", omittingEmptySubsequences: false).dropLast()
.map { res[LKs(l: level-1, ks: Array($0))]! }.reduce(0, +)
}
} }
return res
}
let levels = Int(CommandLine.arguments[2])! - 1
let bests = best(maxLevel: levels)
var answer = 0 var answer = 0
for passwd in try readInput(CommandLine.arguments[1]) { for passwd in try readInput(CommandLine.arguments[1]) {
var seq = Numpad.press(nA, passwd[...]) let n = Numpad.press(nA, passwd[...])
seq.map { $0.joined() }.forEach { print("\($0.count): \($0)") } .map { Dirpad.press(nA, $0[...]) }.map { ks in
print() return ks
for _ in 0..<25 { .split(separator: "A", omittingEmptySubsequences: false).dropLast()
let tmpSeq = seq.flatMap { seq in Dirpad.press(nA, seq[...]) } .map { bests[LKs(l: levels, ks: Array($0))]! }
let minLen = seq.map { $0.count }.min()! .reduce(0, +)
seq = tmpSeq.filter { $0.count > minLen } }.min()!
//seq.map { $0.joined() }.forEach { print("\($0.count): \($0)") } answer += n * Int(passwd.joined().dropLast())!
//print()
}
let r = seq.map { $0.count }.min()! * Int(passwd.joined().dropLast())!
//print("\(passwd.joined()): \(r)")
answer += r
} }
print(answer) print(answer)