我们认为, 类别定义, 是在OOP程式设计中最困难的部分. 所以在这些课程中, 我们不准备详细地解释如何设计类别, 属性与方法. 我们只会解说在这个程式库中既有的类别, 属性与方法. 所以我们可以类比这些类别, 属性与方法所构成的资料结构是一个解决数独的模拟环境, 以便让学习者以人的思考模式来学习如何解开一个数独.
首先, 我们可以想像在一个美丽的山谷中, 有9x9 间方方正正的房子, 它们排列如下:
一个假想的联合王国
这里有9 个国家, 每一个国家有9 个人, 他们决定一起定居在这个美丽的山谷. 而这个山谷共有9x9 间房子. 他们决定每一排(x-way line), 每一列(y-way line ), 及每一个3x3 区块都包含了每一个国家的人. 如此, 他们才会认为他们这个团体才是一个真正的联合王国, 可以永久和平地生活在一起. 你可以帮助他们达到这个目的吗?
接着, 我们就可以开始协助这些人来促成这一个美好的世界...
在OOP中,类别(class)的定义是主角。它就如同人类j为了探索、沟通或者纪录等目的,会将有同样行为、特性与外表的事物归类一样。如同我们会将动物当作一类,而大象就是动物类别的一个子类别,一只大象就是同属于动物及大象这两类的一个物件。
虽然在自然上,一只大象这个物件同时隶属于大象类及动物类,但看目标的需要,也可以直接将一只大象当做动物类别的一个物件即可。所以我们可以说在OOP 所说的物件(Object)就是我们现实世界的一个实体,就如同人类若是一个类别,那你就是隶属此类别的一个唯一独立的物件。
依据我们设定的范围与需要,我们可能设计出不同的类别,而让同一个物件同时隶属于它们。如我们想要研究城市生态时,我们可能会设计一个animal 类别,而这个类别中的物件包括一些人,一些宠物等等...但当我们想要制作一个电话簿程式时,那我们就会设计一个person 类别,一些人会成为此类别的物件,但不会包括宠物,除非这些宠物也都拥有手机。
在这个专案中,我们设计的主要类别有:
Number Class:
我们可以视数独游戏中每个数字是一个人。而整个数独世界中有9 个国家,每个国家有9 个人。如此,这个Number Class 就可以视为是一个国家类别。每一个国家都有一个识别代码(ID),在这里是1-9,而每个国家都会纪录它的人民住在这山谷中的位置。
Point Class:
Point 物件就是一间房子。每间房子都会标注它是否已住人,如果已住人,那是哪个国家的人民;如果是空的,那可以让哪些国家的人民来申请入住?
GroupBase Class:
GroupBase是一种群组类别,也就是它的物件不是一个实体,而是一群实体的组合。在这里的GroupBase 包含了三种群组,X 与Y 轴方向的房子群组及区块房子群组。每个物件都将指出它包含了哪些房子,已经住了多少人,还有哪些国家的人民还没住进来?
Box Class:
它是GroupBase的子类别,为区块群组。在数独世界中总共有9 个区块物件,从左到右,从上到下,被标注其区块代码如下:
lineX Class:
这是GroupBase 子类别,为X 轴的房子群组。在数独世界中共有9 个物件,从左到右被标注1-9,如下图:
lineY Class:
这是GroupBase 子类别,为Y 轴的房子群组。在数独世界中共有9 个物件,从上到下被标注1-9,如下图:
Matrix Class:
Matrix class定义了数独游戏的整个世界。它是一个美丽的山谷,包含了9 个国家的人民,每一个国家有9 个人,山谷中建造了9x9 间房子以提供给这些人民来居住,以组成一个永远和平的联合王国。
属性(Property)是在类别(Class)的定义里面,类别用它来定义成员,特征及纪录状况。如在一个人的类别里面可能会包含以下一些属性: 这人拥有多少钱、他有几个小孩子、第一个小孩是男或是女、每个小孩各是几岁?
以下是这个专案中几个主要类别的主要属性定义:
Number Class:
v: 这个国家的代码, 1-9
p: 这个国家每一个人民所居住的房子列表
filled: 有多少人已经住进房子了
Point Class:
x: 这个房子的 x 轴座标
y: 这个房子的 y 轴座标
v: 这个房子居住了哪个国家的人民,如果是空的,那它的值就是 0
b: 这个房子隶属哪个区块
GroupBase Class:
idx: 这个群组的代码
p: 隶属这个群组的房子列表
filled: 在这个群组里面已经居住了多少人
possilbe: 在这个群组里面还有哪些国家还没住进来,值为这些国家的代码列表
Box Class:
包含所有 GroupBase 的属性
effects: 这个区块的所有邻居区块
effectsX: 这个区块的 x 轴方相邻居
effectsY: 这个区块的 y 轴方相邻居
lineX Class:
与 GroupBase 的属性相同
lineY Class:
与 GroupBase 的属性相同
Matrix Class:
p: 一个二阶阵列的房子列表,从p[0][0] 到p[8][8],代表这个山谷的所有房子。
lineX: x 轴方向房子群组的列表
lineY: y 轴方向房子群组的列表
b: 区块房子群组的列表
n: 所有国家的列表
filled: 纪录已经有多少人入住在这个山谷了
方法(methods)是一个类别及其物件的一些特定行为。举个例子,如果我们定义了一个收音机类别,它将包含一些按钮的属性,而当我们按下这些按钮时,我们就必须定义一些方法来执行这个动作。这些动作有可能是开始接收某个电台的节目、或者是录制节目到CD等等...
以下是这个专案中的类别中使用道的主要方法:
Number Class:
setit(p1): 当有人找到属于自己的房子时,就会启动这个方法
Point Class:
can_see(p1): 测试一个房子是否能够**看到**另外一个房子(p1)?
can_see_those(posList): 测试一个房子能否**看见** posList 所列的房子,并将所有能看见的房子列表传回。
注解
什么是「看见」?
对一个房子而言,与它同一排、同一列、或者同在一个区块的其他房子,都是它能够**看见**的房子。
GroupBase Class:
allow(v): 测试一个房子群组能否让标记为v 的国家人民来居住?
get_num_pos(v): 在这个房子群组中,取得v 国人民居住的房子物件,如果该国尚未有人入住,则以None来回应。
count_num_possible(count): 在一个房子群组中,取得国家的id及可供该国人民居住的房子列表,如果有参数count,则表示要取得的可供居住的房子数要等于count 才取回。
get_all_pos(method): 如果method = “a”, 取得一个房子群组的所有房屋物件列表;如果method=”u”,则取得所有空房列表;如果method=”s”,则取得所有已住人的房子列表。
Box Class:
所有 GroupBase 类别的方法
get_group_number(num): 测试这个国家代码num 在一个房子区块中能否形成一个**虚拟国民**?
注解
什么是「虚拟国民」?
虚拟国民存在于一个房子区块群组中。在一个区块中尚未有人入住的房子中,如果所有可能让某个国家居住的房子在同一个方向时(无论是x 轴或y 轴),那我们就可以称这些房子形成了一个**虚拟国民**。虽然我还不晓得在这个区块中,这个国家的人民最后将居住在哪里,但我们从虚拟国民中知道,在与它同个方向的其他区域的房子,都将不允许居住这个国家的人民了。
lineX Class:
与 GroupBase 有相同的方法
lineY Class:
与 GroupBase 有相同的方法
Matrix Class:
get_all_pos(method): 如果method = “a”, 取得所有房屋物件列表;如果method=”u”,则取得所有空房列表;如果method=”s”,则取得所有已住人的房子列表。
sort_unassigned_pos_by_possibles(possibles): 取得所有的空房列表,而这些空房数必须仅能够让possibles 个国家的人入住,如果possibles == 0, 将取得全部空房。回应回来时将以可居住国家数,从小排到大。
can_see(p0, method=”u”, num=0): 取得能够看见某一房子(p0)的房子列表,如国num!=0,表示仅取得可让国家代码为num 者居住的房子。
setit(x, y, v): 让国家代码为v 的人民安住在座标为(x, y)的房子。
reduce(x, y, v): 当一个房子(x, y)被入住时,任何能够看见此房子的其他空房,都可用此方法来减掉已入住这个国家人民(v)的可能性。
allow(x, y, v): 测试这个国家(v)的人民是否能够居住于座标(x, y)的房子?
read(file): 从一个定义档(file)中读入最初到此山谷的国家、人民与居住位置。
你能够定义数独游戏的最初状况。在文字档中一行定义一个房子的座标及居住者,格式为x, y, v,如下图,此专案附有一些已定义好的数独,置于[安装的目录]/sudoku/data/ 目录里。
m3.data | 起始的数独外观 |
已解的数独外观 |
---|---|---|