Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions Alphabetizer/Models/乘法口诀.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ""
Expand Down Expand Up @@ -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 准备九字卡() {
Expand Down Expand Up @@ -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 数目字.对应字[积]!
Expand Down
15 changes: 15 additions & 0 deletions Alphabetizer/Models/数目字.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct 数目字 {
"七": 7,
"八": 8,
"九": 9,
"十": 10,
]

static let 对应字: [Int: String] = [
Expand All @@ -33,6 +34,7 @@ struct 数目字 {
7: "七",
8: "八",
9: "九",
10: "十",
]
}

Expand Down Expand Up @@ -61,4 +63,17 @@ extension 数目字 {
"十",
"五",
])

static let 十以内 = 数目字(words: [
"一",
"二",
"三",
"四",
"五",
"六",
"七",
"八",
"九",
"十",
])
}
4 changes: 4 additions & 0 deletions Alphabetizer/Views/全视界.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ struct 全视界: View {
.tabItem {
Label("", systemImage: "4.circle")
}
视界5()
.tabItem {
Label("", systemImage: "5.circle")
}
}
}
}
14 changes: 10 additions & 4 deletions Alphabetizer/Views/字卡视界.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,28 @@ import SwiftUI

struct 字卡视界: View {
var tile: 字卡
var 边长 = 字卡.边长
var 字号 = 40.0

private let borderWidth = 5.0

var body: some 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)
Expand Down
33 changes: 33 additions & 0 deletions Alphabetizer/Views/方阵视界.swift
Original file line number Diff line number Diff line change
@@ -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..<min(index + 5, alphabetizer.方阵字卡.count)])
}
}

var body: some View {
VStack(spacing: 8) {
ForEach(rows.indices, id: \.self) { rowIndex in
HStack(spacing: 8) {
ForEach(rows[rowIndex]) { tile in
字卡视界(tile: tile, 边长: 58, 字号: 26)
.onTapGesture {
alphabetizer.点选方阵字卡(tile)
}
}
}
}
}
}
}

#Preview {
let alphabetizer = 乘法口诀()
alphabetizer.准备方阵题()
return 方阵视界()
.environment(alphabetizer)
}
20 changes: 20 additions & 0 deletions Alphabetizer/Views/视界5.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import SwiftUI

struct 视界5: View {
@State private var 口诀 = 乘法口诀()

var body: some View {
VStack(spacing: 15) {
方阵视界()
}
.padding(.top, 60)
.environment(口诀)
.onAppear {
口诀.准备方阵题()
}
}
}

#Preview {
视界5()
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
2. 由中文数字得到中文数字的积,如看三、四得到 一十二
3. 看中文数字的积以及两个中文数字,按先小后大点击后通过,如看 一十二,四、三,需先点三,后点四
4. 看中文数字的积在九个数字中选取对应的几个,如看 一十二 选 三、四 或者 二、六;四三、六二都允许,(彩蛋)甚至三、二、二
5. 【待做】方阵找连线,在五乘五方阵中,找到任一横、竖、对角线中能够达成 甲乘乙 得到 丙 的排列,并按甲、乙、丙顺序点击(甲乙无需先小后大)。
5. 方阵找连线,在五乘五方阵中,找到任一横、竖、对角线中能够达成 甲乘乙 得到 丙 的排列,并按甲、乙、丙顺序点击(甲乙无需先小后大,也支持省略十的快速读法)。
6. 待定:俄罗斯方块?


Expand Down
Loading