吧务
level 11

我们使用C#的fixed关键字来指定一个数组,这样的话它会以缓冲区的模式来表达。当然如果别的语言没有的话,你可以使用private short _values = new short[81];的语法来完成。
这个MaxCandidatesCount是常量,它等于(1 << 9 - 1),即511。为什么是&511呢?你想一想,我们一共是12个比特位来表示数据信息,高三位用来表示单元格的状态了,所以剩下9个比特位作为低比特位直接取出来是不是就可以了?所以&511意思就是在取剩下的部分。
首先是get方法。get方法用来获取这个格子到底填入了什么数。我们这里用到一个叫做GetStatus的方法,我们马上就说,它用来计算这个格子到底是什么类型的格子(提示数、自己填了数字的格子还是空格);返回的 CellStatus类型是一个枚举类型,它包含Undefined(未定义)、Empty(空格)、Modifiable(可修改的自己填入的数字)、Given(提示数)四种状态。如果格子是 Empty的,返回 -1表示取值非法;其它情况则返回0到8的数据来表示1到9。大家都知道,C系列语言都是数组0下标开始的,所以这么做是为了处理起来方便。0表示数字1、1表示数字2、2表示数字3,……,一直到8表示数字9。
有get还不够。set方法要去给这个格子赋值填入一个数字。
首先是get方法。这个索引器有两个参数,一个是单元格,一个是数字。返回值(赋值)类型都是bool,这表示我到底是填这个数字进去还是去掉这个数字。
然后是set方法。set略微麻烦一点,因为我们要赋值true的话就会填入一个数据进去,因此ValueChanged这个函数指针指向的方法会被自动调用,因此这里我们也要用到它。


RegionMaps是一个预处理过的数组,region是几就刚好取出所有这个区域的格子,构成的这个数组就是这个结果。foreach循环就直接可以迭代遍历这个数组了。
请看后面这个if条件。(mask & mask - 1) == 0就表示这个数字是不是只有一个比特位是1,而别的地方都是0。如果这个数字是只有一个1,而别的都是0的话,这个数有一个特性就是,比它小一个单位的数字,二进制表达恰好1所在比特位以后的所有比特位都是1,而它自己改成了0。我们只需要&运算符来一下,因为每个比特位对应都不同,所以永远得不到1,因此结果必然是0。
如图所示,我们假设ABC三个区分别表示区块用到的三个部分,C是区块所处位置,而A或者B则是删数的区域。区块总是只会删除掉A或者B其中一个区下的某个数,所以另外一边是不会有删数的。那么我们可以这么去思考。


这里的这个r变量表示什么区域的区块对什么区域做排除效果。