【问题标题】:How do I shuffle and deal cards one at a time to players?我如何一次向玩家洗牌和发牌?
【发布时间】:2014-12-18 05:19:03
【问题描述】:

这就是我到目前为止所得到的,发现自己陷入了困境。=/

Private Sub Dealbtn_Click(sender As Object, e As EventArgs) Handles Dealbtn.Click  
     Dim Suits() As String  = {"S", "D", "C", "H"} 
     Dim Faces() As String = {"2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"}  
     Dim rand As New Random  
     Dim rand1 As Integer = rand.Next(12)  
     Dim rand2 As Integer = rand.Next(3)  
     Label2.Text() = Faces(rand1) + Suits(rand2)  
End Sub

【问题讨论】:

  • 从了解Scope in Visual Basic开始,您的数组将只存在于那个微小的事件过程中
  • 是的,我有,但我不知道每次我使用循环按下交易 btn 时如何让它向 lbl 发牌。它只是没有点击
  • 设置断点 - 它几乎可以肯定是点击;每次只针对同一个标签与 1 到 4 个不同的播放器/标签
  • 是的,我知道,但问题是对我脑海中没有点击的“断点”进行编码。
  • 断点已设置 [F9] 未编码。

标签: .net vb.net class


【解决方案1】:

这是错误的做法:

Dim rand As New Random  
Dim rand1 As Integer = rand.Next(12)  
Dim rand2 As Integer = rand.Next(3) 

您很容易得到重复的牌,因为您在选择这张牌时并不知道它是否已经发牌(即使在此点击中!)。您还希望 一个 随机使用每个游戏/应用程序,而不是每张卡。将卡片表示为 suit & face 会起作用,但它将 2 条重要信息粘合在一起 - 在大多数游戏中,您稍后必须解析它才能获取该信息。

一副牌由 52 张牌组成;每张卡片由花色和等级组成。让我们构建一两个简单的类来模仿:

Public Class Card
    Public Property Suit As String
    Public Property Rank As Integer

    ' card images from
    ' http://www.jfitz.com/cards/
    Public Property Img As Image

    Private Faces() As String = {"Jack", "Queen", "King", "Ace"}

    ' for text version of the game
    Public Function CardText() As String
        Dim tmp As String = Rank.ToString
        If Rank = 1 Then
            tmp = "Ace"
        ElseIf Rank >= 11 Then
            tmp = Faces(Rank - 11)
        End If
        Return String.Format("{0} of {1}", tmp, Suit)

    End Function

    ' iDeck class will assign Rank, Suit and img to an "empty" card
    Public Sub New(strSuit As String, nRank As Integer, i As Image)
        Suit = strSuit
        Rank = nRank
        Img = i
    End Sub

    Public Overrides Function ToString() As String
        Return CardText()
    End Function
End Class

实际上,您还需要一个 Value 属性,因为在大多数游戏中它与 Rank 不同。

将等级和花色作为单独的属性,您可以测试一个玩家的牌与另一个玩家的牌,看看谁的牌最好。这在像二十一点这样的游戏中很容易,因为您所关心的只是排名和总和。手牌评估在其他游戏中更为复杂,因为您可以使用 FullHouse 和 Flush 等组合。现在是套牌(出于说明目的,两种洗牌方法都在那里):

Public Class Deck
    Dim rand As Random

    ' the deck will be built in the same order a real deck comes in
    Private Suits() As String = {"Spades", "Diamonds", "Clubs", "Hearts"}
    Private Rank() As Integer = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}

    ' useful for blackjack
    Private Const Ace As Integer = 1

    ' freshly opened pack where they are in order.  this is reused rather 
    ' than building a new deck each time
    Private freshDeck As List(Of Card)

    ' shuffled deck; Stack prevents any bugs from a botched counter var
    Private shoe As Stack(Of Card)

    ' using an imagelist but My.Resources could work depending on card names
    Private imglist As ImageList

    ' the GAME object passes us the imagelist holding the card pics
    Public Sub New(imgs As ImageList)     ' ctor
        ' new random ONCE
        rand = New Random
        imglist = imgs
        NewDeck()
    End Sub

    ' create a new deck (done ONCE) but could be called again 
    Private Sub NewDeck()
        freshDeck = New List(Of Card)      ' new object

        For Each s As String In Suits
            For Each n As Integer In Rank
                Dim key As String = CardKey(s, n)

                freshDeck.Add(New Card(s, n, imglist.Images(key)))
            Next
        Next
    End Sub

    Private keys() As String = {"J", "Q", "K"}

    Private Function CardKey(suit As String, rank As Integer) As String
        ' convert Suit / Key to the key used in the imglist
        ' (e.g C1.JPG for Clubs, Ace)
        ' cards come from http://www.jfitz.com/cards/
        ' use the windows set (or rename them all)

        Dim key As String = suit.Substring(0, 1)   ' => C, H, D, S
        If rank < 11 Then
            key &= rank.ToString
        Else
            key &= keys(rank - 11)      ' cvt 11, 12, 13 => J, Q, K
        End If

        Return key & ".png"
    End Function

    ' Shuffle deck using Fisher-Yates; sub optimal here since we "use up"
    ' the shoe each hand and are not reshuffling a deck
    Public Sub Shuffle()
        ' new temp deck preserves the new deck starting point
        Dim thisDeck As New List(Of Card)(freshDeck.ToArray)
        Dim tmp As Card

        Dim j As Integer
        ' hi to low, so the rand pick result is meaningful
        ' lo to hi introduces a definite bias
        For i As Integer = thisDeck.Count - 1 To 0 Step -1
            j = rand.Next(0, i + 1)        ' NB max param is EXCLUSIVE

            tmp = thisDeck(j)
            ' swap Card j and Card i 
            thisDeck(j) = thisDeck(i)
            thisDeck(i) = tmp
        Next

        ' using a stack for the actual deck in use; copy shuffled deck to the Shoe
        shoe = New Stack(Of Card)(thisDeck.ToArray)

    End Sub

    ' shuffle using random and LINQ (neo's answer)
    Public Sub ShuffleLinq()
        ' using the same rand per app run may be random enough
        ' but would not suffice for most 'serious' games or standards
        shoe = New Stack(Of Card)(freshDeck.OrderBy(Function() rand.Next))

    End Sub

    Public Function DealCard() As Card
        ' get a card
        If shoe.Count = 0 Then
            ' ToDo: out of cards
            ' happens with 9+ handed, 7 card games and many hi-lo games...
            ' usually mucked and burn cards are reshuffled
            ' some games use shared cards at the end
            ' (muck/burn list not implemented)
        End If
        Return shoe.Pop
    End Function

