質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.23%

乱数 重複しない

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,904
退会済みユーザー

退会済みユーザー

前提・実現したいこと

今カルタの文を読んでくれるアプリ?を作っています。今できているところは48種類のカルタの文をランダムに読んでくれるところです。しかし、一度読んだ文もまた繰り返されます。それを一度読んだものはもう読まないようにしたいです。

ボタンを押すと次の文と最初の文字を表示しその文を
読み上げてくれるようになっています。

該当のソースコード

    import UIKit

import AVFoundation

class ViewController: UIViewController {

    @IBOutlet weak var QuestionLabel: UILabel!

    @IBOutlet weak var Button1: UIButton!

    @IBOutlet weak var Next: UIButton!

    var CorrectAnswer = String\(\)

    override func viewDidLoad\(\) {
        super\.viewDidLoad\(\)

        Hide\(\)
        RandomQuestions\(\)

    }

    override func didReceiveMemoryWarning\(\) {
        super\.didReceiveMemoryWarning\(\)

    }
    func RandomQuestions\(\){

        var RandomNumber = arc4random\(\) % 48

        RandomNumber \+= 1

        switch \(RandomNumber\) {

        case 1:

            QuestionLabel\.text = "モンゴルの民族模様は自由の印"
            Button1\.setTitle\("も", for: \.normal\)
//文を読む
            let synthesizer = AVSpeechSynthesizer\(\)
            let utterance = AVSpeechUtterance\(string: "モンゴルの民族模様は自由の印。"\)
            synthesizer\.speak\(utterance\)

            break

        case 2:

            QuestionLabel\.text = "三色の統一ドイツ黒赤金"
            Button1\.setTitle\("さ", for: \.normal\)

            let synthesizer = AVSpeechSynthesizer\(\)
            let utterance = AVSpeechUtterance\(string: "三色の統一ドイツ黒赤金"\)
            synthesizer\.speak\(utterance\)



            break

        case 3:


            QuestionLabel\.text = "エクアドルコンドルが飛ぶアンデスへ"
            Button1\.setTitle\("え", for: \.normal\)

            let synthesizer = AVSpeechSynthesizer\(\)
            let utterance = AVSpeechUtterance\(string: "エクアドルコンドルが飛ぶアンデスへ"\)
            synthesizer\.speak\(utterance\)


            break

//略



        case 48:


            QuestionLabel\.text = "バーレーンはギザギザ模様で鮮やかに"
            Button1\.setTitle\("ば", for: \.normal\)

            let synthesizer = AVSpeechSynthesizer\(\)
            let utterance = AVSpeechUtterance\(string: "バーレーンはギザギザ模様で鮮やかに"\)
            synthesizer\.speak\(utterance\)
            break

        default:

            break

        }

    }

    func Hide\(\){

        Next\.isHidden = true
    }

    func UnHide\(\){

        Next\.isHidden = false
    }

    @IBAction func Button1Action\(_ sender: AnyObject\) {

       UnHide\(\)

    }

    @IBAction func Next\(_ sender: AnyObject\) {
        RandomQuestions\(\)
    }

}

試したこと

nsuser defaultsを使ったり、空の配列を作り一度つかったものを入れたりなどと案は思いつきますが、どのようにコードを書くのかわかりません。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • fuzzball

    2017/04/18 10:38

    質問とは関係ありませんが、乱数生成には arc4random_uniform() を使った方がいいです。

    キャンセル

  • ozwk

    2017/04/19 15:52

    質問内容消してアカウント消すのってたまに見ますけど何がしたいんでしょうね?乗っ取り?

    キャンセル

  • 退会済みユーザー

    2017/04/19 15:54

    複数のユーザーから「意図的に内容が抹消された質問」という意見がありました
    解決後に編集機能を用いて質問内容を改変し関係のない内容にしたり、内容を削除する行為は禁止しています。
    投稿していただいた質問は、後に他の誰かが困ったときに助けになる情報資産になると考えるからです。
    「質問を編集する」ボタンから編集を行い、他のユーザにも質問内容が見えるように修正してください。

回答 4

+5

Fisher-Yates法というのが、配列をシャッフルする定番のアルゴリズムです(ランダムな箇所をシャッフルし続ける方法では、「完璧に均等にはできない」ことが、比較的容易に証明できます)。

# 擬似コード
while(i = arr.length; i >= 2; --i) {
  j = (0以上i-1以下の乱数)
  arr[i]とarr[j]を交換
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/04/17 19:49

    ウィキペディア見ました。私もこれを作っている時に何回も同じものが繰り返されました。
    どのようにwhile(i = arr.length; i >= 2; --i) {
    j = (0以上i-1以下の乱数)
    arr[i]とarr[j]を交換
    }

    を使うと解決しますかね?

    キャンセル

checkベストアンサー

0

欲しいのは1~48の乱数ではなく、
「1から48までの数字が、重複なく1回だけ出てくる、48個の値を持つリスト」だということを理解しましょう。

この場合乱数でランダムに1~48を作るのではなく、

  1. 1~48までを順に並べたリストを用意する
  2. 十分な回数(リスト内の個数の半分やればよいことが数学的に証明されています)、リストの任意の2か所の内容を入れ替える(シャッフル)

とやるのが定法です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/04/18 11:33 編集

    いえ、「動かさない」(=同一の箇所を入れ替える)というパターンが存在しうるので、任意の2か所でよかったはず。最適手を取った場合(入れ替える位置が一切重複しない)、個数 2n であれば最大 n 回の入替で目標の順列にたどり着くことができる、はず。もう数学の授業は20年以上前のことなので忘れちゃってますが(棒

    キャンセル

  • 2017/04/18 11:37

    いや、「任意」じゃなくて「無作為」では?と言いたかったんです

    キャンセル

  • 2017/04/18 11:46

    ああ、そういうことですか。納得しました。確かに無作為の方が良かったかもしれません。

    キャンセル

0

質問とは関係ありませんが、長々と続くswitch文を見て思わず筆を執ってしまいました。

//配列+タプルでカルタを定義
let Q = [
    ("も", "モンゴルの民族模様は自由の印"),
    ("さ", "三色の統一ドイツ黒赤金"),
    ("ば", "バーレーンはギザギザ模様で鮮やかに"),
]

/*
//.0で1番目の項目にアクセス
print(Q[0].0) //=> も
//.1で2番目の項目にアクセス
print(Q[0].1) //=> モンゴルの民族模様は自由の印
*/

func RandomQuestions() {
    var rand = arc4random_uniform(Q.count) //0~(問題数-1)の乱数を生成

    QuestionLabel.text = Q[rand].1
    Button1.setTitle(Q[rand].0, for: .normal)
    let synthesizer = AVSpeechSynthesizer()
    let utterance = AVSpeechUtterance(string: QuestionLabel.text) //表示と同じなのであればQuestionLabel.textをそのまま使えばOK
    synthesizer.speak(utterance)
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/04/18 21:19

    重複しないためにこうすると良いというアドバイスありますかね・・・?

    キャンセル

  • 2017/04/18 21:21

    それは他の方の回答を参考にされては?

    キャンセル

  • 2017/04/18 21:25

    わかりました

    キャンセル

0

var RandomNumber = arc4random() % 48

の取得結果を配列に格納していって、
二回目以降のRandomNumberと配列に格納された数値を比較して等しいものがあったら
RandomNumberを実行しなおすようにしたら出来るんじゃないかな。

まぁ48枚目のとき1/48を引くまで無限にランダム数字取得しに行くことになるけど。。。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.23%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る