2016-01-25 66 views
4

我正在製作測驗應用程序。該應用程序使用.json文件作爲問題和答案的「數據庫」。這個.json文件看起來如下...在iOS中隨機顯示字符串而不重複它們

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

...並且只是繼續超過500個問題。

我用下面的代碼隨機顯示的問題:

let randomNumber = Int(arc4random_uniform(UInt32(allEntries.count))) 
    LoadQuestion(randomNumber) 

這項工作很好,但因爲它選擇的問題隨機我發現,問題都被定期(即使我有超過500個重複問題!)。

我已經對此進行了廣泛的研究,並認爲或許我讀了太多,因爲我現在很困惑。我已經閱讀過關於「播種」的內容,關於保存問題索引以及嘗試使用NSUserDefault。

總之,我怎麼能修改我的代碼來實現以下成果之一,而不是:

  1. 不重複在所有的任何問題,但停止問問題時,所有的問題都已經問一次;
  2. 與上面的1類似,但具有由用戶設置的問題數量而不是詢問數據庫中的所有問題;
  3. 不要重複任何問題,直到首先詢問所有問題;或者,
  4. 要不重複以前已正確回答的任何問題,但可能會重複錯誤回答的問題。

下面就是我的想法是代碼的相關位:

LoadAllQuestionsAndAnswers() 

    let randomNumber = Int(arc4random_uniform(UInt32(allEntries.count))) 
    LoadQuestion(randomNumber) 


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) 

} 


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() 

} 



@IBAction func PressedButtonNext(sender: UIButton) { 
    print("button Next pressed") 
    let randomNumber = Int(arc4random_uniform(UInt32(allEntries.count))) 
    LoadQuestion(randomNumber) 

} 

回答

3

如果我正確地理解您的需求:

  • 你要堅持視圖控制器實例之間的隨機生成的數字和應用程序發佈
  • 你永遠不想重複任何問題

實現此目的的一種快速方法是使用NSUserDefaults來跟蹤PRNG中(僞)隨機數的順序和值。這樣,您可以通過重播先前的骰子卷,以正確的順序從池中移除這些問題,從而立即實例化即時問題的可用問題數組。

這也可以讓你把PRNG作爲一個黑盒子來處理,而不是關心播種和重播。

此外,請確保從任何骰子擲出當前池中刪除任何選定的問題。

備註:您沒有遵循命名約定 - 例如,函數將以小寫字母開頭。

爲了您的良好和可讀性,請遵循流行的慣例,至少在與他人分享您的代碼時。更好的是,所有的時間。

編輯

得更加詳細:

  • NSUserDefaults可以節省少量的爲你的數據在一個簡單的方法。如果你「只是想記住一系列數字」,那就到位了。
  • 假設你的數據是helt在一個實例變量,像這樣:

    var questions : [Question] = // load the questions - carefully, see below. 
    

    可以輕鬆去除的問題您PSNG(p seudo- [R andom ň enerator)選擇像這樣:

    let randomNumber = Int(arc4random_uniform(UInt32(questions.count))) 
    questions.removeAtIndex(randomNumber) 
    

    因此,下一個擲骰子(例如您的PSNG的調用)是保證不要選擇已經問過的問題,因爲它已經不在其選擇的可用問題池中。

  • 這種方法確實需要您以正確的順序保存所有的隨機數字,以便'重放'在實例化新實例之前發生的情況(例如,因爲應用程序已重新打開)。這就是NSUserDefaults' setObject:forKey:objectForKey:在最初加載問題和「記住」每個新骰子滾動時起作用的地方。

我希望,這涵蓋了你可能以前不明白的東西。

+0

謝謝你的建議。這對我來說是全新的,所以你說的大部分內容都像是讀一門外語,但我會試着再次研究NSUserDefaults。如果有什麼可以推薦給我的,或者甚至是一些代碼示例,那就太棒了。 感謝您對以下命名約定的建議 - 我甚至不知道函數應該以小寫開頭,因此我將更正所有代碼。 – Monomeeth

+0

OP,我的確嘗試着寫更詳細的代碼給你,所以你可以理解正在發生什麼,而不是從SO編寫代碼;) – SmokeDispenser

+0

太棒了。我現在正在研究NSUserDedaults,試圖讓我的頭腦轉向它。有一件事,你能澄清爲什麼我需要以正確的順序保存所有的隨機數嗎?我試圖讓我的頭瞭解爲什麼訂單很重要,並且爲什麼它不會自動按照正確的順序放行? – Monomeeth