0

I am creating a simple quiz app. There are four choices and the placement of choices is generated randomly. Four UILabels are set to display choices.

I have written the following code and it usually works well but sometimes the same choices are displayed.

ex) 2017 2015 2015 1700

The error should be the for loops but I can't figure out.

let questions = ["What year is now?"]
let answers = [["2017", "2015", "1000", "1700"]]
var rightAnswerPlacement:UInt32 = 0
var currentQuestion = 0

//Function that displays new question
func newQuestion()
{
    lbl.text = questions[currentQuestion]        
    rightAnswerPlacement = arc4random_uniform(4)+1        
    // Create a button
    var button:UIButton = UIButton()
    var x = 1        
    for i in 1...4
    {
        //Create a button
        button = view.viewWithTag(i) as! UIButton
        if (i == Int(rightAnswerPlacement))
        {
            button.setTitle(answers[currentQuestion][0], for: .normal)
        }
        else
        {
            button.setTitle(answers[currentQuestion][x], for: .normal)
            x = 2
        }
    }
    button.setTitle(answers[currentQuestion][3], for: .normal)
    currentQuestion += 1
}
rebecca87
  • 69
  • 2
  • 9
  • Where does `currentQuestion` get a value? You use it to look up values in `answers` but you never assign a value to it. – Tom Harrington May 26 '17 at 17:02
  • Sorry I updated my question – rebecca87 May 26 '17 at 17:08
  • If I understand correctly, you want to place the first answer (the right one) randomly and the other three in sequence? With the four iterations of the loop (btw. do not use 4 as the fixed number but check the size of the answers-array) you create 4 buttons but with the x-index-counting you might skip one of the answers. Also you have one extra button for answer[currentQuestion][3] – Gerriet May 26 '17 at 17:12
  • Why "with the x-index-counting it might skip one of the answers"? I removed [currentQuestion][3] and now it has two same answers:/ – rebecca87 May 26 '17 at 17:17

2 Answers2

2

A very common method is to "shuffle" the answers. Then you don't have to do any ifs:

let questions = [
    "What year is now?",
    "What is your favorite color?"
]

let answers = [
    ["2017", "2015", "1000", "1700"],
    ["Blue", "Red", "Yellow", "Green"]
]

var currentQuestion = 0

//Function that displays new question
func newQuestion()
{
    // get the current question text
    let thisQuestion = questions[currentQuestion]

    // get a "shuffled" array of the current answers
    let theseAnswers = answers[currentQuestion].shuffled()

    lbl.text = thisQuestion

    // loop through the shuffled answers, setting the button titles
    for (i, answer) in theseAnswers.enumerated() {
        if let button = view.viewWithTag(i) as? UIButton {
            button.setTitle(answer, for: .normal)
        }
    }

}

Now, each time you call newQuestion() the answers will be in random order.


There are many examples of Array shuffling - this is a good example (from "Nate Cook" here... How do I shuffle an array in Swift?):

extension MutableCollection where Indices.Iterator.Element == Index {
    /// Shuffles the contents of this collection.
    mutating func shuffle() {
        let c = count
        guard c > 1 else { return }

        for (firstUnshuffled , unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
            let d: IndexDistance = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
            guard d != 0 else { continue }
            let i = index(firstUnshuffled, offsetBy: d)
            swap(&self[firstUnshuffled], &self[i])
        }
    }
}

extension Sequence {
    /// Returns an array with the contents of this sequence, shuffled.
    func shuffled() -> [Iterator.Element] {
        var result = Array(self)
        result.shuffle()
        return result
    }
}
DonMag
  • 69,424
  • 5
  • 50
  • 86
1

Replace x = 2 with x = x + 1. You want to skip an answer rather than picking a specific one.

Doing that also means you don't need the special case for [currentQuestion][3].

Phillip Mills
  • 30,888
  • 4
  • 42
  • 57