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

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

ただいまの
回答率

88.04%

xcodeで乱数がおかしい・デッキ制限ありのときのトランプランダム配布の処理

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,659

score 8

前提・実現したいこと

Xcode6.4 (6E35b),iOS SDK8.4の環境でアプリを作ろうとしています。ボタンを押すと、手札にランダムなマーク、数字のカードが追加されるというようなプログラムを作りました。しかし、その「ランダム」がなんだかおかしいです。。。

発生している問題・エラーメッセージ

実際のiOS Simulatorの画像このように、まあランダムではあるんですが、明らかに偏りが生じています。。。これじゃあトランプでゲーム!なんてとてもじゃないけどできません。。。

下記のソースコードのランダムの部分を作ってるコードはplaygroundで作ったものなのですが、playgroundでは正常に作動していました。しかし実際にアプリの方に移したらこのような結果になっています。。。

ソースコード

import UIKit

class ViewController: UIViewController {
    
    var w = UIScreen.mainScreen().bounds.size.width
    var h = UIScreen.mainScreen().bounds.size.height
    var imageView :Array<UIImageView> = []
    var n = 0
    var tefuda = [Int](count: 21, repeatedValue: 0)

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        for i in 0...20 {
            tefuda[i] = Int(arc4random_uniform(51)) + 1
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBOutlet weak var imageButton: UIButton!

    @IBAction func buttonAction(sender: AnyObject) {
        
        var color = "c"
        var number = 0
        var show = "c01"
        
        
        //println("\(tefuda[n])") 出力されず…
        
        switch tefuda[n] {
            
        case 1...13:
            color = "c"
        case 14...26:
            color = "d"
        case 27...39:
            color = "h"
        case 40...52:
            color = "s"
        default:
            break
            
        }
        
        if tefuda[n] % 13 == 0 {
            number = 13
        } else {
            number = tefuda[0] % 13 //←ここの0がnでした
        }
        
        if number < 10 {
            show = color + "0" + String(number)
        } else {
            show = color + String(number)
        }
        
        imageView.append(UIImageView(frame: CGRectMake(CGFloat(10+20*n), CGFloat(9*h/10-150), CGFloat(100), CGFloat(150))))
        
        self.view.addSubview(imageView[n])
        
        imageView[n].image = UIImage(named: show)
        
        n++
        
    }
}

補足情報(言語/FW/ツール等のバージョンなど)

  • 画像はc01.png(クローバーの1)からc13.png(クローバーの13)まで、といった感じにリソースファイル(?)に読み込んであります。ダイヤはd、ハートはh、スペードはsが数字の前についています。
  • 配列tehudaをprintln()で出力しようとしたのですがなぜか出力されず。。。何回再起動しても同じ数字ばっかりでます…なぜか時々挟まってくるキングが不思議です笑
  • arc4random_uniformのところをarc4randomでやったりもしましたがダメでした
  • 内容的には、ブラックジャックを意識してます。6デッキ以上使うことを想定しているため、Aが21枚出るかも…と思ったので、tehuda[]の要素数は21個です。
  • プログラミングは趣味でやってます。初心者ですので、とても初歩的なミスをしてるかもしれません。そうだったらごめんなさい。
  • 初めて質問します。何か無礼なことがあったら、申し訳ございません。もしよろしければ、分かる方、ご教授お願いいたします

解決

ランダムにミスを修正した結果、ちゃんとランダムになりました!やった!回答してくださったお二方、本当にありがとうございました。

複数のデッキを使った時のシャッフル

import UIKit

class ViewController: UIViewController {
    
    var w = UIScreen.mainScreen().bounds.size.width
    var h = UIScreen.mainScreen().bounds.size.height
    var imageView :Array<UIImageView> = []
    var n = 0
    ☆var deckCount = 6 //デッキ数
    var tefuda = [Int](count: 21, repeatedValue: 0)

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        ☆var card = [Int](count: 52*deckCount, repeatedValue: 0)
        
        //シャッフルされた配列
        ☆var shuffledCard :Array<Int> = []
        
        //1~52がデッキ数並んだ配列card
        ☆for i in 0...52*deckCount-1 {
        ☆    card[i] = i % 52 + 1
        ☆}
        
