五子棋程序设计开发

一,界面

棋盘用PS画好的图:chessboard.png

把该图片导入到Properties的Resources.resx中。

程序中引用如下:

Image imgChessboard = global::fivestone.Properties.Resources.chessboard;//棋盘图片大小600*600像素

在本窗口(winfrom)中画棋盘

//mg是本窗口的graphics,顶部菜单占去24个单位

mg.DrawImage(imgChessboard, 0, 24, imgChessboard.Width, imgChessboard.Height);

二,画棋子

画棋子可以用PS画好再导入,但这样容易变形。可以用GDI+画黑白棋子

#region 画黑白棋子

        //黑子

        public System.Drawing.Image BlackStone

        {

            get

            {

                System.Drawing.Bitmap img =newBitmap(40, 40);

                System.Drawing.Graphics gi = System.Drawing.Graphics.FromImage(img);

                gi.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

                Brush bru = new SolidBrush(Color.Black);

                gi.FillEllipse(bru, 3, 3, 32, 32);

                return img;

            }

        }

        //白子

        public System.Drawing.Image WhiteStone

        {

            get

            {

                System.Drawing.Bitmap img =newBitmap(40, 40);

                System.Drawing.Graphics gi = System.Drawing.Graphics.FromImage(img);

                gi.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

                Brush bru = new SolidBrush(Color.White);

                gi.FillEllipse(bru, 3, 3, 32, 32);

                return img;

            }

        }

        #endregion

 

三,落子

//计算后的鼠标位移

int m = 0, n = 0;

m = (int)Math.Floor((double)e.X / 40);

//计算后的鼠标位移

n = (int)Math.Floor((double)(e.Y) / 40);

如何在棋盘上落子?

棋盘的每个格式是一个正方形。正方形规格是40X40。也就是在每一个可以落子的点周围形成一个40X40的正方形。

棋盘的15X15规格。共15X15=255个棋子,存为一个数组ArrChessBoard[15,15]中。

需要把鼠标位移转化为棋盘上的落子点位置。

我们把某个落子点的周围形成一个正方形,在这个正方形范围内落子即视为在该点落子。即范围在(x-20,y-20) 至(x+20,y+20)范围之内,它们的长度是40。所以这个范围是在中心点的一倍距离之内。可以用Math.Floor求得.

第一个点的鼠标位移为20,20。最小位移是(0,0),最大位移是(40,40)

计算后的位置(0,0)

最后一个点的鼠标位移为580,580。最小位移是(560,560),最小位移是(600,600)

计算后的位置(14,14)

这样落子后我们就得到了该点在棋盘上的位置坐标。

同时规定。下的是黑子,ArrChessBoard数组存储为0,下白子,ArrChessBoard数组存储为1。空着则数组存储为2。

 

黑子(先手)禁手

禁手:对局中如果使用将被判负的行棋手段。

三三禁手:黑棋一子落下同时形成两个或两个以上的活三.

四四禁手:黑棋一子落下同时形成两个或两个以上的冲四或活四。

长连禁手:黑棋一子落下形成一个或一个以上的长连。

 

四,电脑下子(人工智能)

电脑要怎么要下子呢?首先要明白下五子棋的规则。五子棋因为先手的优势很大,所以对先手有一定的规范,即所谓禁手。先手是黑子。则黑子存在禁手。禁手一般包括双三禁手,双四禁手,长联禁手。如果电脑先下,电脑是黑子,要遵循这个原则。如果人先下,人是黑子也需要遵循这个规则,如果人是黑子而走了禁手则判定为负。

 

电脑需要在哪里下了呢?

1.   棋位必须在棋盘范围内。

2.   棋位必须是空的。

3.   棋位必须是最大优势的。

前两点都好判断,最难在于第3点。这里需要用到权重这个概念。即下子的位置是最有利的。CPU的速度是很快的。不必考虑运算问题。

 

权重

权得即在该点是最大优势的。判断在假设点下一个子,我方下子或者对方下子的权重比值。

1.   落子在中间,权重+1,这样电脑下第一个子的时候就下子在中间。位置在(7,7)

2.   已方在四个方向(横,竖,左斜线,右斜线)有一方能联到5个子(5联胜利),权重+100000,正值最大,对方能5联,权重+50000,

3.   以下判断的是四联和三联,这里需要注意的是是否活的还是死的。活三联表示两边都没有阻挡,死三联表示两边有一个和二两人个阻挡

             //4

            int w3_h = 10000;

            int w3_s = 5000;

            int w4_h = 8000;

            int w4_s = 3000;

 

            //3

            int w5_h = 1000;

            int w5_s = 500;

            int w6_h = 800;

            int w6_s = 300;

 

            //2

            int w7_h = 100;

            int w7_s = 50;

            int w8_h = 80;

            int w8_s = 30;

 

            //黑子的失败点,即禁手

            int w9 = -1000000;

4.如果该点已经有子则权重为-1。ArrChessBoard初始化后,各点的权重默认为0。因此电脑不会在-1位置下子

判断每个方向的联子个数

以假设下子点为原点,向前,后判断与该子的联子个数,如果是活的话返回正值个数,如果两头有阻挡或一头有阻挡时返回负值个数,表示死的。(如果要加强电脑的智能。这里还可以再细分,因为两头都有阻挡的话胜算更小,一头有阻挡的话还可以冲)

        public static int Xnum(int m,int n,int[,] arrchessboard)

        {

            //正东方向

            int flag = 0, num = 1;

            int i = m + 1;

            while (i < 15)

            {

                if (arrchessboard[m, n] == arrchessboard[i, n])

                {

                    num++;

                    i++;

                }

                else break;

            }

            if (i == 15) flag++;

            else

            {

                if (arrchessboard[i, n] != 2) flag++;

            }

 

            //正西方向

            i = m - 1;

            while (i >= 0)

            {

                if (arrchessboard[m, n] == arrchessboard[i, n])

                {

                    num++;

                    i--;

                }

                else break;

            }

            if (i == -1) flag++;

            else

            {

                if (arrchessboard[i, n] != 2) flag++;

            }

            //flag=2时如两种情况:1,两头都已经在边,或者两头都有其它的子,X轴已经占满;2,一头有子一头到边

            //flag=2表示两边都堵住了.已经没有发展的前途,除非是大于等于5,但这种情况很少

            if (flag == 2) return -num;

            else

            {

                //一头到边或者有子,即使是3个也不是活3

                if (flag == 1 && num == 3)return -num;

                else return num;

            }

        }

Y轴,XY轴,YX轴以此类推。

 

轮到电脑下子的时候,电脑循环在15X15个位置上循环判断,得到每个点的权重值,最后取出最大的权重值,在最大权重值的点上下子(前提是在该点上没有子)

        ///

        ///判断是否在该点存在棋子,存在返回true;

        ///

        ///

        ///

        ///

        ///

        public static bool IsExists(int m,int n,int[,] ChessBoard)

        {

            if (ChessBoard[m, n] < 2)returntrue;

            else return false;

        }

 

五,判断结果

1.      胜利

任何一方如果四个方向有一个方向联成了5个就判断为胜利。

2.平局

当15X15个棋子位置都占满而没有一方联成5个时判断为平局。

3.禁手失败

当黑子(先手)走三三联,四四联,长联时则判定为负。


六.源码下载 vs2010   http://download.csdn.net/detail/u011966339/9803073

你可能感兴趣的:(游戏编程)