这是错误的做法:
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
您应该开始尝试学习概念,而不是简单地寻找要粘贴的代码(即使只是学习您想要/需要了解更多有关的概念名称:类、枚举、集合、对象、方法...)。上面的内容比简单的数组要复杂得多,但如果你研究它,你会发现Card 和Deck 模仿了真实世界的版本。套牌自己构建,所以我们只需要在其他地方使用它。
接下来是一个保存纸牌的玩家类和一个用于实施游戏规则、发牌和控制顺序的游戏类(这些都留给学生完成)。这导致表单中几乎没有代码,只有一些对 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”。