基于人类经验的五子棋(2)---补充规则和指出

基于人类经验的五子棋(2)—补充规则和指出

基于之前建立的规则,来建立了一个初级的五子棋电脑,我们用规则来为棋盘上的每个位置评分,再从中找出评分最高的位置来选择;尽管有了一个良好的开端,但这仍然不能为它模拟一个"视觉"数据。

在进入下一步之前,我得提供一个事件,这个事件包含着一个经验,这个经验正是在这个五子棋目前状态中所有的。

我在上一篇位置提供了这些:

  1. 墙的优势计算【-5000】
  2. 当前位置在一行内是否有敌子(5格)的优势计算【-1】
  3. 与我子临格(5格)的优势计算【+2】
  4. 当前位置与我子关联(即临格1格)【+3】
  5. 如果另一边有子堵且可成3子【+3】,否则【+5】;
  6. 如果另一边有子堵且可成4子【+13】,否则【+20】;
  7. 成5子【+10000】

当时的我并没有处理“另一边有子堵且”。也就意味着我只处理了成3/4子的情况,而忽略了被堵的判断。不过,造成这种影响的确是因为五子棋入门潜,容易忽略这些,而在把程序做出来后,再去分析,才加入了这些功能。

所以,在进行项目之前,要尽量接触与项目有关的事物,以尽可能地完全实现项目中的行为细节。

好吧,那就从这里继续。接下来的问题是如何快速地添加这个实现。

void nodefraction(strplay**, int, int, short);
//计算优势,short是猜测对方下几步的次数

这个是我的计算优势的函数,strplay结构(或者说是类,但使用struct构造,而不是class)中存在着两个成员,分别记录着玩家优势分与电脑优势分。

与现在话题有关的、其内部实现:

//在此【CSDN】略有改动和从代码阅读上的优化
/*
static bool negative(strplay**node, int x, int y, int a, int b, int need, bool mode, bool how);
//查看该成子处另一端是否被堵。need为要看的方向:1为右-左;3为上-下;5为右上-左下;7为左上-右下返回true说明此位置被堵,被堵死则标记(只看5步);mode为false则不记录堵;how为true则为玩家
*/

				//右边
				linebool = false;//[bool]标记是否被堵,true是,false为否
				int CommputerPtr = UserPtr = 0;//[int]UserPtr为玩家子计数;CommputerPtr为敌方子计数
				CommputerUint = UserUint = false;//[bool]标记是否有电脑/玩家子出现过,true是,false否
				//看这个位置以及接下来的4个位置
				for (int i = 1, linea = a; linea < x && i < 5; ++i)
				{
					linea = a + i;//[int]
					if (node[linea][b].mode == 0) //此处无子
						break;//退出这个看右边的for,接下来是看左边
					else 
					{
						if (node[linea][b].mode == 1)//此处为玩家子
						{
							if (UserPtr < 4 && !CommputerUint)
								++UserPtr;
							else
								break;

							UserUint = true;
						}
						else //此处为电脑子
						{
							if (CommputerPtr < 4 && !UserUint)
								++CommputerPtr;
							else
								break;

							CommputerUint = true;
						}
					}
				}

				//左边
				CommputerUint = UserUint = false;//标记是否有电脑/玩家子出现过,true是,false否
				//看这个位置以及接下来的4个位置
				for (int i = 1, linea = a; linea >= 0 && i < 5; ++i)
				{
					linea = a - i;
					if (linea < 0)
						break;
					else if (node[linea][b].mode == 0)//此处无子
						break;//退出这个看左边的for,然后其他方向,不过在此【CSDN】没有给出接下来的代码
					else 
					{
						if (node[linea][b].mode == 1)//此处为玩家子
						{
							if (UserPtr < 4 && !CommputerUint)
								++UserPtr;
							else
								break;

							UserUint = true;
						}
						else//此处为电脑子
						{
							if (CommputerPtr < 4 && !UserUint)
								++CommputerPtr;
							else
								break;

							CommputerUint = true;
						}

					}
				}

				linebool = negative(node, x, y, a, b, 1, true, true);//玩家记录被堵死位置
					
				//玩家子成子数加分
				switch (UserPtr) {//目前位置上的子是玩家子
				case 2://成3子
					if (linebool)//查看是否会被堵,会则为true
						node[a][b].pinguser += 3;
					else
						node[a][b].pinguser += 7;
					break;
				case 3://成4子
					if (linebool)
						node[a][b].pinguser += 11;
					else
						node[a][b].pinguser += 500;
					break;
				case 4:node[a][b].pinguser += 10000;//5子+10000
					break;
				}

				linebool = false;
				linebool = negative(node, x, y, a, b, 1, true, false);//记录电脑被堵死位置

				//电脑子成子数加分
				switch (CommputerPtr) {//目前位置上的子是电脑子
				case 2://成3子
					if (linebool)
						node[a][b].pingcommputer += 3;//3子+3
					else
						node[a][b].pingcommputer += 7;
					break;
				case 3://成4子
					if (linebool)
						node[a][b].pingcommputer += 11;//4子+11
					else
						node[a][b].pingcommputer += 500;
					break;
				case 4:node[a][b].pingcommputer += 10000;//5子+10000
					break;
				}

去除与这次话题无关的部分,改了一些,随后发现一些优化的地方也优化了,不过源代码我没动[懒得动]。

这是右-左的判断,每次判断的循环是对棋盘上的每个位置进行的。这里添加的函数negative:它判断这个成子处的两端是否全部都是空位,如果是则返回false,否则返回true标识被堵,如果被堵死,则记录到玩家/电脑的被堵死位置去。

基于上面的negative函数实现会发现一些问题:

  1. 对两端空位查看来判断是否被堵死的方法并非总是有效的。如一个成3子,但它的两端+1处都是敌子或墙;
  2. 记录堵死位置有潜在的不可逆风险。因为记录了不一定会删除(没人认为这有多么重要,并且在后面还会用到它,所以无法知道正确删除的时机)——如果在后续添加一个与此相联的功能: 比如用户想在游戏进行时自定义棋盘棋子,此时,玩家/电脑被堵死位置的信息仍然存在,又因为现在的目标是以最方便的方法到达现有目标,导致用户在完成他想做的事后,对于某些棋子位置电脑总是忽略它。

这个问题的解决方法是在软件开发文档中记录它。是的,你可以选择在合适的时候去处理它,但谁会知道这个数据对象会对后面的开发工作产生影响?现有对象是基于现有方案来实现处理的,所以根本无法从目前的要求考虑到对象的未来处理,从而到后面的功能添加时,发生了问题,也不一定能够准确分析出是因为某个数据对象造成的。所以,最好的方法是使negative函数不进行记录被堵死位置,取而代之为对此位置的评分记为最低。(这个方案相当不错,它既解决了以后对棋盘内容改动的潜在麻烦,也完成了功能需求。不过遗憾的是源代码中并没有这样做,因为现在改动可能会影响先前根据此来开发的功能,另外,这里其实还包含着一个经验,只是现在还不明显。)

现在的计算优势分函数完成了要求的更改。尽管这样,人机还是不能“正确”地下棋,有些明摆着的位置人机不给予理会,所以在用户眼里,他们无法理解这些行为,只能指出人机各种各样的错误来表达人机并不智能。(不过幸好我这时没把它推广)

由此可见,单纯的基于纳升均衡式数字化过于笨拙,应该添加一些“视觉”上的规则来纠正它。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值