我如何使用 Swift 的 Gameplaykit 中的 GKRandomSource 随机播放问题

How do I use GKRandomSource from Swift's Gameplaykit to shuffle questions

我是 Swift 和 iOS 开发的新手,正在学习一些在线课程。在一门课程中,我完成了一个 iPhone 测验应用程序。所有问题和可能的答案都从 .json 文件中加载,我们使用的代码随机选择一个问题供用户回答。这很好用,除了随着时间的推移问题会重复,所以我一直在寻找防止这种情况的方法。

在尝试让应用程序存储随机选择并将它们从剩余问题的总池中删除失败后,我意识到更有效的方法是先随机排列问题,然后再问他们一个一个。

因此,我进行了一些挖掘,发现了所谓的 Fisher-Yates 洗牌,此后一直在努力寻找实现这一目标的方法。然后我从 Swift 的 Gameplaykit 中找到了使用 GKRandomSource 来随机播放的参考资料,所以我一直在尝试使用它来完成这个技巧,但似乎无法让它发挥作用。

以下是我迄今为止在代码等方面的尝试

所有问题和可能的答案选择都存储在 .json 文件中:

{
        "id" : "1",
        "question": "Earth is a:",
             "answers": [
            "Planet",
            "Meteor",
            "Star",
            "Asteroid"
          ],
          "difficulty": "1"
      }

我使用以下代码加载 .json 文件:

func loadAllQuestionsAndAnswers()
{
    let path = NSBundle.mainBundle().pathForResource("content", ofType: "json")
    let jsonData : NSData = NSData(contentsOfFile: path!)!
    allEntries = (try! NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers)) as! NSArray
    //println(allEntries)

}

下面是我用来尝试随机播放所有问题的代码:

var shuffledNumber : Int! = 0

    loadAllQuestionsAndAnswers()

    if #available(iOS 9.0, *) {
        let shuffledNumber = GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(allEntries as NSArray as [AnyObject])
    } else {
        // Fallback on earlier versions
    }
    LoadQuestion(shuffledNumber)

我用一个标签来显示问题,用四张图片来显示可能的答案,代码如下:

func LoadQuestion(index : Int)
{
    let entry : NSDictionary = allEntries.objectAtIndex(index) as! NSDictionary
    let question : NSString = entry.objectForKey("question") as! NSString
    let arr : NSMutableArray = entry.objectForKey("answers") as! NSMutableArray

    //println(question)
    //println(arr)

    labelQuestion.text = question as String

    let indices : [Int] = [0,1,2,3]
    //let newSequence = shuffle(indices)
    let newSequence = indices.shuffle()
    var i : Int = 0
    for(i = 0; i < newSequence.count; i++)
    {
        let index = newSequence[i]
        if(index == 0)
        {
            // we need to store the correct answer index
            currentCorrectAnswerIndex =  i

        }

        let answer = arr.objectAtIndex(index) as! NSString
        switch(i)
        {
        case 0:
            buttonA.setTitle(answer as String, forState: UIControlState.Normal)
            break;

        case 1:
            buttonB.setTitle(answer as String, forState: UIControlState.Normal)
            break;

        case 2:
            buttonC.setTitle(answer as String, forState: UIControlState.Normal)
            break;

        case 3:
            buttonD.setTitle(answer as String, forState: UIControlState.Normal)
            break;

        default:
            break;
        }



    }
    buttonNext.hidden = true
    // we will need to reset the buttons to reenable them
    ResetAnswerButtons()

}

最后,我使用以下代码在用户回答问题后向他们显示 'Next' 按钮:

@IBAction func PressedButtonNext(sender: UIButton) {
    print("button Next pressed")
        if #available(iOS 9.0, *) {
            _ = GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(allEntries as [AnyObject])
        } else {
            // Fallback on earlier versions
        }
        LoadQuestion(shuffledNumber)

现在,虽然我认为这一切都应该可行,但事实并非如此。虽然应用程序加载正常,但它总是向用户呈现 .json 文件中的第一个问题,并在您每次点击“下一步”按钮时不断重复相同的问题。

我如何使用它来打乱所有问题,然后按顺序一一提问?让我知道是否需要包含更多代码。

arrayByShufflingObjectsInArray 给你一个新的随机排列的数组。因此,您应该调用它一次,并在调用 PressedButtonNext 时沿它移动索引。鉴于您已声明

    var shuffledNumber : Int! = 0

然后有效地重新声明

    let shuffledNumber = ...

它不起作用也就不足为奇了。我怀疑你在 IOS 9 下没有 运行,所以你没有得到编译错误(虽然我之前没有使用过#available)。

您应该声明以下实例变量:

    var shuffledQuestions: [AnyObject]!
    var nextQuestion = -1

然后在 loadAllQuestionsAndAnswers 中,您应该包括

    shuffledQuestions = GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(...

并在 PressedButtonNext

    nextQuestion++
    LoadQuestion(nextQuestion)

然后更改您的 LoadQuestion 以从打乱的问题中获得 entry

    let entry : NSDictionary = shuffledQuestions[index] as! NSDictionary

看看这个例子here