• Thứ Tư, 22/09/2010 09:21 (GMT+7)

    Chương trình Carô chơi qua mạng

    Nguyễn Văn HIệp
    Chương trình viết bằng ngôn ngữ Visual Basic 6, cho phép 2 người chơi trên 2 máy tính khác nhau thông qua mạng.

    Chương trình cho 2 người chơi carô trên 2 máy tính khác nhau trong 1 mạng là 1 ứng dụng mạng. Thường 1 ứng dụng mạng dùng mô hình client-server để hoạt động. Với mô hình client-server, 1 ứng dụng mạng gồm 2 module độc lập chạy trên 2 máy: module client và module server. Module Client và module Server sẽ kết nối với nhau bằng 1 cầu nối (phương tiện truyền tin), khi cần, module client sẽ gởi 1 thông báo “request” tới module server để nhờ server phục vụ. Sau khi nhận 1 request từ module client, module server sẽ thực hiện rồi gởi kết quả về module client bằng 1 thông báo “reply”. Khi nào client/server không muốn giao tiếp với đối tác nữa thì nó sẽ đóng cầu nối lại.

    Vấn đề thiết yếu nhất khi viết 1 ứng dụng mạng là định nghĩa được tập các thông báo request/reply mà client/server sẽ dùng trong giao tiếp với nhau. Phụ thuộc vào chức năng và tính chất hoạt động của ứng dụng mà giao thức sẽ ra sao. Thí dụ, sau khi phân tích chức năng của trò chơi carô, ta có thể định nghĩa giao thức làm việc tối giản cho ứng dụng này như sau:

    Client có thể dùng 1 trong 2 thông báo request sau:
     

    -         “Restart” để yêu cầu server khởi động lại trò chơi hầu chơi ván mới.

    -
             “x,y” để thông báo tọa độ của cell mà người dùng trên máy client vừa chọn.
     

    Còn Server có thể dùng 1 trong 3 thông báo reply sau :
     

    -         “Accepted” để thông báo cho client biết mình đã chấp nhận yêu cầu kết nối của client và sẵn sàng phục vụ yêu cầu từ client.
     

    -         “Restart” để yêu cầu client khởi động lại trò chơi hầu chơi ván mới.
     

    -         “x,y” để thông báo tọa độ của cell mà người dùng trên máy server vừa chọn.
     

    Khi viết ứng dụng mạng bằng ngôn ngữ VB 6.0, cách dễ dàng nhất là dùng điều khiển ActiveX của Microsoft có tên là Winsock. Điều khiển Winsock có thể hoạt động ở 1 trong 2 chế độ: winsock client hay winsock server. Winsock Server có thể giao tiếp với nhiều client đồng thời, còn winsock client thì chỉ có thể giao tiếp với 1 server tại từng thời điểm. 
     

    Để demo rõ ràng cụ thể, chúng tôi xây dựng ứng dụng (ở mức đơn giản nhất) cho 2 người trên 2 máy chơi carô, người chơi trên server sẽ đi trước với ký hiệu “O”, người chơi trên client sẽ đi sau với ký hiệu “X”. Sau đây là phát họa thuật giải của module server:
     

    1. thiết lập các thông số hoạt động cho điều khiển winsock server, chờ và lắng nghe yêu cầu kết nối từ client…
     

    2. khi client yêu cầu kết nối thì chấp thuận rồi gởi reply “Accepted” về client để báo sẵn sàng. 
     

    3. chờ người dùng ấn chuột vào vị trí chơi, kiểm tra tính hợp lệ, nếu hợp lệ sẽ hiển thị ký hiệu “O” vào vị trí và gởi thông báo “x,y” về client biết rồi kiểm tra xem server thắng chưa, nếu chưa thì chờ client chơi. Nếu server thắng thì dừng trò chơi và chờ yêu cầu chơi ván khác từ người dùng trên server hay trên client. 
     

    4. khi người dùng client đi xong, server sẽ nhận được thông báo “x,y” từ client gởi tới, server sẽ hiển thị ký hiệu “X” vào vị trí x,y, kiểm tra xem client thắng chưa, nếu chưa thì quay về bước 3. Nều client thắng thì dừng trò chơi và chờ yêu cầu chơi ván khác từ người dùng trên server hay trên client.
     

    Tương tự, sau đây là phát họa thuật giải của module client:
     

    1. yêu cầu người dùng cung cấp địa chỉ máy server cần giao tiếp, thiết lập các thông số hoạt động cho điều khiển winsock client, gọi tác vụ Connect của winsock client đế yêu cầu nối kết với server.
     

    2. chờ đợi, khi nhận được reply “Accepted” từ server gởi về, client bắt đầu hoạt động. Theo qui ước ở trên, client sẽ đi sau.
     

    3. client chờ server đi.
     

    4. khi nhận được thông báo “x,y” từ server gởi tới, client sẽ hiển thị ký hiệu “O” vào vị trí x,y, kiểm tra xem server thắng chưa. Nếu server thắng thì dừng trò chơi và chờ yêu cầu chơi ván khác từ người dùng trên server hay trên client.
     

    5. chờ người dùng ấn chuột vào vị trí chơi, kiểm tra tính hợp lệ, nếu hợp lệ sẽ hiển thị ký hiệu “X” vào vị trí và gởi thông báo “x,y” về server biết rồi kiểm tra xem client thắng chưa, nếu chưa thì quay về bước 3. Nếu client thắng thì dừng trò chơi và chờ yêu cầu chơi ván khác từ người dùng trên server hay trên client.  
     

    Dựa vào thuật giải được phát họa ở trên, ta sẽ hiện thực 2 module client và server để chúng thực hiện đúng theo thuật giải đã phát họa.

     

    Qui trình vẽ các ảnh bitmap
     

    Bàn cờ carô gồm nhiều ô cờ, mỗi ô cờ sẽ ở 1 trong 5 trạng thái sau : trống chưa đi, quân O đi, quân X đi, quân O thắng, quân X thắng. Dùng trình soạn thảo ảnh bitmap (Paint, CorelDraw, PhotoShop,...) vẽ 5 ảnh bitmap với kích thước bằng nhau (16*16) và lưu lên thành 5 file null.jpg, O.jpg, X.jpg, Ob.jpg, Xb.jpg.

     

    Qui trình xây dựng module CaroServer bằng VB 6.0
     

    1. chạy VB 6.0, tạo Propject "Standard EXE".
     

    2. chọn menu Project.Components để hiển thị cửa sổ Components, duyệt tìm và chọn 2 mục “Microsoft Winsock Control 6.0” và “Microsoft Windows Common Control x.0” để “add” chúng vào cửa sổ ToolBox của Project.
     

    3. Thiết kế Form cho ứng dụng CaroServer như sau:

    Form Server có 3 label, 1 đối tượng ImageList, 1 đối tượng Winsock và 1 menu bar. Đặt tên cho 3 label lần lượt là lblState, lblPrompt1, lblPrompt2, tên cho ImageList là imgList, tên cho winsock là ServerSock. Để thiết kế menu bar, chọn menu Tools.Menu Editor rồi đặc tả 1 menu pop-up có tiêu đề “Thi hành lệnh…”, menu pop-up này chứa 2 option “Chơi lại ván khác” và “Dừng chương trình”. Đặt tên cho 2 option lần lượt là mnuExecPlay, menuExecQuit.
     

    4. Thiết lập dữ liệu cho đối tượng ImageList : ấn phải chuột trên đối tượng ImageList rồi chọn mục Properties để hiển thị cửa sổ thuộc tính của đối tượng này. Chọn tag General, chọn option Custom, nhập độ rộng, độ cao của các ảnh miêu tả ô cờ. Chọn tag Images rồi chọn button "Insert Picture" để thêm từng file ảnh ô cờ vào. Lưu ý các file ảnh phải được thêm vào theo thứ tự sau: 1. null.jpg, 2. O.jpg, 3. X.jpg, 4. Ob.jpg, 5. Xb.jpg để tương thích với chỉ số được dùng trong code của chương trình dưới đây.
     

    5. chọn menu View.Code để hiển thị cửa sổ soạn code cho form rồi viết đoạn code VB 6.0 sau đây:
     

    Option Explicit
     

    'Định nghĩa các hằng gợi nhớ được dùng
     

    Private Const SID = 1 'mã nhận dạng người chơi ở server
     

    Private Const CID = 2 'mã nhận dạng người chơi ở client
     

    Private Const BLANC_IMG = 0 'mã ảnh miêu tả cell trống
     

    Private Const O_IMG = 1            'mã ảnh miêu tả cell O
     

    Private Const X_IMG = 2 'mã ảnh miêu tả cell X
     

    Private Const WO_IMG = 3 'mã ảnh miêu tả cell O thắng
     

    Private Const WX_IMG = 4 'mã ảnh miêu tả cell X thắng

    'Định nghĩa các biến được dùng
     

    Private Board() As Integer  'Ma trận tráng thái các ô
     

    Private intRowsBoard As Integer 'số lượng hàng
     

    Private intColsBoard As Integer 'số lượng cột
     

    'Các biến miêu tả vị trí 5 ô thắng
     

    Private WinRow As Integer, WinRStep As Integer
     

    Private WinCol As Integer, WinCStep As Integer
     

    'Các biến miêu tả tọa độ góc trên trái bàn cờ
     

    Private intBaseX As Integer, intBaseY As Integer
     

    'Các biến miêu tả kích thước từng ô cờ
     

    Private intCellWidth As Integer, intCellHeight As Integer
     

    'biến miêu tả trạng thái hoạt động
     

    Dim curState As Integer
     

    'biến miêu tả mã người thắng cuộc
     

    Dim WinID As Integer

     
    '1. thủ tục thiết lập các thông số ban đầu
     

    Private Sub Form_Load()
     

    Dim row As Integer, col As Integer
     

      intRowsBoard = 20
     

      intColsBoard = 20
     

      intCellWidth = 15
     

      intCellHeight = 15
     

      intBaseX = 4
     

      intBaseY = 70
     

      'thiết lập lại kích thước form cho phù hợp
     

      Me.ScaleMode = vbPixels
     

      Me.Width = Me.ScaleX(intColsBoard * intCellWidth + intBaseX + 16, vbPixels, vbTwips)
     

      Me.Height = Me.ScaleY(intRowsBoard * intCellHeight + intBaseY + 65, vbPixels, vbTwips)
     

      ReDim Board(intRowsBoard - 1, intColsBoard - 1)
     

      InitBoard
     

      'hiển thị các thông báo cần thiết
     

      lblState = "Đang chờ Client kết nối..."
     

      lblPrompt1 = "Quân của bạn là O, quân của đối thủ là X"
     

      lblPrompt2 = "Bạn hãy chờ đợi...."
     

      'thiết lập port giao tiếp cho Server socket
     

      ServerSock.LocalPort = 1001 'giá trị từ 0-65535
     

      'chờ client kết nối tới
     

      ServerSock.Listen
     

    End Sub

     

    'thủ tục khởi tạo trạng thái bàn cờ
     

    Private Sub InitBoard()
     

    Dim row As Integer, col As Integer
     

      'thiết lập trạng thái chưa chơi
     

      curState = 0
     

      For row = 0 To intRowsBoard - 1
     

        For col = 0 To intColsBoard - 1
     

          Board(row, col) = 0
     

        Next col
     

      Next row
     

      'hiển thị bàn cờ trống ban đầu
     

      Form_Paint
     

    End Sub

     

    'thủ tục hiển thị bàn cờ
     

    Private Sub Form_Paint()
     

    Dim row As Integer, col As Integer
     

      For row = 0 To intRowsBoard - 1
     

        For col = 0 To intColsBoard - 1
     

          DisplayElem row, col, Board(row, col)
     

        Next col
     

      Next row
     

    End Sub

     

    '3. Thủ tục xử lý ấn chuột trên Form
     

    Private Sub Form_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)


    Dim row As Integer, col As Integer


      'nếu chưa đến lượt thì chưa cho phép đi


      If curState <> SID Then Exit Sub


      'kiểm tra vị trí ấn chuột nằm trong bàn cờ ?


      If intBaseX > x Or x > intBaseX + intColsBoard * intCellWidth Or _


         intBaseY > y Or y > intBaseY + intRowsBoard * intCellHeight Then Exit Sub


      'Xác định vị trí hàng, cột của ô cờ được ấn


      col = (x - intBaseX) \ intCellWidth


      row = (y - intBaseY) \ intCellHeight


      'nếu ô cờ đã chơi rồi thì không xử lý nữa


      If Board(row, col) <> 0 Then Exit Sub


      'ghi nhận mã người chơi vào ô cờ


      Board(row, col) = curState


      'hiển thị chữ O vào ô cờ


      DisplayElem row, col, curState
     

      'gởi tọa độ x,y của ô cờ về cho Client biết
     

      ServerSock.SendData row & "," & col
     

      'kiểm tra người chơi trên máy server thắng chưa?
     

      If KiemtraThang(row, col, curState) Then
     

         WinID = curState
     

         curState = 0
     

         FlashDisplay (WinID)
     

         MsgBox ("Hoan hô! Bạn đã thắng rồi.")
     

         lblPrompt2 = "Bạn hãy chọn option Chơi lại ván khác"

         Exit Sub

      End If

      'chuyển quyền chơi về cho Client

      curState = CID


      lblPrompt2 = "Bạn hãy đợi đối thủ đi..."


    End Sub

     

    'Hàm kiểm tra người chơi có mã id đã thắng chưa?


    Public Function KiemtraThang(h As Integer, c As Integer, ByVal id As Integer) As Boolean


    Dim count As Integer


    Dim col As Integer, row As Integer


      'kiểm tra các ô nằm ngang ở hàng h


      count = 1


      col = c + 1


      While col < intColsBoard And Board(h, col) = id


         count = count + 1


         col = col + 1

      Wend

      col = c - 1

      While col >= 0 And Board(h, col) = id

         count = count + 1

         col = col - 1

      Wend

      If count >= 5 Then

         WinRow = h: WinCol = col + 1

         WinRStep = 0: WinCStep = 1

         KiemtraThang = True

         Exit Function

      End If

      'kiểm tra các ô dọc ở cột c

      count = 1

      row = h + 1

      While row < intRowsBoard And Board(row, c) = id

         count = count + 1

         row = row + 1

      Wend

      row = h - 1

      While row >= 0 And Board(row, c) = id

         count = count + 1

         row = row - 1

      Wend

      If count >= 5 Then

        WinRow = row + 1: WinCol = c

         WinRStep = 1: WinCStep = 0

       KiemtraThang = True

         Exit Function

      End If

      'kiểm tra các ô xéo từ trên trái xuống dưới phải

      count = 1

      row = h + 1: col = c + 1

      While row < intRowsBoard And col < intColsBoard And Board(row, col) = id

         count = count + 1

         row = row + 1: col = col + 1

      Wend

      row = h - 1: col = c - 1

      While row >= 0 And col >= 0 And Board(row, col) = id

         count = count + 1

         row = row - 1: col = col - 1

      Wend

      If count >= 5 Then

        WinRow = row + 1: WinCol = col + 1

         WinRStep = 1: WinCStep = 1

         KiemtraThang = True

         Exit Function

      End If

      'kiểm tra các ô xéo từ trên phải xuống dưới trái

      count = 1

      row = h + 1: col = c - 1

      While row < intRowsBoard And col >= 0 And Board(row, col) = id

         count = count + 1

         row = row + 1: col = col - 1

      Wend

      row = h - 1: col = c + 1

      While row >= 0 And col < intColsBoard And Board(row, col) = id

         count = count + 1

         row = row - 1: col = col + 1

      Wend

      If count >= 5 Then

        WinRow = row + 1: WinCol = col - 1

         WinRStep = 1: WinCStep = -1

         KiemtraThang = True

         Exit Function

      End If

      'nếu chạy tới đây thì người chơi id chưa thắng

      KiemtraThang = False

    End Function 

    'Thủ tục hiển thị 5 ô cờ thắng

    Public Sub FlashDisplay(ByVal id As Integer)

    Dim i As Integer

      For i = 0 To 4

        If id = CID Then

          DisplayElem WinRow + WinRStep * i, WinCol + WinCStep * i, WX_IMG

        Else

          DisplayElem WinRow + WinRStep * i, WinCol + WinCStep * i, WO_IMG

        End If

      Next i

    End Sub

     

    'Thủ tục hiển thị ô cờ có mã imgCode ở vị trí(row,col)

    Private Sub DisplayElem(row As Integer, col As Integer, imgCode As Integer)

    Dim x As Integer, y As Integer

    Dim curPic As Object

      'xác định tọa độ x,y theo đơn vị pixcel từ tọa độ row,col luận lý

      x = intBaseX + col * intCellWidth

      y = intBaseY + row * intCellHeight

      'hiển thị ảnh bitmap ở vị trí xác định

      PaintPicture ImgList.ListImages.Item(imgCode + 1).Picture, x, y, intCellWidth, intCellHeight, 0, 0, , , vbSrcCopy

    End Sub

    'Thủ tục xử lý option "Chơi lại ván khác"

    Private Sub mnuExecPlay_Click()

      'khởi động lại bàn cờ

      InitBoard

      'gởi reply "Restart" về cho client biết

      ServerSock.SendData "Restart"

      'chuyển quyền ban đầu về người chơi ở Server

      curState = SID

      'hiển thị thông báo cho người dùng biết

      lblPrompt2 = "Chơi lại từ đầu. Bạn hãy ấn chuột vào cell cần đi"

    End Sub

     

    'Thủ tục xử lý option "Dừng chương trình"

    Private Sub mnuExecQuit_Click()

      'chưa hiện thực, người chơi chỉ cần click chuột vào icon X

    End Sub

     

    '2. Thủ tục xử lý sự kiện yêu cầu kết nối từ client

    Private Sub ServerSock_ConnectionRequest(ByVal requestID As Long)

      If ServerSock.State <> sckClosed Then ServerSock.Close

      'Chấp nhận yêu cầu nối kết.

      ServerSock.Accept requestID

      ServerSock.SendData "Accepted"

      'Hiển thị thông báo cho người dùng biết.

      lblState = "Da ket noi voi Client. "

      lblPrompt2 = "Bạn hãy tìm và ấn chuột vào ô cờ cần đi..."

      'chuyển quyền ban đầu về người chơi ở Server

      curState = SID

    End Sub

     

    '4.Thủ tục nhận thông tin về nước đi của đối thủ

    Private Sub ServerSock_DataArrival(ByVal bytesTotal As Long)

      Dim strData As String

      Dim buf As String

      Dim pos As Integer

      Dim row As Integer, col As Integer

      'nhận dữ liệu từ client gởi tới

      ServerSock.GetData strData

      'kiểm tra xem có phải là request "Restart" ?

      If strData = "Restart" Then

        'khởi động lại bàn cờ

        InitBoard

        'chuyển quyền ban đầu về người chơi ở Server

        curState = SID

        'hiển thị thông báo cho người dùng biết

        lblPrompt2 = "Chơi lại từ đầu. Bạn hãy ấn chuột vào cell cần đi"

        Exit Sub

      End If

      'nếu chưa đến lượt người chơi ở client thì không xử lý

      If curState <> CID Then Exit Sub

      'xác định tọa độ cell do client ở về

      pos = InStr(1, strData, ",", 0)

      buf = Left(strData, pos - 1)

      row = CInt(buf)

      buf = Mid(strData, pos + 1)

      col = CInt(buf)

      'ghi nhận mã người chơi vào ô cờ

      Board(row, col) = curState

      'hiển thị chữ X vào ô cờ

      DisplayElem row, col, curState

      'kiểm tra người chơi trên máy client thắng chưa ?

      If KiemtraThang(row, col, curState) Then

         WinID = curState

         curState = 0

         FlashDisplay (WinID)

         MsgBox ("Rất tiếc. Bạn đã thua rồi.")

         lblPrompt2 = "Bạn hãy chọn option Chơi lại ván khác"

         Exit Sub

      End If

      'chuyển quyền chơi về cho server

      curState = SID

      lblPrompt2 = "Bạn hãy tìm và ấn chuột vào ô cờ cần đi..."

    End Sub

    6. Chọn menu File.Make Project1.exe và nhập tên file khả thi cần tạo ra (CaroServer) để VB dịch mã nguồn ra file khả thi của module Server.

     

    Qui trình xây dựng module CaroClient

     

    1. chạy VB 6.0, tạo Propject "Standard EXE".

     

    2. chọn menu Project.Components để hiển thị cửa sổ Components, duyệt tìm và chọn 2 mục “Microsoft Winsock Control 6.0” và “Microsoft Windows Common Control x.0” để “add” chúng vào cửa sổ ToolBox của Project. 

    3. Thiết kế Form cho ứng dụng CaroClient như sau:

    Form Client có 3 label, 1 đối tượng ImageList, 1 đối tượng Winsock và 1 menu bar. Đặt tên cho 3 label lần lượt là lblState, lblPrompt1, lblPrompt2, tên cho ImageList là imgList, tên cho winsock là ClientSock. Để thiết kế menu bar, chọn menu Tools.Menu Editor rồi đặc tả 1 menu pop-up có tiêu đề “Thi hành lệnh…”, menu pop-up này chứa 3 option : "Kết nối với server", “Chơi lại ván khác” và “Dừng chương trình”. Đặt tên cho 3 option lần lượt là mnuExecConnect, mnuExecPlay, menuExecQuit. 

    4. Thiết lập dữ liệu cho đối tượng ImageList : ấn phải chuột trên đối tượng ImageList rồi chọn mục Properties để hiển thị cửa sổ thuộc tính của đối tượng này. Chọn tag General, chọn option Custom, nhập độ rộng, độ cao của các ảnh miêu tả ô cờ. Chọn tag Images rồi chọn button "Insert Picture" để thêm từng file ảnh ô cờ vào. Lưu ý các file ảnh phải được thêm vào theo thứ tự sau: (1) null.jpg, (2) O.jpg, (3) X.jpg, (4) Ob.jpg, (5) Xb.jpg để tương thích với chỉ số được dùng trong code của chương trình dưới đây. 

    5. chọn menu View.Code để hiển thị cửa sổ soạn code cho form rồi viết đọan code VB 6.0 sau đây:

    Option Explicit

    'Định nghĩa các hằng gợi nhớ được dùng

    Private Const SID = 1 'mã nhận dạng người chơi ở server

    Private Const CID = 2 'mã nhận dạng người chơi ở client

    Private Const BLANC_IMG = 0 'mã ảnh miêu tả cell trống

    Private Const O_IMG = 1            'mã ảnh miêu tả cell O

    Private Const X_IMG = 2 'mã ảnh miêu tả cell X

    Private Const WO_IMG = 3 'mã ảnh miêu tả cell O thắng

    Private Const WX_IMG = 4 'mã ảnh miêu tả cell X thắng 

    'Định nghĩa các biến được dùng

    Private Board() As Integer  'Ma trận tráng thái các ô

    Private intRowsBoard As Integer 'số lượng hàng

    Private intColsBoard As Integer 'số lượng cột

    'Các biến miêu tả vị trí 5 ô thắng

    Private WinRow As Integer, WinRStep As Integer

    Private WinCol As Integer, WinCStep As Integer

    'Các biến miêu tả tọa độ góc trên trái bàn cờ

    Private intBaseX As Integer, intBaseY As Integer

    'Các biến miêu tả kích thước từng ô cờ

    Private intCellWidth As Integer, intCellHeight As Integer

    'biến miêu tả trạng thái hoạt động

    Dim curState As Integer

    'biến miêu tả mã người thắng cuộc

    Dim WinID As Integer

     

    '1. thủ tục thiết lập các thông số ban đầu

    Private Sub Form_Load()

    Dim row As Integer, col As Integer

      intRowsBoard = 20

      intColsBoard = 20

      intCellWidth = 15

      intCellHeight = 15

      intBaseX = 4

      intBaseY = 70

      'thiết lập lại kích thước form cho phù hợp

      Me.ScaleMode = vbPixels

      Me.Width = Me.ScaleX(intColsBoard * intCellWidth + intBaseX + 16, vbPixels, vbTwips)

      Me.Height = Me.ScaleY(intRowsBoard * intCellHeight + intBaseY + 65, vbPixels, vbTwips)

      ReDim Board(intRowsBoard - 1, intColsBoard - 1)

      InitBoard

      'hiển thị các thông báo cần thiết

      lblState = ""

      lblPrompt1 = "Quân của bạn là X, quân của đối thủ là O"

      lblPrompt2 = "Bạn hãy yêu cầu kết nối tới server đi..."

    End Sub
     

    'thủ tục khởi tạo trạng thái bàn cờ

    Private Sub InitBoard()

    Dim row As Integer, col As Integer

      'thiết lập trạng thái chưa chơi

      curState = 0

      For row = 0 To intRowsBoard - 1

        For col = 0 To intColsBoard - 1

          Board(row, col) = 0

        Next col

      Next row

      'hiển thị bàn cờ trống ban đầu

      Form_Paint

    End Sub 

    'thủ tục hiển thị bàn cờ

    Private Sub Form_Paint()

    Dim row As Integer, col As Integer

      For row = 0 To intRowsBoard - 1

        For col = 0 To intColsBoard - 1

          DisplayElem row, col, Board(row, col)

        Next col

      Next row

    End Sub 

    '3. Thủ tục xử lý ấn chuột trên Form

    Private Sub Form_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)

    Dim row As Integer, col As Integer

      'nếu chưa đến lượt thì chưa cho phép đi

      If curState <> CID Then Exit Sub

      'kiểm tra vị trí ấn chuột nằm trong bàn cờ ?

      If intBaseX > x Or x > intBaseX + intColsBoard * intCellWidth Or _

         intBaseY > y Or y > intBaseY + intRowsBoard * intCellHeight Then Exit Sub

      'Xác định vị trí hàng, cột của ô cờ được ấn

      col = (x - intBaseX) \ intCellWidth

      row = (y - intBaseY) \ intCellHeight

      'nếu ô cờ đã chơi rồi thì không xử lý nữa

      If Board(row, col) <> 0 Then Exit Sub

      'ghi nhận mã người chơi vào ô cờ

      Board(row, col) = curState

      'hiển thị chữ O vào ô cờ

      DisplayElem row, col, curState

      'gởi tọa độ x,y của ô cờ về cho server biết

      ClientSock.SendData row & "," & col

      'kiểm tra người chơi trên máy client thắng chưa ?

      If KiemtraThang(row, col, curState) Then

         WinID = curState

         curState = 0

         FlashDisplay (WinID)

         MsgBox ("Hoan hô! Bạn đã thắng rồi.")

         lblPrompt2 = "Bạn hãy chọn option Chơi lại ván khác"

         Exit Sub

      End If

      'chuyển quyền chơi về cho Server

      curState = SID

      lblPrompt2 = "Bạn hãy đợi đối thủ đi..."

    End Sub 

    'Hàm kiểm tra người chơi có mã id đã thắng chưa?

    Public Function KiemtraThang(h As Integer, c As Integer, ByVal id As Integer) As Boolean

    Dim count As Integer

    Dim col As Integer, row As Integer

      'kiểm tra các ô nằm ngang ở hàng h

      count = 1

      col = c + 1

      While col < intColsBoard And Board(h, col) = id

         count = count + 1

         col = col + 1

      Wend

      col = c - 1

      While col >= 0 And Board(h, col) = id

         count = count + 1

         col = col - 1

      Wend

      If count >= 5 Then

         WinRow = h: WinCol = col + 1

         WinRStep = 0: WinCStep = 1

         KiemtraThang = True

         Exit Function

      End If

      'kiểm tra các ô dọc ở cột c

      count = 1

      row = h + 1

      While row < intRowsBoard And Board(row, c) = id

         count = count + 1

         row = row + 1

      Wend

      row = h - 1

      While row >= 0 And Board(row, c) = id

         count = count + 1

         row = row - 1

      Wend

      If count >= 5 Then

        WinRow = row + 1: WinCol = c

         WinRStep = 1: WinCStep = 0

       KiemtraThang = True

         Exit Function

      End If

      'kiểm tra các ô xéo từ trên trái xuống dưới phải

      count = 1

      row = h + 1: col = c + 1

      While row < intRowsBoard And col < intColsBoard And Board(row, col) = id

         count = count + 1

         row = row + 1: col = col + 1

      Wend

      row = h - 1: col = c - 1

      While row >= 0 And col >= 0 And Board(row, col) = id

         count = count + 1

         row = row - 1: col = col - 1

      Wend

      If count >= 5 Then

        WinRow = row + 1: WinCol = col + 1

         WinRStep = 1: WinCStep = 1

         KiemtraThang = True

         Exit Function

      End If

      'kiểm tra các ô xéo từ trên phải xuống dưới trái

      count = 1

      row = h + 1: col = c - 1

      While row < intRowsBoard And col >= 0 And Board(row, col) = id

         count = count + 1

         row = row + 1: col = col - 1

      Wend

      row = h - 1: col = c + 1

      While row >= 0 And col < intColsBoard And Board(row, col) = id

         count = count + 1

         row = row - 1: col = col + 1

      Wend

      If count >= 5 Then

        WinRow = row + 1: WinCol = col - 1

         WinRStep = 1: WinCStep = -1

         KiemtraThang = True

         Exit Function

      End If

      'nếu chạy tới đây thì người chơi id chưa thắng

      KiemtraThang = False

    End Function 

    'Thủ tục hiển thị 5 ô cờ thắng

    Public Sub FlashDisplay(ByVal id As Integer)

    Dim i As Integer

      For i = 0 To 4

        If id = CID Then

          DisplayElem WinRow + WinRStep * i, WinCol + WinCStep * i, WX_IMG

        Else

          DisplayElem WinRow + WinRStep * i, WinCol + WinCStep * i, WO_IMG

        End If

      Next i

    End Sub 

    'Thủ tục hiển thị ô cờ có mã imgCode ở vị trí(row,col)

    Private Sub DisplayElem(row As Integer, col As Integer, imgCode As Integer)

    Dim x As Integer, y As Integer

    Dim curPic As Object

      'xác định tọa độ x,y theo đơn vị pixcel từ tọa độ row,col luận lý

      x = intBaseX + col * intCellWidth

      y = intBaseY + row * intCellHeight

      'hiển thị ảnh bitmap ở vị trí xác định

      PaintPicture ImgList.ListImages.Item(imgCode + 1).Picture, x, y, intCellWidth, intCellHeight, 0, 0, , , vbSrcCopy

    End Sub 

    'Thủ tục xử lý option "Chơi lại ván khác"

    Private Sub mnuExecPlay_Click()

      'khởi động lại bàn cờ

      InitBoard

      'gởi reply "Restart" về cho client biết

      ClientSock.SendData "Restart"

      'chuyển quyền ban đầu về người chơi ở Server

      curState = SID

      'hiển thị thông báo cho người dùng biết

      lblState = "Đang yêu cầu server chơi lại..."

      lblPrompt2 = "Hãy chờ đợi..."

    End Sub

     

    'Thủ tục xử lý option "Dừng chương trình"

    Private Sub mnuExecQuit_Click()

      'chưa hiện thực, người chơi chỉ cần click chuột vào icon X

    End Sub

     

    'Thủ tục xử lý option "Kết nối với server"

    Private Sub mnuExecConnect_Click()

      'hiển thị form Connect

      frmConnect.Show vbModal

      'nếu người dùng chấp nhận

      If frmConnect.fOk Then

        'thiết lập thông tin về server

        ClientSock.RemoteHost = frmConnect.txtTCP

        ClientSock.RemotePort = 1001

        'yêu cầu kết nối với server

        ClientSock.Connect

        'Hiển thị thông báo cho người dùng biết.

        lblState = "Đang yêu cầu kết nối với server..."

        lblPrompt2 = "Hãy chờ đợi..."

    End If

    End Sub

     

    '4.Thủ tục nhận thông tin về nước đi của đối thủ

    Private Sub ClientSock_DataArrival(ByVal bytesTotal As Long)

      Dim strData As String

      Dim buf As String

      Dim pos As Integer

      Dim row As Integer, col As Integer

      'nhận dữ liệu từ client gởi tới

      ClientSock.GetData strData

      'kiểm tra xem có phải là request "Accepted" ?

      If strData = "Accepted" Then

        'chuyển quyền ban đầu về người chơi ở Server

        curState = SID

        'hiển thị thông báo cho người dùng biết

        lblState = "Đã kết nối tới server."

        lblPrompt2 = "Hãy chờ đối thủ đi trước..."

        Exit Sub

      End If

      'kiểm tra xem có phải là request "Restart" ?

      If strData = "Restart" Then

        'khởi động lại bàn cờ

        InitBoard

        'chuyển quyền ban đầu về người chơi ở Server

        curState = SID

        'hiển thị thông báo cho người dùng biết

        lblPrompt2 = "Chơi lại từ đầu. Hãy chờ đối thủ đi trước..."

        Exit Sub

      End If

      'nếu chưa đến lượt người chơi ở Server thì không xử lý

      If curState <> SID Then Exit Sub

      'xác định tọa độ cell do Server ở về

      pos = InStr(1, strData, ",", 0)

      buf = Left(strData, pos - 1)

      row = CInt(buf)

      buf = Mid(strData, pos + 1)

      col = CInt(buf)

      'ghi nhận mã người chơi vào ô cờ

      Board(row, col) = curState

      'hiển thị chữ O vào ô cờ

      DisplayElem row, col, curState

      'kiểm tra người chơi trên máy server thắng chưa?

      If KiemtraThang(row, col, curState) Then

         WinID = curState

         curState = 0

         FlashDisplay (WinID)

         MsgBox ("Rất tiếc. Bạn đã thua rồi.")

         lblPrompt2 = "Bạn hãy chọn option Chơi lại ván khác"

         Exit Sub

      End If

      'chuyển quyền chơi về cho server

      curState = CID

      lblPrompt2 = "Bạn hãy tìm và ấn chuột vào ô cờ cần đi..."

    End Sub
     

    6. Chọn menu Project.Add Form để hiển thị cửa sổ "Add Form". Chọn icon "Form" rồi ấn button OK để tạo 1 form trống mới. Thiết kế form mới như sau:

    Form Kết nối có 1 label, 1 textbox, 2 button. Đặt tên cho textbox là txtTCP, tên cho button Connect là btnConnect, tên cho button Cancel là btnCancel. Đặt tên cho form mới là frmConnect. Ấn kép chuột vào button OK để tạo thủ tục xử lý sự kiện Click chuột trên button này. Khi cửa sổ soạn code của form hiển thị, viết đoạn code VB 6.0 sau đây:
     

    Option Explicit
     

    Public fOk As Boolean

     

    'thủ tục xử lý button Cancel
     

    Private Sub btnCancel_Click()

      fOk = False

      Me.Visible = False

      Me.Hide

    End Sub

     

    'thủ tục xử lý button Connect

    Private Sub btnConnect_Click()

      fOk = True

      Me.Visible = False

      Me.Hide

    End Sub

     

    7. Chọn menu File.Make Project1.exe và nhập tên file khả thi cần tạo ra (CaroClient) để VB dịch mã nguồn ra file khả thi của module Client. 

    8. Sau khi đã xây dựng được 2 module client & server của ứng dụng mạng, bạn có thể cài đặt từng module vào từng máy người chơi. Ở đây, với mục đích dễ kiểm tra, bạn sẽ chạy 2 module trên cùng 1 máy, module CaroServer sẽ chạy trước, module CaroClient sẽ chạy sau. Người chơi trên CaroClient sẽ chọn option "Kết nối tới server..." để cung cấp địa chỉ máy sẽ server (localhost hay 127.0.0.1). Module CaroServer sẽ chấp nhận và yêu cầu người trên Server chơi trước rồi tới người trên Client chơi sau, cứ thế tiếp tục cho đến khi 1 trong 2 người chơi thắng hoặc khi có yêu cầu "Chơi lại ván khác" bởi 1 trong 2 người chơi. 

    ID: A1007_111