我如何一次一个地给玩家洗牌和发牌?

时间:2014-10-22 16:53:07

标签: .net vb.net class

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

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

2 个答案:

答案 0 :(得分:8)

这是错误的做法:

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

你可以很容易地得到重复的卡片,因为你在不知道它是否已被处理的情况下挑选这张卡片(即使在这次点击中也是如此!)。您还希望每个游戏/应用程序使用一个随机,而不是每张卡。代表卡片suit & face 工作,但它将两个重要的信息粘合在一起 - 在大多数游戏中,您稍后将需要解析它以获取该信息。

甲板由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不同。

将Rank和Suit作为个人属性,您可以测试一个玩家与另一个玩家的牌,以查看谁拥有最好的牌。这在BlackJack等游戏中很容易,因为你所关心的只是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模仿现实世界的版本。甲板在其他地方建立自己,我们只需要使用它。

接下来是持有牌的玩家类和游戏类,以实现游戏规则,交易牌和控制订单(这些留给学生完成)。这导致形式中几乎没有代码,只是一些调用游戏(并且只有游戏),后者又使用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)

使用类,表单不知道或关心任何事情发生(比如哪种双重方法),只是在请求时发生。德州HoldEm游戏,社区卡由持有IsHouse财产的玩家(0)和其他IsHuman玩家持有(基本上他们的卡总是显示):

enter image description here

.o0(是的,“Jon”全力以赴,请全力以赴。)
我肯定希望看到“Neo”出现'6'。绝对是“Neo”的'6'。

答案 1 :(得分:1)

您需要预先生成整个牌组(52张牌),将其存储在列表/堆栈/队列中,并在需要时将其交给玩家。

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

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

参考:

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