用Visual Basic.NET編寫撲克牌遊戲

來源:互聯網
上載者:User
visual

  撲克遊戲林林總總,同一種遊戲各地玩法亦不盡相同。編程愛好者多喜歡編寫一些本地玩法的撲克遊戲。那麼,編寫自己的撲克遊戲該從何處入手呢?

  撲克遊戲編程關鍵有兩點:一是撲克牌面的繪製;二是撲克遊戲規則的演算法實現。初學撲克遊戲編程的愛好者可從一些簡單的遊戲、借用一些現有資源開始。本文擬借用Windows內建的Cards.dll和簡單的21點遊戲為例,介紹撲克遊戲編程的初步方法。

  一、 撲克牌面繪製

  Cards.dll支援Windows內建的遊戲,如Solitaire(紙牌遊戲)。如果我們知道如何使用Cards.dll中的API函數,那麼,我們就能像Windows內建的遊戲一樣繪製撲克牌面。我們需要使用其中三個基本函數:cdtInit, cdtDrawExt,和 cdtTerm。並且需要兩個變數:width和height用於初始化函數cdtInit進行初始化。下面給出這些介面函數的聲明及參數說明。

Private width As Integer = 0
Private height As Integer = 0

Declare Function cdtInit Lib "cards.dll" (ByRef width As Integer, _
ByRef height As Integer) As Boolean

  參數說明:width,height返回牌預設寬和高,單位為pixels。

Declare Function cdtDrawExt Lib "cards.dll" (ByVal hdc As IntPtr, _
ByVal x As Integer, ByVal y As Integer, ByVal dx As Integer, _
ByVal dy As Integer, ByVal card As Integer, _
ByVal mode As Integer, ByVal color As Long) As Boolean

  參數說明:hdc(handle to a device context)控制代碼;

  x,y指定牌左上方座標位;
  dx,dy指定牌寬和高;
  card需要繪製的牌,0-51[A(草花、方塊、紅桃、黑桃),2,…,K];53-65牌背面;
  mode 指定繪製方式,牌面向上為0,牌面向下為1;
  color 指定背景色。
 
Declare Sub cdtTerm Lib "cards.dll" ()

  無參數。

  我們需要在遊戲開始時調用cdtInit對cards.dll進行初始化,這樣我們才能使用cards.dll中的cdtDrawEx等函數;每繪製一張牌,我們都要調一次cdtDrawExt函數;當我們結束遊戲時,調用一次cdtTerm以結束cards.dll的使用。

  二、 遊戲規則的演算法實現

  二十一點遊戲是玩家要取得比莊家更大的點數總和,但點數超過二十一點即為爆牌,並輸掉注碼。J、Q、K算10點,A可算1點或11點,其餘按牌面值計點數。“BlackJack”是由一張A和J、Q、K或10所組成。開始時每人發兩張牌,一張明,一張暗,凡點數不足二十一點,可選擇博牌。如果首兩張牌是對子可選擇分牌。

  為簡化起見,程式中只有兩個玩家Dealer和Player,都發明牌,無下注過程,不記錄輸贏,不支援分牌和加倍等。二十一點遊戲中,一張牌只要有四個屬性說明:Face牌面大小、Suit牌面花色,Count點數,FaceUp牌面是否向上。因此,這裡我們不用Card 類而用Card結構。

Structure card

Public face As Integer

Public suit As Integer

Public count As Integer

Public faceup As Boolean

End Structure

  遊戲開始時,我們首先要取一副牌,然後將牌洗好,指定從第幾張牌開始發起。洗牌時為取得真正的隨機數,用My.Computer.Clock.TickCount作產生隨機數的種子。

Dim Deck() As card

Deck = New card(51) {}

Dim TopCard As Integer

Private Sub GetDeck()
 Dim i, j As Integer
 For i = 0 To 3
  For j = 0 To 12
   Deck(j + 13 * i).face = j
   Deck(j + 13 * i).suit = i
   If j < 10 Then
    Deck(j + 13 * i).count = j + 1
   Else
    Deck(j + 13 * i).count = 10
   End If
   Deck(j + 13 * i).faceup = False
  Next
 Next
End Sub

Private Sub Shuffle()
 Dim i, j, k As Integer
 Dim tc As card
 For k = 1 To 500
  i = CType(My.Computer.Clock.TickCount * Rnd(), Integer) Mod 52
  j = CType(Int(Rnd() * 52), Integer)
  tc = Deck(i)
  Deck(i) = Deck(j)
  Deck(j) = tc
 Next
 topcard = 0
End Sub

  遊戲介面中,我們設定三個命令按鈕,兩個標籤。Button1為“發牌”、Button2為“要牌”、Button3為“停牌”。Label1記錄莊家點數,Label2記錄玩家點數。遊戲過程中,如果一副牌發完,立即重洗一副牌,並彈出訊息對話方塊告知。以下列出三個按鈕單擊事件代碼。其中莊家遊戲過程中,為簡化起見,未曾使用遊戲技巧。

Dim playerCount As Integer = 0
Dim playerAce As Integer = 0
Dim dealerCount As Integer = 0
Dim dealerAce As Integer = 0
Dim ipcard, idcard As Integer

