VB.NETでカードのデッキをシャッフルする方法を書く

私は52枚のカードの標準デッキを配列で表現しています。各カードは整数で表されます。私はカードをシャッフルするために以下の関数を書いた。下のコードは大丈夫ですか?

Module Module3

Sub Main()

    ' initialize array
    Dim Cards(52) As Integer

    ' Unit Test
    ' Pass array as argument.
    Console.WriteLine(shuffle(Cards))

End Sub

Function shuffle(ByVal Cards() As Integer)

    Dim counter = 1
    Dim rand = New Random()

    For Each card In Cards

        ' Grab random number with range of 52
        Dim n = rand.Next(52)

        ' Pick a card
        Dim temp = Cards(counter)

        ' Swap picked card with random card
        Cards(counter) = Cards(n)
        Cards(n) = temp

        counter += 1

    Next

    Return (Cards)

End Function

End Module
3
@ブリュノ - リストの使用を検討してください。私が提供したコードを見てください。
追加された 著者 dbasnett,

4 答え

いいえ、コードはあなたの言うことをしません。

Dim Cards(52) As Integer

これにより、52枚ではなく53枚のカードの配列が作成されます。使用:

Dim Cards(51) As Integer

シャッフル時に、各カードをデッキ(またはそれ自身)の前のカードで交換します。デッキのどこにでも入れないでください。 (これはFisher-Yatesのシャッフルの原理です。)

ループとは別のカウンタを使用する代わりに、ループのカウンタを使用します。

Dim rand = New Random()

For counter = 0 to Cards.Length - 1

  Dim n = rand.Next(counter + 1)

  Dim temp = Cards(counter)
  Cards(counter) = Cards(n)
  Cards(n) = temp

Next
4
追加された

これは、私は配列を使用しないだろういくつかのゲームに使用される場合、私は簡単な項目が追加/削除することができるため、リストを使用します。

Module Module1

    Dim deck As New List(Of Integer)
    Dim prng As New Random

    Sub Main()
        newDeck()
        showDeck()
        shuffle()
        showDeck()
        Dim s As String
        Do
            s = Console.ReadLine()
            Select Case s
                Case "s"
                    showDeck()
                Case "c"
                    If deck.Count = 0 Then
                        Console.WriteLine("No cards")
                    Else
                        'take top card
                        Dim foo As Integer = deck(0)
                        deck.RemoveAt(0)
                        Console.WriteLine(foo.ToString)
                    End If
                Case "n"
                    newDeck()
                    shuffle()
            End Select
        Loop Until s.ToLower = "x"
    End Sub

    Sub newDeck()
        deck = Enumerable.Range(1, 52).ToList 'create deck
    End Sub

    Sub shuffle()
        deck = deck.OrderBy(Function(r) prng.Next).ToList
    End Sub

    Sub showDeck()
        Dim ctr As Integer = 0
        Console.WriteLine()
        For Each card As Integer In deck
            Console.Write("{0}", card.ToString.PadLeft(4, " "c))
            ctr += 1
            If ctr Mod 10 = 0 Then Console.WriteLine()
        Next
        Console.WriteLine()
    End Sub
End Module

しばらくの間、私はこれがコンピュータが実際の世界をまねするべきではないと考えていました。まず、乱数ジェネレータの種を知ることで問題を示すプログラムがあります。

'create a form with three buttons and a richtextbox
Dim deckIdx As New List(Of Integer)
Dim cards As New List(Of card)
Dim prng As New Random

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    newDeck()
    shuffle()
    showDeck()
End Sub

Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles Button3.Click
    'show next five cards
    Dim sb As New System.Text.StringBuilder
    sb.AppendLine()
    For x As Integer = 1 To 5
        Dim foo As card = getTopCard()
        If Not foo Is Nothing Then sb.AppendFormat("{0}", foo.theCard.ToString.PadLeft(4, " "c))
    Next
    RichTextBox1.AppendText(sb.ToString)
    RichTextBox1.ScrollToCaret()
End Sub

Private Sub Form1_Shown(sender As Object, e As System.EventArgs) Handles Me.Shown
    Button1.PerformClick()
End Sub

Class card
    Public theCard As Integer
    Public count As Integer
End Class

Sub newDeck()
    prng = New Random(42) '<<<<<<<<<<<<<<<<<<<<<<<< OOPS!!!
    deckIdx = Enumerable.Range(0, 51).ToList 'create deck indicies
    cards = New List(Of card)
    For Each cIDX As Integer In deckIdx
        Dim foo As New card
        foo.theCard = cIDX
        foo.count = 0
        cards.Add(foo)
    Next
End Sub

Sub shuffle()
    deckIdx = deckIdx.OrderBy(Function(r) prng.Next).ToList
