由于后面的过程中,哈里也是遇到了一些坑,因此完全按照当时开发时候的逻辑,可能篇幅太长。因此就直接把最后选择的算法做介绍吧。
上回书说道:
·那我要悔棋怎么办啊?
·那我要再开一局怎么办啊?
·我要棋子落得更整齐应该怎么办啊?
·我想让程序告诉我哪方胜利该怎么办啊?
·我想双方交换棋盒颜色该怎么办啊?
就拿悔棋来说吧,我们自然五子棋最重要的核心,与别的五子棋最大的不同就是模仿真实的下棋过程。因此,每个棋子,我们可以拖动它们到新的位置上去或者放回棋盒重新选位置落子这两种自然的悔棋方式。
那如何才能够移动棋子或者将棋子返回棋盒呢?传统的做法是记录每棋子落的每一步,然后撤销最后一步就是悔棋了。
而我们这里,将每一颗棋子当作一个对象来看待。
什么是对象?对象通俗的说就是一个由许多属性共同描述的物体。比如棋子,它的属性有颜色、大小、位置(二维平面中是横坐标x,与纵坐标y共同确定的)。
VB里面怎么快速而简单的建立一个对象呢?
type 类型名
属性A
属性B
...(依此类推)
end type
大家可以想象,如果棋子是一个对象的话,我们改变棋子的位置属性,那么是不是它在棋盘上的位置就实际改变了呢。
好,接下来就是哈里编写的棋子的属性(这个声明哈里是放在Module(模块)里面的,如果放窗体里,需要把public改成private):
这里我们没有设置棋子的大小了,因为棋子都是一样大,到时候我们设置一个常量来表示就可以了。哈里设置的属性中,因为棋子的位置是棋盘上的任意位置,因此越精确的记录棋子的位置就是我们的需求,因此表示横坐标x和纵坐标y的变量我都声明为单精度小数,这样比long(长整型)或integer(整型)表示得更精确。c是颜色,因为棋盘上只有黑白两种颜色,因此甚至boolean(布尔型)都能表示,这里用integer的原因是因为,第一章里面我们已经说了,用棋盒的颜色来表示棋子的颜色,这里的c其实是存放的棋盒的index值。棋盒(c).backcolor就可以获得棋子的颜色了。
棋子有了,棋局我们怎么表示呢?
哈里用的是一个动态数组来表示的,每下一颗棋子,数组就生成一个新元素来表示新棋子。声明如下:
棋子在什么时候最终生成呢?当然是我们落子的时候。
于是落子时候的过程应当是这样的:
棋局数组的初始化(redim 棋局(0))哈里是放在每一局棋开始的时候的。如果不初始化就直接执行 ubound() 函数(获得数组大限),是会报错的。这个过程是放在棋盘的MouseDown事件(鼠标按键点下事件)中的。
这里我们会遇到一个问题,就是如果鼠标落下的位置已经有棋子了,如果没有检测机制,我们下的棋子就有可能重叠在一起,因此这里我们还要想办法让棋子间不相容。而且,在这里我们还需要注意的一点是:明确性。什么是明确性呢?就是在棋盘上任意竖线和横线交叉的地方,有且只能有一颗棋子。为什么要这样呢?因为这样才能方便程序判断胜负和后面的让棋子自动变得更整齐的时候不至于两颗棋子重叠在一起。
一个比较通用的检测棋盘上某点(x,y)上是否有棋子的函数如下:
这里的0.4是我们棋子的半径。因为我们棋盘每一小格的边长是1,因此棋子半径0.4的话,两颗棋子之间会有0.2的间隙,不会给人太密集的感觉。
这个函数的作用并不是完全为检测落点是否有棋子准备的,它的作用其实是假如我要拖动一颗棋子的时候,判断我手指摁在棋盘上的位置有没有棋子准备的。
好哒,这里引入了一个“摁住的棋子”这个概念。
为什么这里要用long呢?因为vb里面数组的最多元素数量就是long的长度,用long就可以索引整个数组了,其实这里用integer甚至byte也是可以的,因为一局棋最多落15*15=225颗棋子。也就是说棋局数组的大限理论上不会超过225。
接下来才是我们判断棋子是否重叠的算法(函数):
这里可能会有比较初学的朋友看不太明白,其实这个算法已经暴露了我们如何将棋子整齐化的方法了。
int()函数是VB内置的一个函数,作用是将一个小数去掉小数点部分变成整数。
试问:(小数+0.5)取整,不就是四舍五入吗?
一个棋子的位置,四舍五入之后,不就正好在棋盘横竖交叉的地方吗?不就整齐化了吗?
同理,如果把要下的这颗棋子化整后,比对整个棋局里所有棋子化整后的位置,如果没有一样的,是不是就说明当前落点没有棋子了呢。
好的,第二章暂时到这里吧~