        //シャッフル
        ☆for i in 0...52*deckCount-1 {
        ☆    var index = Int(arc4random()) % card.count
            
        ☆    shuffledCard.append(card[index])
        ☆    card.removeAtIndex(index)
        ☆}
        
        for i in 0...20 {
        ☆    tefuda[i] = shuffledCard[i]
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBOutlet weak var imageButton: UIButton!

    
    
    
    
    
    @IBAction func buttonAction(sender: AnyObject) {
        
        var color = "c"
        var number = 0
        var show = "c01"
        
        
        //println("\(tefuda[n])")
        
        switch tefuda[n] {
            
        case 1...13:
            color = "c"
        case 14...26:
            color = "d"
        case 27...39:
            color = "h"
        case 40...52:
            color = "s"
        default:
            break
            
        }
        
        if tefuda[n] % 13 == 0 {
            number = 13
        } else {
            number = tefuda[n] % 13
        }
        
        if number < 10 {
            show = color + "0" + String(number)
        } else {
            show = color + String(number)
        }
        
        imageView.append(UIImageView(frame: CGRectMake(CGFloat(10+20*n), CGFloat(9*h/10-150), CGFloat(100), CGFloat(150))))
        
        self.view.addSubview(imageView[n])
        
        imageView[n].image = UIImage(named: show)
        
        n++
        
    }
}
☆の部分を変更、及び追記しました。
良いプログラムではないと思いますが、正常に動作するのを確認できました。
シャッフルの処理はこちらより丸コピさせていただきました。勝手に使ってごめんなさい。
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

0

トランプですから、単純にランダムカードを表示するのではなく、
同じカードが現れないようシャッフル処理すべきという話はありますが、
このコーディングで同じ数字ばっかり出る理由は
    if tefuda[n] % 13 == 0 {
        number = 13
    } else {
        number = tefuda[0] % 13
    }
の部分が誤っているからです。
number = tefuda[0] % 13
ではなく
number = tefuda[n] % 13
にしないと、全部tefuda[0]の数字のカードが表示されてしまいます。
そして、tefuda[n]%13が0の時だけキングのカードが表示されます。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/09/20 00:16

    TakeOne様
    回答ありがとうございます。

    本当ですね!!
    初歩的なミスを犯していました…申し訳ありません。
    playgroundの方では追加していく方式ではなく、一枚表示するだけだったので、tefuda配列の[0]しか使ってませんでした。まさかの移植ミス…
    おかげさまで、見事ちゃんとしたランダムを生成することができました。
    同じカードがデッキ数より多く存在しないように調整しつつ、アプリを作っていこうと思います。ありがとうございました。

    キャンセル

0

サイコロを振る動作を乱数で行う場合と、トランプを配るのを乱数で行う場合は処理が変わります。
サイコロの場合は、同じ目が出てもよいですが、トランプを配る場合は、同じカードが2回以上 出てはいけないからです。

for i in 0...20 {
  tefuda[i] = Int(arc4random_uniform(51)) + 1
}
では、同じカードが選ばれてしまう可能性があります。

シャッフルについての参考記事を紹介します。
参考:
- swiftでArrayを擬似乱数でshuffleする方法は? http://ja.stackoverflow.com/questions/9110/
- swiftでシャッフル関数 http://qiita.com/satoshia/items/13d0842a784f0f91c018
- Playing cards http://rosettacode.org/wiki/Playing_cards#Swift
- How to shuffle an array in iOS 8 and below https://www.hackingwithswift.com/example-code/arrays/how-to-shuffle-an-array-in-ios-8-and-below

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/09/20 01:27

    多数のアドバイス、ありがとうございます。
    確かに、"C2"のようにして扱えば、楽になりますね!
    何よりわかりやすいですね。
    ありがとうございました。
    がんばります!

    キャンセル

  • 2015/09/20 06:28

    ぜひ、複数トランプの組みのシャッフル処理の最終コードをここに載せて欲しいです。
    同じことをしたい方へのよい助けになると思います。

    キャンセル

  • 2015/09/20 09:55

    追記しました!
    プログラムはだらだらと長くなってしまいましたが、正常に動作したので自分の中では満足しています。
    この度は色々とありがとうございました。

    キャンセル

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

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

関連した質問

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