Private Sub delay(ByVal dt As Integer)
 Dim t As Integer
 t = My.Computer.Clock.TickCount
 Do
  If My.Computer.Clock.TickCount >= t + dt Then Exit Do
 Loop
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

 Button1.Visible = False
 Label1.Text=””
 Label2.Text=””
 Label1.Refresh()
 Label2.Refresh()
 MyBase.CreateGraphics.Clear(Color.DarkGreen)
 dealerAce = 0
 playerAce = 0
 dealerCount = 0
 playerCount = 0

 cdtDrawExt(MyBase.CreateGraphics.GetHdc, 200, 200, 75, 100, (Deck(TopCard).face * 4 + Deck(TopCard).suit), 0, 0)

 playerCount += Deck(TopCard).count

 If Deck(TopCard).face = 0 Then playerCount += 10 : playerAce += 1
 TopCard += 1
 If TopCard >= 52 Then Shuffle() : MsgBox("NEW DECK!")
 Label2.Text = playerCount.ToString
 Label2.Refresh()
 delay(1000)

 cdtDrawExt(MyBase.CreateGraphics.GetHdc, 200, 10, 75, 100, (Deck(TopCard).face * 4 + Deck(TopCard).suit), 0, 0)

 dealerCount += Deck(TopCard).count

 If Deck(TopCard).face = 0 Then dealerCount += 10 : dealerAce += 1
 TopCard += 1
 If TopCard >= 52 Then Shuffle() : MsgBox("NEW DECK!")
 Label1.Text = dealerCount.ToString
 Label1.Refresh()
 delay(1000)

 cdtDrawExt(MyBase.CreateGraphics.GetHdc, 220, 200, 75, 100, (Deck(TopCard).face * 4 + Deck(TopCard).suit), 0, 0)

 playerCount += Deck(TopCard).count

 If Deck(TopCard).face = 0 And playerAce = 0 Then playerCount += 10 : playerAce += 1
 TopCard += 1
 If TopCard >= 52 Then Shuffle() : MsgBox("NEW DECK!")
 Label2.Text = playerCount.ToString
 Label2.Refresh()
 delay(1000)

 cdtDrawExt(MyBase.CreateGraphics.GetHdc, 220, 10, 75, 100, (Deck(TopCard).face * 4 + Deck(TopCard).suit), 0, 0)

 dealerCount += Deck(TopCard).count

 If Deck(TopCard).face = 0 And dealerAce = 0 Then dealerCount += 10 : dealerAce += 1
 TopCard += 1
 If TopCard >= 52 Then Shuffle() : MsgBox("NEW DECK!")
 Label1.Text = dealerCount.ToString
 Label1.Refresh()
 delay(1000)
 ipcard = 2
 idcard = 2
 Button2.Visible = True
 Button3.Visible = True
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

 cdtDrawExt(MyBase.CreateGraphics.GetHdc, 200 + 20 * ipcard, 200, 75, 100, (Deck(TopCard).face * 4 + Deck(TopCard).suit), 0, 0)

 playerCount += Deck(TopCard).count

 If Deck(TopCard).face = 0 Then playerCount += 10 : playerAce += 1
 TopCard += 1
 If TopCard >= 52 Then Shuffle() : MsgBox("NEW DECK!")
 ipcard += 1
 Label2.Text = playerCount.ToString
 Label2.Refresh()

 If playerCount > 21 Then
  If playerAce >= 1 Then
   playerCount -= 10
   playerAce -= 1
   Label2.Text = playerCount.ToString
   Label2.Refresh()
  Else
   MsgBox("Player loss!")
   Button1.Visible = True
   Button2.Visible = False
   Button3.Visible = False
  End If
 End If
End Sub

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
 Button2.Visible = False
 Button3.Visible = False
 dealERPlay()
End Sub

Private Sub dealerPlay()
 Do
  If dealerCount < 17 Then
   cdtDrawExt(MyBase.CreateGraphics.GetHdc, 200 + 20 * idcard, 10, 75, 100, (Deck(TopCard).face * 4 + Deck(TopCard).suit), 0, 0)
   dealerCount += Deck(TopCard).count
  If dealerCount > 21 And dealerAce = 1 Then dealerCount -= 10 : dealerAce -= 1
  If Deck(TopCard).face = 0 And dealerCount <= 11 Then dealerCount += 10
  TopCard += 1
  If TopCard >= 52 Then Shuffle() : MsgBox("NEW DECK!")
  idcard += 1
 Else
  Exit Do
 End If
Loop

Label1.Text = dealerCount.ToString
Label1.Refresh()
If dealerCount <= 21 Then
 If playerCount > dealerCount Then
  MsgBox("Player win!")
 Else
  MsgBox("Dealer win!")
 End If
Else
 MsgBox("Player win!")
End If

Button1.Visible = True
Button2.Visible = False
Button3.Visible = False

End Sub

  運行結果如下圖所示:

  三、 實踐與提高

  上述編程中,我們用了結構描述Card,對Card的Face取值(A,2,…,K)和Suit取值(Club,Diamond,Heart,Spade)用了數值0-12和0-3表示。遊戲規則也作了簡化,只有兩個玩家,也未對玩家屬性(如:財富、下注、所持牌、持牌點數等)進行描述。實踐表明,較好的方法是用Card、player類,Face和Suit用枚舉型資料。這些,我們可以在編程中逐步地添加完善。

  隨著編程實踐的深入,我們的經驗也會隨之豐富起來。如何寫一系列的類去支援各式遊戲(包括升級、鬥地主等需要用大小王牌的遊戲)?如何記錄玩家得分?如何支援網路?如何處理網路遊戲中玩家離開?如此等等。經一個月、兩個月,一年、兩年的實踐後,你將成為行家裏手。



相關文章

Cloud Intelligence Leading the Digital Future

Alibaba Cloud ACtivate Online Conference, Nov. 20th & 21st, 2019 (UTC+08)

Register Now >

11.11 Big Sale for Cloud

Get Unbeatable Offers with up to 90% Off,Oct.24-Nov.13 (UTC+8)

Get It Now >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。