Write a method to shuffle a deck of cards in VB.NET

前端 未结 4 1838
栀梦
栀梦 2021-01-06 11:57

I have a standard deck of 52 cards is represented in an array. Each card is represented as an integer. I wrote the below function to shuffle the cards. Does the code below l

4条回答
  •  迷失自我
    2021-01-06 12:16

    If this is going to be used for some game I wouldn't use an array, I would use a list because of the ease items can be added / removed.

    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
    

    For some time I have thought that this was a case where the computer shouldn't mimic the real world exactly. First, here is a program that shows the problem with knowing the seed of the random number generator.

    '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
    

    Running the program and pressing button1 / 3 repeatedly will produce the same results, over and over. If we are going to adhere to the idea that the computer must mimic the real world exactly, then the obvious fix is to not re-seed the PRNG. But what if we took a different approach.

    Add this code

    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
    

    Run the program as before, press button 1 and 3 to verify that nothing has changed. When you are satisfied press button 2, and then press button 1 and 3.

    When you play cards in person it is obvious that the deck is not constantly being shuffled, but what if it was? Would it change anything? If I play cards online do I know or care if the deck is constantly being shuffled?

    The code was only to demonstrate a point, to think outside of the box, and should not be considered a finished product.

    edit: Bull Mountain is likely to affect some of this.

提交回复
热议问题