概要

13ジャンルから興味のあるものをコインで解放し、3つのプレイモード(ランダム/順番/続きから)で問題を解いていく機能。 進捗・履歴は AppGroup に保存。

関連画面

13ジャンル

歴史 / 科学 / 地理 / 文学・言語 / 芸術・音楽 / スポーツ / 食・料理 / 自然・動植物 / 宇宙・天文 / テクノロジー・IT / 医学・健康 / 心理学 / 雑学・トリビア

API

@MainActor
final class GenreQuizService {
    func unlockGenre(id: String) -> Bool
    func isUnlocked(id: String) -> Bool
    func loadQuestions(genreId: String) -> [GenreQuizQuestion]
    func randomQuestion(genreId: String) -> GenreQuizQuestion?
}

final class GenreProgressService {  // @unchecked Sendable
    func getAnsweredCount(genreId: String) -> Int
    func getCorrectCount(genreId: String) -> Int
    func getPosition(genreId: String) -> Int
    func recordAnswer(genreId:, questionId:, correct:)
}

プレイモード

モード動作
ランダム毎回 randomQuestion() で異なる問題
順番通りposition をリセットして1問目から
続きから保存された position から再開

処理フロー(アンロック → プレイ)

  1. ユーザーがジャンルカードで「100コインで解放」タップ
  2. CoinService.spendCoins(100)
  3. GenreQuizService.unlockGenre(id:)
  4. AppGroup の unlocked_genres に追加
  5. 「プレイ」ボタン → モード選択
  6. Interstitial広告表示(無料ユーザー)
  7. GenreQuizPlayView で問題解答
  8. 各回答ごとに GenreProgressService.recordAnswer()

ビジネスルール

外部連携

連携先用途
Bundle JSON各ジャンルの問題セット読込
CoinService解放時のコイン消費
InterstitialAdManagerプレイ開始時の広告
AppGroup UserDefaults進捗・履歴・アンロック状態

エラー処理

発生条件対応
残高不足「コインが足りません」アラート
JSON 読込失敗「問題を取得できませんでした」 + 空リスト
すでにアンロック済みUI でブロック(unlock ボタン非表示)

実装メモ

変更履歴

バージョン日付変更内容
1.02026-05-09初版作成