End Sub

Function getTopCard() As card
    If deckIdx.Count > 0 Then
        Dim foo As New card
        foo.theCard = cards(deckIdx(0)).theCard
        foo.count = cards(deckIdx(0)).count
        deckIdx.RemoveAt(0)
        Return foo
    Else
        Return Nothing
    End If
End Function

Sub showDeck()
    Dim ctr As Integer = 0
    Dim sb As New System.Text.StringBuilder
    For Each card As Integer In deckIdx
        sb.AppendFormat("{0}", cards(card).theCard.ToString.PadLeft(4, " "c))
        ctr += 1
        If ctr Mod 10 = 0 Then sb.AppendLine()
    Next
    RichTextBox1.Text = sb.ToString
End Sub

プログラムを実行し、ボタン1/3を繰り返し押すと、同じ結果が何度も繰り返されます。コンピュータが現実の世界を正確に模倣しなければならないという考えに固執するつもりならば、明らかな修正はPRNGを再シードすることではありません。しかし、もし我々が別のアプローチをとったらどうでしょうか?

このコードを追加する

Dim bkgShuffle As Threading.Thread
Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
    Button2.Enabled = False
    bkgShuffle = New Threading.Thread(AddressOf shuffleBkg)
    bkgShuffle.IsBackground = True
    bkgShuffle.Start()
End Sub

Sub shuffleBkg()
    Do
        Threading.Thread.Sleep(50)
        shuffle()
    Loop
End Sub

前と同じようにプログラムを実行し、ボタン1と3を押して何も変わっていないことを確認します。満足したら、ボタン2を押して、ボタン1と3を押します。

自分でカードをプレイすると、デッキが常にシャッフルされているのではないことは明らかですが、それがあればどうなりますか?それは何か変わるだろうか?私がオンラインでカードをプレイすると、デッキが常にシャッフルされているかどうか知っていますか?

このコードは、箱の外で考えるという点を示すことに過ぎず、完成した製品とは見なすべきではありません。

編集: ブルマウンテンは一部の人々に影響を与える可能性がありますこれの。

1
追加された
非常に素晴らしい。ありがとうございました!
追加された 著者 Bruno,
アプリケーションは終了します。私が言ったように、これはある点を示すことでした。
追加された 著者 dbasnett,
あなたのshuffleBkgメソッドで無限ループを終了させるものは何ですか?
追加された 著者 Chris Dunaway,

主題に関するJeff Atwoodのブログ記事を見てください。

http://www.codinghorror.com/blog/2007/12/shuffling.html

1
追加された
私はインテルズ・ブル・マウンテン・アーキテクチャーがこのすべてにどのように影響を与えるのだろうか?
追加された 著者 dbasnett,

正式には今は「ブリッグス」シャッフルとして知られています

Module module1

Dim cards(51) As String
Dim trues(51) As Boolean
Dim number, Truecheck As Integer
Dim stores, loopy As String

Sub main()

    number = 1

    cards(0) = "Ace of Spades"
    cards(10) = "Jack of Spades"
    cards(11) = "Queen of Spades"
    cards(12) = "King of Spades"

    cards(13) = "Ace of Clubs"
    cards(23) = "Jack of Clubs"
    cards(24) = "Queen of Clubs"
    cards(25) = "King of Clubs"

    cards(26) = "Aec of Diamonds"
    cards(36) = "Jack of Diamods"
    cards(37) = "Queen of Diamonds"
    cards(38) = "King of Diamonds"

    cards(39) = "Ace of Hearts"
    cards(49) = "Jack of Heats"
    cards(50) = "Queen of Hearts"
    cards(51) = "King of Hearts"


    For i = 1 To 9
        number = number + 1
        cards(i) = number.ToString + " of Spades"
    Next

    number = 1

    For i = 14 To 22
        number = number + 1
        cards(i) = number.ToString + " of Clubs"
    Next

    number = 1

    For i = 27 To 35
        number = number + 1
        cards(i) = number.ToString + " of Diamonds"
    Next

    number = 1

    For i = 40 To 48
        number = number + 1
        cards(i) = number.ToString + " of Hearts"
    Next

    For i = 0 To 51
        Console.WriteLine(cards(i))
    Next


    Console.WriteLine("")
    Console.WriteLine("")

    For i = 0 To 51

linetrue:

        Randomize()
        stores = cards(i)
        Truecheck = Int(Rnd() * 51)
        If trues(Truecheck) = True Then GoTo linetrue

        trues(i) = True
        cards(i) = cards(Truecheck)
        cards(Truecheck) = stores
        Console.WriteLine(cards(i))

    Next


End Sub


End Module
0
追加された