好库网 好库网首页 | 我的好库
csharp的专栏

文章分类

C#五子棋程序设计

发布者:csharp
发布日期:2013/2/24 17:39:06   更新日期:2013/2/24 17:55:45
阅读次数:5882
评分:4.80
介绍: 五子棋起源于古代中国,发展于日本,风靡于欧洲。对于它与围棋的关系有两种说法,一说早于围棋,早在 “ 尧造围棋 ” 之前,民间就已有五子棋游戏;一说源于围棋,是围棋发展的一个分支。在中国的文化里,倍受人们的青睐。古代的五子棋的棋具与围棋相同,纵横各十七道。五子棋大约随围棋一起在我国南北朝时先后传入朝鲜、日本等地。
正文:

作者:李老头

 

下载源代码:http://www.okbase.net/file/item/21480

 

一、界面

 

棋盘用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 = new Bitmap(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 = new Bitmap(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个位置上循环判断,得到每个点的权重值,最后取出最大的权重值,在最大权重值的点上下子(前提是在该点上没有子)

 

/// <summary>
/// 判断是否在该点存在棋子,存在返回true;
/// </summary>
/// <param name="m"></param>
/// <param name="n"></param>
/// <param name="ChessBoard"></param>
/// <returns></returns>
public static bool IsExists(int m, int n,int[,] ChessBoard)
{
	if (ChessBoard[m, n] < 2) return true;
	else return false;
}

 

 

 

五、判断结果

1. 胜利

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

2.平局

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

3.禁手失败

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

 

附:五子棋简介  

 

   五子棋起源于古代中国,发展于日本,风靡于欧洲。对于它与围棋的关系有两种说法,一说早于围棋,早在 “ 尧造围棋 ” 之前,民间就已有五子棋游戏;一说源于围棋,是围棋发展的一个分支。在中国的文化里,倍受人们的青睐。古代的五子棋的棋具与围棋相同,纵横各十七道。五子棋大约随围棋一起在我国南北朝时先后传入朝鲜、日本等地。据日本史料文献介绍,中国古代的五子棋是经由高丽 ( 朝鲜 ) ,于 1688 年至 1704 年的日本元禄时代传到日本的。到日本明治 32 年 ( 公元 1899 年 ) ,经过公开征名, “ 连珠 ” 这一名称才被正式确定下来,取意于 “ 日月如合壁,五星如连珠 ” 。从此,连珠活动经过了不断的改良,主要是规则的变化 ( 即对执黑棋一方的限制 ) ,例如, 1899 年规定,禁止黑白双方走 “ 双三 ” ; 1903 年规定,只禁止黑方走 “ 双三 ” ; 1912 年规定,黑方被迫走 “ 双三 ” 亦算输; 1916 年规定,黑方不许走 “ 长连 ” ; 1918 年规定,黑方不许走 “ 四、三、三 ” ; 1931 年规定,黑方不许走 “ 双四 ” ,并规定将 19×19 的围棋盘改为 15×15 的连珠专用棋盘。本世纪初五子棋传入欧洲并迅速风靡全欧。通过一系列的变化,使五子棋这一简单的游戏复杂化、规范化,而最终成为今天的职业连珠五子棋,同时也成为一种国际比赛棋。

 


评论 [发表评论]
账号 密码 还没帐号呢,现在注册一个?

免责声明:好库网所展示的信息由买卖双方自行提供,其真实性、准确性和合法性由信息发布人负责。好库网不提供任何保证,并不承担任何法律责任。