End Class

您应该开始尝试学习概念,而不是简单地寻找要粘贴的代码(即使只是学习您想要/需要了解更多有关的概念名称:类、枚举、集合、对象、方法...)。上面的内容比简单的数组要复杂得多,但如果你研究它,你会发现CardDeck 模仿了真实世界的版本。套牌自己构建,所以我们只需要在其他地方使用它。

接下来是一个保存纸牌的玩家类和一个用于实施游戏规则、发牌和控制顺序的游戏类(这些都留给学生完成)。这导致表单中几乎没有代码,只有一些对 Game(并且只有 Game)的调用,而 Game 又使用 Deck 和 Player、控制回合、给玩家卡片等。例如:

Private poker As Game
...
New Game(theImgList, 3)     ' 3 == the human player

随机播放按钮:

    poker.ShuffleDeck()
    poker.NewHand()
    thisRound = Game.Rounds.HoleCards

成交按钮:

    Select Case thisRound
        Case Game.Rounds.HoleCards
            poker.NewHand()                ' clears the display etc
            poker.DealRound(thisRound)     ' deal cards
            thisRound = Game.Rounds.Flop   ' change round indicator

        Case Game.Rounds.Flop             ' even this could be internal to Game(poker)
            poker.DealRound(thisRound)     
            thisRound = Game.Rounds.Turn

在 Game.DealRound 中:

    Case Rounds.Flop
        myDeck.DealCard()            ' burn card
        players(0).AddCard(myDeck.DealCard)  ' Player(0) is the house or community
        players(0).AddCard(myDeck.DealCard)
        players(0).AddCard(myDeck.DealCard)

使用类,表单不知道也不关心任何事情是如何发生的(比如哪个 suffle 方法),只是在请求时发生。德州扑克游戏,公共牌由拥有IsHouse 属性的玩家(0) 和IsHuman 的其他玩家持有(基本上他们的牌总是显示):

.o0(是的,“乔恩”全力以赴,请全力以赴。)
而且我绝对希望看到“Neo”出现“6”。绝对是“Neo”的“6”。

【讨论】:

    【解决方案2】:

    您需要预先生成整副牌(52 张牌),将其存储在 List/Stack/Queue 中,并在需要时将一张牌发给玩家。

    双循环应该足以顺序生成卡片,然后按随机数排序:

    Dim Suits() As String = {"S", "D", "C", "H"}
    Dim Faces() As String = {"2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"}
    
    Dim cards As New List(Of String)
    For Each s As String In Suits
      For Each f As String In Faces
        cards.Add(s & f)
      Next
    Next
    
    Dim r As New Random
    Dim cardsShuffled = cards.OrderBy(Function() r.Next)
    

    编辑:以下是填充标签的方法(只是其中一种方法):

    Dim deck As New Stack(Of String)(cardsShuffled)
    For Each lbl As Label in {Label1, Label2, Label3, ...} 'you need to write all
      Try
        lbl.Text = deck.Pop()
      Catch ex As InvalidOperationException
        MessageBox.Show("No more cards.")
      End Try      
    Next
    

    参考:

    一个合适的解决方案是动态创建标签,但首先要确保你可以让它工作。重构通常在你有一个可以工作的产品之后进行。

    【讨论】:

    • 它是说变量“s”将一个变量隐藏在一个封闭的框中。
    • @jimmy:那就叫它suit
    • 好的,它可以工作,但是当点击交易 btn 时它仍然在同一个 lbl 上而不是不同的 lbls
    • @jimmy:在可用标签上创建一个 for 循环,并为每个标签分配一张发牌,或者更好的是,为每个玩家的手牌创建一个标签数组,然后循环 i = 0 to X
    • @jimmy:如果我的回答对您有帮助,请不要忘记接受。
    猜你喜欢
    • 2017-05-16
    • 1970-01-01
    • 1970-01-01
    • 2018-11-19
    • 1970-01-01
    • 2021-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多