diff --git "a/Alphabetizer/Models/\344\271\230\346\263\225\345\217\243\350\257\200.swift" "b/Alphabetizer/Models/\344\271\230\346\263\225\345\217\243\350\257\200.swift" index 1c27d07..8e4cc28 100644 --- "a/Alphabetizer/Models/\344\271\230\346\263\225\345\217\243\350\257\200.swift" +++ "b/Alphabetizer/Models/\344\271\230\346\263\225\345\217\243\350\257\200.swift" @@ -5,9 +5,12 @@ class 乘法口诀 { private var 数字: 数目字 private var 九宫点选积 = 1 private var 九宫点选数 = 0 + private var 方阵已选字卡 = [字卡]() + private var 方阵有效线 = [[字卡]]() var 两字卡 = [字卡]() var 九字卡 = [字卡]() + var 方阵字卡 = [字卡]() var 积值: Int = 0 var 积输出: String = "" var 积中文输出: String = "" @@ -80,6 +83,50 @@ class 乘法口诀 { } } + func 准备方阵题() { + let 可用字 = 数目字.十以内.words + 方阵字卡 = (0..<25).map { _ in + 字卡(word: 可用字.randomElement()!) + } + + let 口诀序列 = 方阵口诀序列().randomElement()! + let 放置方式 = 方阵可放位置(长度: 口诀序列.count).randomElement()! + + for (offset, 字) in 口诀序列.enumerated() { + let 行 = 放置方式.行 + 放置方式.行向 * offset + let 列 = 放置方式.列 + 放置方式.列向 * offset + let 字卡 = 方阵字卡[方阵索引(行: 行, 列: 列)] + 字卡.字 = 字 + 字卡.数 = 数目字.对应数[字] ?? 0 + } + + 更新方阵有效线() + 重置方阵点选() + } + + func 点选方阵字卡(_ 所点字卡: 字卡) { + if 所点字卡.flipped { + return + } + + 方阵已选字卡.append(所点字卡) + if 方阵已选为有效前缀 { + 所点字卡.flipped = true + if 方阵已选为完整答案 { + 准备方阵题() + } + return + } + + 重置方阵点选() + 方阵已选字卡 = [所点字卡] + if 方阵已选为有效前缀 { + 所点字卡.flipped = true + } else { + 方阵已选字卡.removeAll() + } + } + // MARK: private implementation private func 准备九字卡() { @@ -114,6 +161,118 @@ class 乘法口诀 { } } + private var 方阵已选为有效前缀: Bool { + 方阵有效线.contains { 线 in + guard 方阵已选字卡.count <= 线.count else { + return false + } + return Array(线.prefix(方阵已选字卡.count)) == 方阵已选字卡 + } + } + + private var 方阵已选为完整答案: Bool { + 方阵有效线.contains { 线 in + 线 == 方阵已选字卡 + } + } + + private func 重置方阵点选() { + 方阵已选字卡.removeAll() + for tile in 方阵字卡 { + tile.flipped = false + } + } + + private func 更新方阵有效线() { + let 所有口诀序列 = 方阵口诀序列() + var 新有效线 = [[字卡]]() + + for 序列 in 所有口诀序列 { + for 放置方式 in 方阵可放位置(长度: 序列.count) { + let 线 = (0..<序列.count).map { offset in + let 行 = 放置方式.行 + 放置方式.行向 * offset + let 列 = 放置方式.列 + 放置方式.列向 * offset + return 方阵字卡[方阵索引(行: 行, 列: 列)] + } + if zip(线, 序列).allSatisfy({ $0.字 == $1 }) { + 新有效线.append(线) + } + } + } + + 方阵有效线 = 新有效线.shuffled() + } + + private func 方阵口诀序列() -> [[String]] { + var 序列 = [[String]]() + for 甲 in 1...9 { + for 乙 in 1...9 { + let 积 = 甲 * 乙 + var 标准序列 = [数目字.对应字[甲]!, 数目字.对应字[乙]!] + 标准序列.append(contentsOf: 方阵积字(积)) + 序列.append(标准序列) + + if let 省十序列 = 方阵省十积字(积) { + 序列.append([数目字.对应字[甲]!, 数目字.对应字[乙]!] + 省十序列) + } + } + } + return 序列 + } + + private func 方阵积字(_ 积: Int) -> [String] { + if 积 <= 10 { + return [数目字.对应字[积]!] + } + + let 十位值 = 积 / 10 + let 个位值 = 积 % 10 + var 中文 = [String]() + if 十位值 > 1 { + 中文.append(数目字.对应字[十位值]!) + } + 中文.append("十") + if 个位值 > 0 { + 中文.append(数目字.对应字[个位值]!) + } + return 中文 + } + + private func 方阵省十积字(_ 积: Int) -> [String]? { + let 十位值 = 积 / 10 + let 个位值 = 积 % 10 + guard 十位值 >= 2 && 个位值 > 0 else { + return nil + } + return [数目字.对应字[十位值]!, 数目字.对应字[个位值]!] + } + + private func 方阵可放位置(长度: Int) -> [(行: Int, 列: Int, 行向: Int, 列向: Int)] { + let 方向 = [ + (-1, -1), (-1, 0), (-1, 1), + (0, -1), (0, 1), + (1, -1), (1, 0), (1, 1), + ] + + var 位置 = [(行: Int, 列: Int, 行向: Int, 列向: Int)]() + for 行 in 0..<5 { + for 列 in 0..<5 { + for (行向, 列向) in 方向 { + let 末行 = 行 + 行向 * (长度 - 1) + let 末列 = 列 + 列向 * (长度 - 1) + if (0..<5).contains(末行), (0..<5).contains(末列) { + 位置.append((行, 列, 行向, 列向)) + } + } + } + } + return 位置 + } + + private func 方阵索引(行: Int, 列: Int) -> Int { + 行 * 5 + 列 + } + private func 积的中文(_ 积: Int) -> String { if 积 < 10 { return 数目字.对应字[积]! diff --git "a/Alphabetizer/Models/\346\225\260\347\233\256\345\255\227.swift" "b/Alphabetizer/Models/\346\225\260\347\233\256\345\255\227.swift" index 4d3ecbc..b34df29 100644 --- "a/Alphabetizer/Models/\346\225\260\347\233\256\345\255\227.swift" +++ "b/Alphabetizer/Models/\346\225\260\347\233\256\345\255\227.swift" @@ -21,6 +21,7 @@ struct 数目字 { "七": 7, "八": 8, "九": 9, + "十": 10, ] static let 对应字: [Int: String] = [ @@ -33,6 +34,7 @@ struct 数目字 { 7: "七", 8: "八", 9: "九", + 10: "十", ] } @@ -61,4 +63,17 @@ extension 数目字 { "十", "五", ]) + + static let 十以内 = 数目字(words: [ + "一", + "二", + "三", + "四", + "五", + "六", + "七", + "八", + "九", + "十", + ]) } diff --git "a/Alphabetizer/Views/\345\205\250\350\247\206\347\225\214.swift" "b/Alphabetizer/Views/\345\205\250\350\247\206\347\225\214.swift" index da84a9d..54b79cb 100644 --- "a/Alphabetizer/Views/\345\205\250\350\247\206\347\225\214.swift" +++ "b/Alphabetizer/Views/\345\205\250\350\247\206\347\225\214.swift" @@ -25,6 +25,10 @@ struct 全视界: View { .tabItem { Label("", systemImage: "4.circle") } + 视界5() + .tabItem { + Label("", systemImage: "5.circle") + } } } } diff --git "a/Alphabetizer/Views/\345\255\227\345\215\241\350\247\206\347\225\214.swift" "b/Alphabetizer/Views/\345\255\227\345\215\241\350\247\206\347\225\214.swift" index 52224be..8326601 100644 --- "a/Alphabetizer/Views/\345\255\227\345\215\241\350\247\206\347\225\214.swift" +++ "b/Alphabetizer/Views/\345\255\227\345\215\241\350\247\206\347\225\214.swift" @@ -2,6 +2,8 @@ import SwiftUI struct 字卡视界: View { var tile: 字卡 + var 边长 = 字卡.边长 + var 字号 = 40.0 private let borderWidth = 5.0 @@ -9,15 +11,19 @@ struct 字卡视界: View { VStack { if tile.flipped { Text(tile.字) - .font(Font.system(size: 40)) + .font(Font.system(size: 字号)) + .lineLimit(1) + .minimumScaleFactor(0.5) } else { Text(tile.字) - .font(Font.system(size: 40)) + .font(Font.system(size: 字号)) + .lineLimit(1) + .minimumScaleFactor(0.5) } } - .frame(width: 字卡.边长 - borderWidth * 2, height: 字卡.边长 - borderWidth * 2) + .frame(width: 边长 - borderWidth * 2, height: 边长 - borderWidth * 2) .overlay(RoundedRectangle(cornerRadius: 16).stroke(borderStyle(), lineWidth: borderWidth)) - .background(Color.purple.opacity(0.5)) + .background(tile.flipped ? Color.green.opacity(0.45) : Color.purple.opacity(0.5)) .clipShape(RoundedRectangle(cornerRadius: 16)) .rotation3DEffect(.degrees(tile.flipped ? 180 : 0), axis: (x: 0, y: 1, z: 0)) .animation(.default, value: tile.flipped) diff --git "a/Alphabetizer/Views/\346\226\271\351\230\265\350\247\206\347\225\214.swift" "b/Alphabetizer/Views/\346\226\271\351\230\265\350\247\206\347\225\214.swift" new file mode 100644 index 0000000..f5d8ed9 --- /dev/null +++ "b/Alphabetizer/Views/\346\226\271\351\230\265\350\247\206\347\225\214.swift" @@ -0,0 +1,33 @@ +import SwiftUI + +struct 方阵视界: View { + @Environment(乘法口诀.self) private var alphabetizer + + private var rows: [[字卡]] { + stride(from: 0, to: alphabetizer.方阵字卡.count, by: 5).map { index in + Array(alphabetizer.方阵字卡[index..