We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
除了早期从 WLS 抄来的那些改进之外,rlifsrc 引入的改进中最简单又有效的是这两个:前排非空(non-empty front),和对角宽度。其中前排非空的选项已在 4.0 版删除:这个功能还在,只是改成根据对称性、位移、搜索顺序等条件自动开启。
不过和对角宽度比起来,前排非空不是这么直观直观。我也一直害怕有 bug,还是要写点文档总结一下,顺便也为实现 #51 中提到的更多对称性作准备。
前排非空的想法很简单:比如说,假如我们要搜 17x5 大小向上飞的 c/3 飞船,搜索顺序是从左到右一列一列地搜,找到了这么一个玩意儿:
注意它在一个周期中的三代,最左边一列都是空的。如果我们把它 ⬅️ 向左移动一列,结果还是满足所有的条件:
于是,我们可以干脆增加一个第一列非空的条件,这样可以有效地缩减搜索空间。
这种情况下我们把第一列叫做前排(front)。如果搜索顺序是一行一行地搜,则把第一行叫做前排;如果搜索顺序是对角方向,则把第一行和第一列都算作前排。
不过,我们还需要定义什么是空——由于 B0 规则的存在,我们不能简单地把死细胞定义为空。这里我们采取的定义是:对于每一代,如果一个细胞的状态和搜索范围之外的细胞一致,则称其为空。也就是说:
当我们说一个细胞集合(比如说前排)为空时,指的是集合中每一个细胞都为空。同样到了,说这个集合非空指的是至少有一个细胞非空。
搜索的时候,我们可以用一个变量来记录前排中未知或已知非空的细胞的数量;每次搜到一个在前排的细胞,都根据其状态的变换来更新这个变量;如果变量变成了0,则说明当前的 partial result 不满足前排非空的条件,没必要在它上面浪费时间,可以直接回头。
然后问题来了:什么时候可以要求前排非空?
或者换句话说,怎样的搜索条件有平移不变性,即任何满足此条件的图样在向指定方向平移之后还满足同样的条件?
我们按网页版的 Setting,从上到下一条一条分析:
后面几个选项也都无关,不一一讨论了。
也就是说,我们需要考虑的只有对角宽度、变换、对称、已知的细胞这几个选项。
但有时我们不需要考虑整个前排:比如说,假如我们要搜 45x10 大小向左飞的 c/4 飞船,搜索顺序还是从左到右一列一列地搜,找到了这么一个玩意儿:
注意它一个周期的四个回合中,第一列的上半部分都是空的。如果我们把它上下翻转一下,结果还是满足所有的条件:
因此,我们可以要求一个第一列的上半部分非空,进一步缩减搜索空间。
(写到这里忽然发现这个条件还可以进一步加强:把第一列所有回合的细胞状态写成一个二进制数,然后要求这个二进制数不能小于把它所有数位左右翻转的结果;或者把第一列的上半部分和下半部分写到两个二进制数中,然后比较这两个数就行了。不过 Rust 中整数大小是有限的,用 64 位的整数表示的话就不支持前排超过 64 个细胞的情形;Generations 的规则要把二进制改成 n 进制,能支持的前排细胞数更少,实现上也更复杂一些。)
类似地,如果搜索顺序是一行一行地搜,则只考虑第一行的左半边;如果搜索顺序是对角方向,只考虑第一列。
为了能加上这个条件,我们要要求搜索条件在翻转变换下不变。
如果以图样中心处为原点的话,这里涉及到的三种翻转如下:
(x,y) => (-x,y)
(x,y) => (x,-y)
(x,y) => (y,x)
(等等,写到这里我发现我的实现有个严重的 Bug:非各向同性的规则是不能随便翻转的!这有点难办……等改好这个 Bug 再继续写吧。)
(以上 Bug 已修复……希望不要引入新 Bug……)
和之前一样,所有设置从上到下一条一条分析:
看起来变换、对称和已知细胞的条件比前排非空要宽松。不过我们是在要求前排非空的前提下才能考虑半个前排,所以实际新增的条件只有规则(差点又忘了)、宽度、高度、dx、dy 这些。
前面说的前排指的是前排的每一代。要求前排非空等价于要求至少有一代的前排非空。于是,对于振荡子(也就是 dx、dy 为 0 的情形),只要规则没有 B0,我们可以干脆前排非空的那一代定为第一代,于是可以要求前排的第一代非空,进一步缩减搜索空间。
但对飞船来说,问题没这么简单。事实上,对于周期为 p 的振荡子,第 p+1 代和第一代是一样的,因此第二代到第 p+1 代也满足原本的条件。但对飞船来说,第 p+1 代相比第一代还会有一个平移,可能会平移出原本的高度和宽度所规定的范围。
不过,搜索飞船的一种常见情况是:每个周期仅平移一格,而且平移的方向正好是向着前排。
比如说,假如我们要搜 21x13 大小向左飞的 c/4 飞船,对称性是 D2-,搜索顺序还是从左到右一列一列地搜,找到了这么一个玩意儿(这次把每一代都画出来了,从左到右):
这飞船前排的第一代是空的。于是,它的第五代只是把第一代向前平移一格,并不会移出规定的范围。也就是说,它的第二到第五代也满足原本的条件:
因此,这种情况下也可以要求前排的第一代非空。
也就是说,如果要要求前排的第一代非空,在前排非空的条件的基础上,我们还需要:
(写到这里忽然发现,没必要完全禁掉 B0 的规则,其实可以改成要求前排的前两代非空;对于 Generations 的规则,若有 n 种状态,则可以改为前排的前 n 代非空。这里需要的改动很小,已改。)
上一节的讨论只适合飞船每个周期向前平移一格的情形。如果平移不止一格呢?
此时,我们不能再要求前排的第一代非空。事实上,此时前排的第一代必须是空的,因为这些细胞的前一代的整个邻域都已经在搜索范围之外。
不过,我们可以把“前排”往后挪一挪。
比如说,假如我们要搜 12x15 大小向左飞的 2c/5 飞船,对称性是 D2-,搜索顺序还是从左到右一列一列地搜,找到了这么一个玩意儿(这次把每一代都画出来了,从左到右):
它第一代前两列都是空的。第六代只是把第一代向前移动两格,不会移出规定的范围。于是,和之前一样,我们可以考虑它的第二到第六代:
于是,我们可以干脆把前排的定义从第一列移到第二列,继续要求新的“前排”的第一代非空。
一般地,如果飞船每个周期向前平移 d 格(平移的方向必须向着前排),我们就可以把前排的定义修改为第 d-1 行/列/行加列。
但我们还要说明新的要求比原本要求的前排(所有代)非空要强,不然直接用原本的要求不就行了吗?
这也不难。一个细胞非空的必要条件是它前一代的邻域中至少有一个细胞非空。若飞船周期为 p,新的前排是第 d-1 列,那么新前排的前一代对应于第 p 代往前刚离开搜索范围的那一列,其邻域的三列只有一列在搜索范围之内,也就是第 p 代的第一列。因此,只要要求新的前排第一代非空,旧的前排就一定也非空。
于是,我们可以把上一节的条件改进为:
此时“前排”的定义为:
目前 rlifesrc 采用的前排非空的条件就是这么多。
前面说了这么多,一方面是为了总结和查 bug,另一方面是为实现 #51 中提到的自定义对称性做准备。
其实说“自定义对称性”有点不准确,因为这也包含了一些不属于对称性的条件。
我们想要支持哪些条件呢?先试着列举一下。
区域怎么定义,允许哪些变换,都是需要讨论的。
自定义对称性最好还能写成一种方便读取的格式,比如说 JSON。
(未完待续)
The text was updated successfully, but these errors were encountered:
啊啊啊,又忘了考虑 B0 的规则……
先在前面加一句注意,以后再补充。已补充。
Sorry, something went wrong.
本想这个春节假期实现自定义对称性的,不过都偷懒去了……
接下来这段时间我会比较忙,没时间更新 rlifesrc (除了 dependabot 推送的更新)。不过关于自定义对称性有什么好的建议都可以提。@HuntingBot @yujh-yujh (好像@不到)
No branches or pull requests
除了早期从 WLS 抄来的那些改进之外,rlifsrc 引入的改进中最简单又有效的是这两个:前排非空(non-empty front),和对角宽度。其中前排非空的选项已在 4.0 版删除:这个功能还在,只是改成根据对称性、位移、搜索顺序等条件自动开启。
不过和对角宽度比起来,前排非空不是这么直观直观。我也一直害怕有 bug,还是要写点文档总结一下,顺便也为实现 #51 中提到的更多对称性作准备。
前排非空
前排非空的想法很简单:比如说,假如我们要搜 17x5 大小向上飞的 c/3 飞船,搜索顺序是从左到右一列一列地搜,找到了这么一个玩意儿:
注意它在一个周期中的三代,最左边一列都是空的。如果我们把它 ⬅️ 向左移动一列,结果还是满足所有的条件:
于是,我们可以干脆增加一个第一列非空的条件,这样可以有效地缩减搜索空间。
这种情况下我们把第一列叫做前排(front)。如果搜索顺序是一行一行地搜,则把第一行叫做前排;如果搜索顺序是对角方向,则把第一行和第一列都算作前排。
不过,我们还需要定义什么是空——由于 B0 规则的存在,我们不能简单地把死细胞定义为空。这里我们采取的定义是:对于每一代,如果一个细胞的状态和搜索范围之外的细胞一致,则称其为空。也就是说:
当我们说一个细胞集合(比如说前排)为空时,指的是集合中每一个细胞都为空。同样到了,说这个集合非空指的是至少有一个细胞非空。
搜索的时候,我们可以用一个变量来记录前排中未知或已知非空的细胞的数量;每次搜到一个在前排的细胞,都根据其状态的变换来更新这个变量;如果变量变成了0,则说明当前的 partial result 不满足前排非空的条件,没必要在它上面浪费时间,可以直接回头。
然后问题来了:什么时候可以要求前排非空?
或者换句话说,怎样的搜索条件有平移不变性,即任何满足此条件的图样在向指定方向平移之后还满足同样的条件?
条件的平移不变性
我们按网页版的 Setting,从上到下一条一条分析:
后面几个选项也都无关,不一一讨论了。
也就是说,我们需要考虑的只有对角宽度、变换、对称、已知的细胞这几个选项。
半个前排
但有时我们不需要考虑整个前排:比如说,假如我们要搜 45x10 大小向左飞的 c/4 飞船,搜索顺序还是从左到右一列一列地搜,找到了这么一个玩意儿:
注意它一个周期的四个回合中,第一列的上半部分都是空的。如果我们把它上下翻转一下,结果还是满足所有的条件:
因此,我们可以要求一个第一列的上半部分非空,进一步缩减搜索空间。
(写到这里忽然发现这个条件还可以进一步加强:把第一列所有回合的细胞状态写成一个二进制数,然后要求这个二进制数不能小于把它所有数位左右翻转的结果;或者把第一列的上半部分和下半部分写到两个二进制数中,然后比较这两个数就行了。不过 Rust 中整数大小是有限的,用 64 位的整数表示的话就不支持前排超过 64 个细胞的情形;Generations 的规则要把二进制改成 n 进制,能支持的前排细胞数更少,实现上也更复杂一些。)
类似地,如果搜索顺序是一行一行地搜,则只考虑第一行的左半边;如果搜索顺序是对角方向,只考虑第一列。
为了能加上这个条件,我们要要求搜索条件在翻转变换下不变。
如果以图样中心处为原点的话,这里涉及到的三种翻转如下:
(x,y) => (-x,y)
(x,y) => (x,-y)
(x,y) => (y,x)
(等等,写到这里我发现我的实现有个严重的 Bug:非各向同性的规则是不能随便翻转的!这有点难办……等改好这个 Bug 再继续写吧。)
(以上 Bug 已修复……希望不要引入新 Bug……)
和之前一样,所有设置从上到下一条一条分析:
看起来变换、对称和已知细胞的条件比前排非空要宽松。不过我们是在要求前排非空的前提下才能考虑半个前排,所以实际新增的条件只有规则(差点又忘了)、宽度、高度、dx、dy 这些。
前排的第一代
前面说的前排指的是前排的每一代。要求前排非空等价于要求至少有一代的前排非空。于是,对于振荡子(也就是 dx、dy 为 0 的情形),只要规则没有 B0,我们可以干脆前排非空的那一代定为第一代,于是可以要求前排的第一代非空,进一步缩减搜索空间。
但对飞船来说,问题没这么简单。事实上,对于周期为 p 的振荡子,第 p+1 代和第一代是一样的,因此第二代到第 p+1 代也满足原本的条件。但对飞船来说,第 p+1 代相比第一代还会有一个平移,可能会平移出原本的高度和宽度所规定的范围。
不过,搜索飞船的一种常见情况是:每个周期仅平移一格,而且平移的方向正好是向着前排。
比如说,假如我们要搜 21x13 大小向左飞的 c/4 飞船,对称性是 D2-,搜索顺序还是从左到右一列一列地搜,找到了这么一个玩意儿(这次把每一代都画出来了,从左到右):
这飞船前排的第一代是空的。于是,它的第五代只是把第一代向前平移一格,并不会移出规定的范围。也就是说,它的第二到第五代也满足原本的条件:
因此,这种情况下也可以要求前排的第一代非空。
也就是说,如果要要求前排的第一代非空,在前排非空的条件的基础上,我们还需要:
(写到这里忽然发现,没必要完全禁掉 B0 的规则,其实可以改成要求前排的前两代非空;对于 Generations 的规则,若有 n 种状态,则可以改为前排的前 n 代非空。这里需要的改动很小,已改。)
没那么前的前排
上一节的讨论只适合飞船每个周期向前平移一格的情形。如果平移不止一格呢?
此时,我们不能再要求前排的第一代非空。事实上,此时前排的第一代必须是空的,因为这些细胞的前一代的整个邻域都已经在搜索范围之外。
不过,我们可以把“前排”往后挪一挪。
比如说,假如我们要搜 12x15 大小向左飞的 2c/5 飞船,对称性是 D2-,搜索顺序还是从左到右一列一列地搜,找到了这么一个玩意儿(这次把每一代都画出来了,从左到右):
它第一代前两列都是空的。第六代只是把第一代向前移动两格,不会移出规定的范围。于是,和之前一样,我们可以考虑它的第二到第六代:
于是,我们可以干脆把前排的定义从第一列移到第二列,继续要求新的“前排”的第一代非空。
一般地,如果飞船每个周期向前平移 d 格(平移的方向必须向着前排),我们就可以把前排的定义修改为第 d-1 行/列/行加列。
但我们还要说明新的要求比原本要求的前排(所有代)非空要强,不然直接用原本的要求不就行了吗?
这也不难。一个细胞非空的必要条件是它前一代的邻域中至少有一个细胞非空。若飞船周期为 p,新的前排是第 d-1 列,那么新前排的前一代对应于第 p 代往前刚离开搜索范围的那一列,其邻域的三列只有一列在搜索范围之内,也就是第 p 代的第一列。因此,只要要求新的前排第一代非空,旧的前排就一定也非空。
于是,我们可以把上一节的条件改进为:
此时“前排”的定义为:
目前 rlifesrc 采用的前排非空的条件就是这么多。
自定义对称性
前面说了这么多,一方面是为了总结和查 bug,另一方面是为实现 #51 中提到的自定义对称性做准备。
其实说“自定义对称性”有点不准确,因为这也包含了一些不属于对称性的条件。
我们想要支持哪些条件呢?先试着列举一下。
区域怎么定义,允许哪些变换,都是需要讨论的。
自定义对称性最好还能写成一种方便读取的格式,比如说 JSON。
(未完待续)
The text was updated successfully, but these errors were encountered: