五子棋AI循序渐进【1】实现界面和位棋盘

先把这一个传上来,关于局面评价的72向量和综合比较、超出边界的alpha-beta剪裁如何说明更清楚还得再考虑一下,以免表述的不清楚。因为这两部分的代码是整个代码中最核心最重要也是最长的。仅仅是下一集更新的源码就超过600行。当然了,逻辑是非常非常清晰的,因为很多都是重复的逻辑内容——硬编码模板就这样哎。而超出边界的alpha-beta剪裁,是整个程序中最难理解的部分,说难理解不仅是因为递归,更重要的是这种剪裁的思想。剩余的各个部分都非常好理解,编码也很少了。就像将军延伸和空步剪裁也就十行八行的代码就实现了。而静态搜索只是照着alpha-beta剪裁代码稍微一改而已。好了,不多说闲话。

注:从这一篇开始都会对实现的内容首先进行解释,然后传本集的完整源码,源码都是VB2010编写的。

一、位棋盘

1、为什么用位棋盘

按照通常我们的做法,可以用数组board(224),数据类型可以是byte,integer等,但是我们浪费很多存储空间,当然这还不是主要问题,主要问题是速度太慢。原因很简单,寻址远慢于从integer中取某一位。

2、如何实现位棋盘

我们需要一个225位的数据类型,这种长度的数据类型是没有的,所以可以用integer数组来实现。幸好,VB.NET给我们提供了bitarray类,而这个类的内部实现实际上也是用integer数组的。但是问题也随之而来:1位只能是0或者1,而我们要表示白棋、黑棋、空三种数据,怎么办?其实很好解决,可以用2字代表一个位置,或者使用2个bitarray。我的程序采取第二种办法:

    Private wBitArr As BitArray
    Private bBitArr As BitArray

3、如何操作位棋盘

直接上代码:

 

' 位棋盘
Public  Class mBitBoard
     ' 用bitarray代替byte数组,提高读写速度。(bitarray内部实现是用integer数组,每一个元素是32字节,所以寻址速度要比用byte数组快很多)
     ' 0=白方,1=黑方,2=空
     Private wBitArr  As BitArray
     Private bBitArr  As BitArray

     ' 15*15的棋盘。
     Sub  New()
        wBitArr =  New BitArray( 225)
        bBitArr =  New BitArray( 225)
     End Sub

     ' 设置棋子
     Sub [ Set](index  As  Integer, value  As  Integer)
         If value =  0  Then
            wBitArr.Set(index,  True)
         ElseIf value =  1  Then
            bBitArr.Set(index,  True)
         Else
            bBitArr.Set(index,  False)
            wBitArr.Set(index,  False)
         End  If
     End Sub

     ' 获取棋子
     Function [ Get](index  As  IntegerAs  Integer
         If wBitArr.Get(index)  Then  Return  0
         If bBitArr.Get(index)  Then  Return  1
         Return  2
     End Function

End Class

 

很清晰吧。这个类在后来进行了一些小的修改——增加了一个函数。当然这不是我们现在要讨论的问题。好了,现在已经有了棋盘的表示方法,那么我们来实现界面。其实界面简单得不能再简单了:

 

二、五子棋界面

1、搜索或者自己画棋盘和棋子

2、获取棋子偏移量、棋子大小、棋盘大小

3、根据mBitBoard实例绘制棋子

 

我实现的时候在窗体上面画了一个panel,命名为pnlBoard。而后写了这样一个函数:

    '绘制棋子
    Private Sub pnlBoard_Paint(sender As System.Object, e As System.Windows.Forms.PaintEventArgs) Handles pnlBoard.Paint
        e.Graphics.DrawImage(My.Resources._2064, Point.Empty)
        For i As Integer = 0 To 224
            If ucpcSquares.Get(i) = 1 Then e.Graphics.DrawImage(bb, New Point((i Mod 15) * cs.Height, (i \ 15) * cs.Height) + co)
            If ucpcSquares.Get(i) = 0 Then e.Graphics.DrawImage(bw, New Point((i Mod 15) * cs.Height, (i \ 15) * cs.Height) + co)
        Next
    End Sub

首先绘制棋盘图像,然后绘制棋子。

 

下子的代码是这样的:

 

    '下子
    Private Sub pnlBoard_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles pnlBoard.MouseDown
        Dim sdr = CType(sender, Panel)
        '鼠标坐标转棋盘坐标
        Dim p As Point = e.Location - co
        p.X \= cs.Width
        p.Y \= cs.Height
        '下一个白子
        If e.Button = Windows.Forms.MouseButtons.Left Then
            ucpcSquares.Set(p.Y * 15 + p.X, 0)
            '更新显示
            pnlBoard_Paint(sdr, New PaintEventArgs(sdr.CreateGraphics, sdr.DisplayRectangle))
        End If
    End Sub

很简单不是吗。

 

 

完整的代码如下:

 

Public  Class Form1
     ' 黑白棋子
     Private bb  As Bitmap
     Private bw  As Bitmap
     ' 棋子偏移
     Private co  As Point =  New Point( 55)
     ' 棋子大小
     Private cs  As Size =  New Size( 2525)
     ' 位棋盘
     Private ucpcSquares  As mBitBoard

     Private  Sub Form1_Load(sender  As System.Object, e  As System.EventArgs)  Handles  MyBase.Load
         ' 初始化棋子
         Dim resbmp  As Bitmap =  New Bitmap(My.Resources._7041, cs.Width *  4, cs.Height)
         Dim allbmp  As Bitmap =  New Bitmap(resbmp.Width \  2, resbmp.Height)
         ' 获取棋子图像
         For y  As  Integer =  0  To allbmp.Height -  1
             For x  As  Integer =  0  To allbmp.Width -  1
                 If resbmp.GetPixel(x + allbmp.Width, y).ToArgb = Color.Black.ToArgb  Then allbmp.SetPixel(x, y, resbmp.GetPixel(x, y))
             Next
         Next
        bb = allbmp.Clone( New Rectangle( 00, allbmp.Width /  2, allbmp.Height), allbmp.PixelFormat)
        bw = allbmp.Clone( New Rectangle(allbmp.Width /  20, allbmp.Width /  2, allbmp.Height), allbmp.PixelFormat)
         ' ==========================开局棋型可在这里设置==============================
        ucpcSquares =  New mBitBoard()
        ucpcSquares.Set( 7 *  15 +  71)
     End Sub

     ' 绘制棋子
     Private  Sub pnlBoard_Paint(sender  As System.Object, e  As System.Windows.Forms.PaintEventArgs)  Handles pnlBoard.Paint
        e.Graphics.DrawImage(My.Resources._2064, Point.Empty)
         For i  As  Integer =  0  To  224
             If ucpcSquares.Get(i) =  1  Then e.Graphics.DrawImage(bb,  New Point((i  Mod  15) * cs.Height, (i \  15) * cs.Height) + co)
             If ucpcSquares.Get(i) =  0  Then e.Graphics.DrawImage(bw,  New Point((i  Mod  15) * cs.Height, (i \  15) * cs.Height) + co)
         Next
     End Sub

     ' 下子
     Private  Sub pnlBoard_MouseDown(sender  As  Object, e  As System.Windows.Forms.MouseEventArgs)  Handles pnlBoard.MouseDown
         Dim sdr =  CType(sender, Panel)
         ' 鼠标坐标转棋盘坐标
         Dim p  As Point = e.Location - co
        p.X \= cs.Width
        p.Y \= cs.Height
         ' 下一个白子
         If e.Button = Windows.Forms.MouseButtons.Left  Then
            ucpcSquares.Set(p.Y *  15 + p.X,  0)
             ' 更新显示
            pnlBoard_Paint(sdr,  New PaintEventArgs(sdr.CreateGraphics, sdr.DisplayRectangle))
         End  If
     End Sub

End Class

 

其中2064号资源是棋盘,7041是4个图组成的:黑子、白子、各自的掩码图。我没有使用掩码图,呵呵,用了一个循环。我的懒人原则是,初始化代码,能省事就省事……

 

 

完整示例代码:

/Files/zcsor/清月连珠0.1.7z

 

全部文章和源码整理完成,以后更新也会在下面地址:

http://www.vbdevelopers.org

http://www.softos.org

你可能感兴趣的:(五子棋)