CellMarkCodec.swift (2668B)
1 import Foundation 2 3 /// Single source of truth for the `(markKind, checkedRight, checkedWrong)` 4 /// triple that the Moves wire format, `CellEntity`, and `JournalEntity` all use 5 /// to persist a `CellMark`. The pair of booleans encodes an optional 6 /// `CheckResult`: (false, false) = nil, (true, false) = .right, 7 /// (false, true) = .wrong. `markKind` is 0 none / 1 pen / 2 pencil / 3 revealed. 8 enum CellMarkCodec { 9 static func encode(_ mark: CellMark) -> (kind: Int16, checkedRight: Bool, checkedWrong: Bool) { 10 switch mark { 11 case .none: 12 return (0, false, false) 13 case .pen(let check): 14 return (1, check == .right, check == .wrong) 15 case .pencil(let check): 16 return (2, check == .right, check == .wrong) 17 case .revealed: 18 return (3, false, false) 19 } 20 } 21 22 /// Inverse of `encode`. `checkedWrong` takes precedence if both somehow 23 /// ended up true (shouldn't happen — the invariant is enforced where marks 24 /// are constructed in `Game`, not here). 25 static func decode(kind: Int16, checkedRight: Bool, checkedWrong: Bool) -> CellMark { 26 let check: CheckResult? 27 if checkedWrong { 28 check = .wrong 29 } else if checkedRight { 30 check = .right 31 } else { 32 check = nil 33 } 34 switch kind { 35 case 1: return .pen(checked: check) 36 case 2: return .pencil(checked: check) 37 case 3: return .revealed 38 default: return .none 39 } 40 } 41 42 // MARK: - Single-value encoding 43 44 /// Losslessly maps the eight legal `CellMark` states to one `Int16`. Used 45 /// by `JournalEntity`, which models the whole mark as a single field rather 46 /// than the `markKind` + two-bool flattening the synced Moves format uses. 47 static func code(_ mark: CellMark) -> Int16 { 48 switch mark { 49 case .none: return 0 50 case .pen(nil): return 1 51 case .pen(.right): return 2 52 case .pen(.wrong): return 3 53 case .pencil(nil): return 4 54 case .pencil(.right): return 5 55 case .pencil(.wrong): return 6 56 case .revealed: return 7 57 } 58 } 59 60 /// Inverse of `code(_:)`. Unknown codes decode to `.none`. 61 static func mark(code: Int16) -> CellMark { 62 switch code { 63 case 1: return .pen(checked: nil) 64 case 2: return .pen(checked: .right) 65 case 3: return .pen(checked: .wrong) 66 case 4: return .pencil(checked: nil) 67 case 5: return .pencil(checked: .right) 68 case 6: return .pencil(checked: .wrong) 69 case 7: return .revealed 70 default: return .none 71 } 72 } 73 }