技巧區‎ > ‎高級程度‎ > ‎

過三關(Tic Tac Toe)[2002年1月]

張貼者:2010年5月29日 上午6:33Carson Cheng   [ 已更新 2010年5月29日 上午6:34 ]
這個遊戲大家還沒有上學該已學會了,但是要放在Excel裡卻不是件簡單的事情,必須掌握自訂表單(Userform)的技巧。

由於我主要想示範一下表單與Static的用法,所以沒有加進什麼 AI(人功智能),電腦不懂跟你玩,只能人與人玩,電腦提供「場地」和當評判。

首先畫一個表單,上有九個按鈕,代表九個格,用戶按一下,我們就在其上「畫」上「○」或「╳」。另外還要一個「離開」按鈕,讓用戶可以提早結束遊戲。



我想表單並不難,最難還是背後的程序:

' 過三關

' Player函數用的常數,代表各動作背後的值。參考Player函數的說明。
Const cInit = 0  ' 起始
Const cRead = 1  ' 報告當前玩家
Const cSwap = 2  ' 轉玩家

' Player函數負責記錄現在到哪一方玩家(○或╳)下棋。
'   要記錄的只是一個Boolean,對代表○,錯代表╳,其實可以把它放在一個工作表上的
' 儲存格裡,但為了一個數值而開一個工作表不是很「划算」,所以這裡用了Static,經
' Static定義的變數,只要程序在運行,它的數值就不會消失。
'   除了儲存外,這函數還要提供三個動作:起始、報告當前玩家和轉玩家,這三個動作均
' 由引數決定:
' 引數:cInit - 起始,把當前玩家設定為○(對),也就是說○先下棋
'    cRead - 報告當前玩家,如果沒有引數,這個是默認工作
'    cSwap - 轉玩家,由於只有兩個玩家,所以把Boolean的值對調就可以
' 返回:不論引數內動作為何,函數均會返回當前玩家,也就是○或╳。
'
' 注意:1) 為什麼要儲存Boolean值,而不直接儲存文字(字串)「○」或「╳」呢?
'             答案:用文字的話,在轉玩家時很麻煩,用數字或Boolean的話就簡單多了。
'             2) 這個函數是內部用的,不應該給用戶看到,所以加上「Private」字樣。
Private Function Player(Optional iAction As Integer = cRead) As String
 Static bPlayer As Boolean

 Select Case iAction
   Case Is = cInit
     bPlayer = True           ' ○先下棋
   Case Is = cSwap
     bPlayer = Not bPlayer    ' 對調
 End Select

 Player = IIf(bPlayer, "○", "╳")
End Function

' 當這自訂表格(Userform)顯示出來的時候,需要起始化(initialization)
Private Sub Userform_Activate()
 Player (cInit)                                           ' 起始
 LabelMessage.Caption = "開始!請" & Player() & "先下棋"   ' 顯示指示
End Sub

' 按動任何一個按鈕,也會執行ButtonPressed程序。
' 這裡只顯示其中一個按鈕的程式
Private Sub Button11_Click()
   ButtonPressed ("11")
End Sub

' ButtonPressed處理按鈕被鈕後的工作,包括
' 1)把當前的玩家寫在按鈕上;
' 2)決定當前玩家是否勝出;
' 3)決定遊戲是否完結(和局);
' 4)不然則繼續遊戲。
'
' 引數:HitButton - 被按按紐的座標(文字)
'
' 注意:如果按鈕上已寫有東西,那代表按鈕只是給重按,不用理會。
Private Sub ButtonPressed(HitButton As String)
 With Controls("Button" & HitButton)
   If .Caption = "" Then                         ' 按鈕上沒有寫任何東西才用理會
     .Caption = Player()                         ' 把當前的玩家寫在按鈕上

     If Win(Player()) Then                       ' 看看當前玩家有沒有勝出
       LabelMessage.Caption = Player() & "勝!"  ' 顯示適當訊息
       DisableButtons                         ' 把所有沒有選過的按鈕改為失效
     Else
       If Not GameOver() Then             ' 沒有玩家勝出的話,看看遊戲完結了沒有
         Player (cSwap)                          ' 更換當前玩家
         LabelMessage.Caption = "請" & Player() & "下棋"
       Else
         LabelMessage.Caption = "和局"    ' 九個格也選了,又沒有人勝出,就是和局
       End If
     End If
   End If
 End With
End Sub

' Win函數決定引數內的玩家有沒有勝出
' 引數:sP - 玩家
' 返回:True - 勝出;False - 沒有勝出
'
' 注意:這裡沒有用上For...Next迴圈,只是很原始地逐一方向查看玩家是否能連成一線,
'    主要是因為就算用了迴圈也不能省下多少句,反而會很複雜,這樣寫一看就懂,有
'      它的好處。
Private Function Win(sP As String) As Boolean
 Win = (Button11.Caption = sP And Button12.Caption = sP And Button13.Caption = sP) Or _
       (Button21.Caption = sP And Button22.Caption = sP And Button23.Caption = sP) Or _
       (Button31.Caption = sP And Button32.Caption = sP And Button33.Caption = sP) Or _
       (Button11.Caption = sP And Button21.Caption = sP And Button31.Caption = sP) Or _
       (Button12.Caption = sP And Button22.Caption = sP And Button32.Caption = sP) Or _
       (Button13.Caption = sP And Button23.Caption = sP And Button33.Caption = sP) Or _
       (Button11.Caption = sP And Button22.Caption = sP And Button33.Caption = sP) Or _
       (Button31.Caption = sP And Button22.Caption = sP And Button13.Caption = sP)
End Function

' DisableButtons會把所有還沒有選過(空白)的按鈕改為失效(disable),使玩家
' 在遊戲完結後不能再下棋,否則會擾亂程式。
' 不乾脆把所有按鈕改為失效,主要因為失效按鈕上的文字會給轉成陰影,看得不清楚。
Private Sub DisableButtons()
 Dim i As Integer, j As Integer

 For i = 1 To 3
   For j = 1 To 3
     If Controls("Button" & i & j).Caption = "" Then
       Controls("Button" & i & j).Enabled = False
     End If
   Next j
 Next i
End Sub

' GameOver函數看看遊戲是否已完結。如果九個按鈕都已經給選過了(按鈕不是空白),
' 那就代表和局,遊戲已經完結。
Private Function GameOver() As Boolean
 Dim bTemp As Boolean
 Dim i As Integer, j As Integer

 bTemp = True
 For i = 1 To 3
   For j = 1 To 3
     bTemp = bTemp And (Controls("Button" & i & j).Caption <> "")
   Next j
 Next i
 GameOver = bTemp
End Function

' 結束遊戲
Private Sub CommandButtonQuit_Click()
   Unload Me
End Sub

結果
執行後,○可以先下棋,只要在適當的按鈕上按一下便可以。


每走一步,Excel也會在適當的方格上「畫」上○或╳,並顯示到哪一方下棋。
  玩家可以隨時按「離開」結束遊戲。


當有一方勝出後,Excel會顯示哪一方勝出,並會把沒有選過的按鈕改為失效,不讓玩家們繼續。


如果選完九個格也沒有定勝負的話,Excel會顯示「和局」。



ċ
3_11.zip
(27k)
Carson Cheng,
2010年5月29日 上午6:34
Comments