一,界面
棋盘用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