数字分类精简词库,测验支持 0-亿 随机出题

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-07-19 23:51:11 +08:00
parent 75b967893b
commit 837810cfa8
4 changed files with 79 additions and 6 deletions
@@ -1,9 +1,10 @@
import Foundation
enum NumberWords {
static let range = 1...999
static let range = 0...999
private static let atomNumbers: [String: Int] = [
static let atomNumbers: [String: Int] = [
"zero": 0,
"one": 1, "two": 2, "three": 3, "four": 4, "five": 5,
"six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10,
"eleven": 11, "twelve": 12, "thirteen": 13, "fourteen": 14, "fifteen": 15,
@@ -41,11 +42,17 @@ enum NumberWords {
byNumber[number] = atom
}
}
return range.map { byNumber[$0] ?? makeWord($0) }
return range.filter { n in
n <= 9
|| (n >= 10 && n <= 99 && n % 10 == 0)
|| n == 100
}.map { byNumber[$0] ?? makeWord($0) }
}
static func english(_ n: Int) -> String {
switch n {
case 0:
return "zero"
case 1...19:
return ones[n - 1]
case 20...99:
@@ -56,6 +63,16 @@ enum NumberWords {
let head = "\(ones[n / 100 - 1]) hundred"
let rest = n % 100
return rest == 0 ? head : "\(head) \(english(rest))"
case 1_000...999_999:
let thousands = n / 1_000
let rest = n % 1_000
let head = "\(english(thousands)) thousand"
return rest == 0 ? head : "\(head) \(english(rest))"
case 1_000_000...999_999_999:
let millions = n / 1_000_000
let rest = n % 1_000_000
let head = "\(english(millions)) million"
return rest == 0 ? head : "\(head) \(english(rest))"
default:
return "\(n)"
}
@@ -63,6 +80,8 @@ enum NumberWords {
static func phonetic(_ n: Int) -> String {
switch n {
case 0:
return "ˈzɪroʊ"
case 1...19:
return onesPhonetics[n - 1]
case 20...99:
@@ -73,6 +92,16 @@ enum NumberWords {
let head = "\(onesPhonetics[n / 100 - 1]) ˈhʌndrəd"
let rest = n % 100
return rest == 0 ? head : "\(head) \(phonetic(rest))"
case 1_000...999_999:
let thousands = n / 1_000
let rest = n % 1_000
let head = "\(phonetic(thousands)) ˈθaʊznd"
return rest == 0 ? head : "\(head) \(phonetic(rest))"
case 1_000_000...999_999_999:
let millions = n / 1_000_000
let rest = n % 1_000_000
let head = "\(phonetic(millions)) ˈmɪljən"
return rest == 0 ? head : "\(head) \(phonetic(rest))"
default:
return ""
}
@@ -100,11 +129,39 @@ enum NumberWords {
default:
return head + digits[rest / 10] + "" + (rest % 10 == 0 ? "" : digits[rest % 10])
}
case 1_000...9_999:
let head = digits[n / 1_000] + ""
let rest = n % 1_000
guard rest > 0 else { return head }
return rest < 100 ? head + "" + chinese(rest) : head + chinese(rest)
case 10_000...99_999_999:
let head = chinese(n / 10_000) + ""
let rest = n % 10_000
guard rest > 0 else { return head }
return rest < 1_000 ? head + "" + chinese(rest) : head + chinese(rest)
case 100_000_000...999_999_999:
let head = digits[n / 100_000_000] + "亿"
let rest = n % 100_000_000
guard rest > 0 else { return head }
return rest < 10_000_000 ? head + "" + chinese(rest) : head + chinese(rest)
default:
return "\(n)"
}
}
static func randomWord() -> Word {
let n = Int.random(in: 0...999_999_999)
return Word(word: english(n),
phonetic: "/\(phonetic(n))/",
meaning: chinese(n),
example: "The number is \(english(n)).",
exampleMeaning: "这个数字是\(chinese(n))")
}
static func randomWords(count: Int) -> [Word] {
(0..<count).map { _ in randomWord() }
}
private static func makeWord(_ n: Int) -> Word {
Word(word: english(n),
phonetic: "/\(phonetic(n))/",
@@ -147,6 +147,7 @@
"name": "数字",
"icon": "number",
"words": [
{ "word": "zero", "phonetic": "/ˈzɪroʊ/", "meaning": "零", "example": "Zero means nothing.", "exampleMeaning": "零表示没有。" },
{ "word": "one", "phonetic": "/wʌn/", "meaning": "一", "example": "I have one book.", "exampleMeaning": "我有一本书。" },
{ "word": "two", "phonetic": "/tuː/", "meaning": "二", "example": "Two birds are singing.", "exampleMeaning": "两只鸟在唱歌。" },
{ "word": "three", "phonetic": "/θriː/", "meaning": "三", "example": "Three cats are sleeping.", "exampleMeaning": "三只猫在睡觉。" },
@@ -174,7 +175,13 @@
{ "word": "seventy", "phonetic": "/ˈsevnti/", "meaning": "七十", "example": "My grandmother is seventy.", "exampleMeaning": "我奶奶七十岁。" },
{ "word": "eighty", "phonetic": "/ˈeɪti/", "meaning": "八十", "example": "He can count to eighty.", "exampleMeaning": "他能数到八十。" },
{ "word": "ninety", "phonetic": "/ˈnaɪnti/", "meaning": "九十", "example": "The book has ninety pages.", "exampleMeaning": "这本书有九十页。" },
{ "word": "hundred", "phonetic": "/ˈhʌndrəd/", "meaning": "百", "example": "One hundred people came.", "exampleMeaning": "来了一百个人。" }
{ "word": "hundred", "phonetic": "/ˈhʌndrəd/", "meaning": "百", "example": "One hundred people came.", "exampleMeaning": "来了一百个人。" },
{ "word": "thousand", "phonetic": "/ˈθaʊznd/", "meaning": "千", "example": "This library has thousands of books.", "exampleMeaning": "这个图书馆有数千本书。" },
{ "word": "ten thousand", "phonetic": "/ten ˈθaʊznd/", "meaning": "一万", "example": "Ten thousand people ran in the race.", "exampleMeaning": "一万人参加了赛跑。" },
{ "word": "hundred thousand", "phonetic": "/ˈhʌndrəd ˈθaʊznd/", "meaning": "十万", "example": "The house is worth two hundred thousand dollars.", "exampleMeaning": "这房子价值二十万美元。" },
{ "word": "million", "phonetic": "/ˈmɪljən/", "meaning": "百万", "example": "The city has a population of one million.", "exampleMeaning": "这个城市有一百万人口。" },
{ "word": "ten million", "phonetic": "/ten ˈmɪljən/", "meaning": "千万", "example": "Ten million viewers watched the show.", "exampleMeaning": "一千万观众看了这个节目。" },
{ "word": "hundred million", "phonetic": "/ˈhʌndrəd ˈmɪljən/", "meaning": "亿", "example": "Over a hundred million people speak Japanese.", "exampleMeaning": "超过一亿人说日语。" }
]
},
{
@@ -29,8 +29,11 @@ final class WordStore {
let decoded = try JSONDecoder().decode(WordBank.self, from: data)
let categories = decoded.categories.map { category -> WordCategory in
guard category.id == "numbers" else { return category }
var words = NumberWords.makeWords(atoms: category.words)
let extras = category.words.filter { NumberWords.atomNumbers[$0.word] == nil }
words.append(contentsOf: extras)
return WordCategory(id: category.id, name: category.name, icon: category.icon,
words: NumberWords.makeWords(atoms: category.words))
words: words)
}
bank = WordBank(version: decoded.version, categories: categories)
} catch {
@@ -119,7 +119,13 @@ final class WordListViewController: UIViewController {
private func startQuiz() {
Haptics.selection()
let request = QuizSetupRequest(words: category.words)
let words: [Word]
if category.id == "numbers" {
words = NumberWords.randomWords(count: 50)
} else {
words = category.words
}
let request = QuizSetupRequest(words: words)
navigationController?.pushViewController(QuizSetupViewController(request: request), animated: true)
}