@AquiAki (Aki)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

クイズアプリで問題を重複なしでランダムに表示する方法【swift】

解決したいこと

swiftでクイズアプリを作ってますが、問題を重複なしでランダムに表示することができません。

手順として
1、配列quizをランダムに表示する
2、重複しないように表示する
( 空の配列を用意して、ランダムになったクイズから1つ取り出し空の配列に入れる など??)

かと思います。

しかしまだ1のランダムに表示することが出来ていません。
色々試しましたが、うまくいきませんでした。
プログラミング初心者のため、頭が混乱しています。。
どうかお助けください!

発生している問題・エラー

【Question.swift】  // Questionの型をこのファイルで指定

import Foundation

struct Question {
    let text: String
    let answers: [String]
    let rightAnswer: String
    init(q: String, a: [String], correctAnswer: String) {
        text = q
        answers = a
        rightAnswer = correctAnswer
    }
}


【QuizBrain.swift】 // 問題の内容はこのファイルで管理

import Foundation

struct QuizBrain {

var randomNumber = Int.random(in: 0..<11) // 1~10の整数をランダムで作る
var questionNumber = 0

let quiz = [
        Question(q: "Which is C ?", a: ["B", "C", "D"], correctAnswer: "C"),
        Question(q: "Which is F?", a: ["F", "G", "H"], correctAnswer: "F"),
        Question(q: "Which is J ?", a: ["H", "I", "J"], correctAnswer: "J"),
        Question(q: "Which is L ?", a: ["L", "M", "N"], correctAnswer: "L"),
        Question(q: "Which is P ?", a: ["P", "Q", "R"], correctAnswer: "P"),
]


func randomQuiz() ->  Question {
        let random = quiz.shuffled() // 配列quizの中身をシャッフル
        let randomQuiz = random[randomNumber] // さらにランダム(整数1~10の間)で配列の要素を決める  
        return randomQuiz
    }

mutating func nextQuestion() {
        if questionNumber + 1  < quiz.count {
            questionNumber += 1
        } else {
            questionNumber = 0
        }
    }

// ランダムで決めた問題のテキスト、つまりQuestionのqを取得
mutating func getText() -> String {
        return randomQuiz().text
}

// ランダムで決めた問題のアンサー、つまりQuestionのaを取得
mutating func getAnswers() -> [String] {
        return randomQuiz().answers
}

// ユーザーが選択したものが正解かをチェックする
mutating func checkAnswer(userAnswer: String) -> Bool {
        if userAnswer == quiz[questionNumber].rightAnswer {
            return true
        } else {
            return false
        }
    }
}


【VocabularyController.swift】 // MVCモデルのControllerの部分

import UIKit
import AVFoundation

class VocabularyController: UIViewController {

    @IBOutlet weak var questionLabel: UILabel! // Questionのqを表示
    @IBOutlet weak var choice1: UIButton! // Questionのaの1つを表示
    @IBOutlet weak var choice2: UIButton! // Questionのaの1つを表示
    @IBOutlet weak var choice3: UIButton! // Questionのaの1つを表示

    var quizBrain = QuizBrain() // このファイルでQuizBrain()の中身を使えるようにする
    override func viewDidLoad() {
        super.viewDidLoad()
        updateUI()
    }

  @IBAction func answerButtonPressed(_ sender: UIButton) {
        let userAnswer = sender.currentTitle!
        let userGotItRight = quizBrain.checkAnswer(userAnswer: userAnswer)

        quizBrain.nextQuestion() // 次のクイズに進むか確認

        Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(updateUI), userInfo: nil, repeats: false)
  }

@objc func updateUI() {
        questionLabel.text = quizBrain.getText()   // クイズのqの部分を表示する
        let answerChoices = quizBrain.getAnswers() // クイズのaの部分を表示する

        choice1.setTitle(answerChoices[0], for: .normal) // クイズの選択肢が3つある、それを問題ごとにセットする
        choice2.setTitle(answerChoices[1], for: .normal)
        choice3.setTitle(answerChoices[2], for: .normal) 
   }
}


エラーは出ていませんが、ランダムにうまく表示が出来ません。
具体的には、ランダムに表示するとquizのqがランダムに表示されますが、そのqに合ったaが表示されないです。

例えばqが "Which is F?" であればaは ["F", "G", "H"] となるはずですが、
関係のない["P", "Q", "R"]が解答の選択肢として表示されてしまいます。
つまり問題と選択肢が一致しないです。

問題と選択肢が一致させながらランダムにクイズを表示させる方法を教えて下さい。
そして、問題を重複しないように表示する方法も合わせて是非ご教授ください。
宜しくお願いします!

0 likes

1Answer

問題と答え候補が一致しない原因は、以下の部分でそれぞれ独立にrandomQuizを呼んでいるためです。

// ランダムで決めた問題のテキスト、つまりQuestionのqを取得
mutating func getText() -> String {
        return randomQuiz().text
}

// ランダムで決めた問題のアンサー、つまりQuestionのaを取得
mutating func getAnswers() -> [String] {
        return randomQuiz().answers
}

解決策ですが、shuffleの結果を固定すればランダムで重複なくqとaが一致するようになります。例えばクイズの開始時にlet shuffledQuiz = quiz.shuffled()を値として保存し、それに対してshuffledQuiz[questionNumber]のように順にアクセスしていく方法が考えられます。お試しください!

1Like

Comments

  1. @AquiAki

    Questioner

    回答ありがとうございます。
    ご指摘して頂いたとおり試したところ、無事ランダムに表示させることができました!
    ずっと詰まっていたところでしたので、本当に助かりました。
    有難うございます!

Your answer might help someone💌