魔方的贴纸图:三束圆与转层
一段流传颇广的动图把魔方画成一张图:左边五十四个彩色圆点摆在几条灰色圆弧上,右边一个三阶魔方不停地转,每转一次左边的颜色就跟着流动一轮,配的说明是「魔方是一张有 43 quintillion 个顶点的图」。说明与画面说的是两张不同的图。说明里那张的顶点是魔方的整个状态,三阶共 个,边是六种面转;画面上那张的顶点只有 个,一个顶点就是一张贴纸。本页还原的是后者,并把它推广到任意阶数。
那些圆弧不是随手画的装饰。把动图逐帧取出来、对灰色像素做圆拟合,得到的是三个圆心与三档半径:圆心两两相隔 、离图心 137 像素,半径 192、247、302 像素,九条圆分成三束各三条。再取 54 个色块的重心,每个重心到其中两条圆的距离偏差都在一个像素以内,而到第三束的任何一条都差着上百像素。原先的猜想是每张贴纸对应三个层号、该落在三条圆上,实测把它推翻了:落点只在两条圆上,第三个层号在整面上是常数,图上不必画。
本页按这条实测反推构造:先把层与转动的账算清楚(§1),再从体对角线方向的正投影看出三族平行线(§2),把直线弯成同心圆后交点数自动配平(§3),随后转一层就成了绕一个圆心挪一步(§4),最后把阶数放开到 2 至 7(§5)。
1 · 贴纸与层
阶魔方的表面铺着 张贴纸,六个面各 张。可动结构则沿三根互相垂直的轴切开。
定义 1.1(层) 取一根坐标轴 与一个下标 ,。层 指所有沿 方向第 格的小方块,连同它们表面的贴纸。一根轴给出 层,三根轴共 层,每层可独立转四分之一圈。
每张贴纸沿每根轴各属于一层,三个层号把它在方块上的位置定死。转动层 时,落在这一层里的贴纸被搬走,其余原地不动。 取 或 时动的是 张:这一面自己的 张,加上四个侧面各一条 张的窄带; 取中间值时那一面不存在,只动 张。
| 阶数 | 贴纸 | 层数 | 转外层挪动 | 转中间层挪动 |
|---|---|---|---|---|
| 2 | 24 | 6 | 12 | 无中间层 |
| 3 | 54 | 9 | 21 | 12 |
| 4 | 96 | 12 | 32 | 16 |
| 5 | 150 | 15 | 45 | 20 |
| 7 | 294 | 21 | 77 | 28 |
为奇数时每面正中那张贴纸在本面的转动下原地不动,故「转外层挪动」一栏记的是这一层贴纸的总数 ,真正换位的比它少一张。
2 · 体对角线方向的正投影
把方块沿体对角线 方向作正投影,外轮廓是一个正六边形,三个朝向观察者的面各占一个 菱形。三根轴的投影两两相隔 ,垂直于某根轴的那 个层平面随之投影成一族互相平行的直线,三族直线两两成 。
这张投影已经把层结构画对了。一张贴纸的两个面内层号,正好是它落在哪两族直线的交点上;第三个层号由所在的面决定,整面共用一个值,图上无须为它画线。
代价是前后重叠: 面与 面投影到同一片菱形上,两族平行线交出的每一个点上坐着两张贴纸。分开它们不需要另起炉灶,只需让每族直线弯一点。
3 · 同心圆束与交点计数
把每族平行线换成一束同心圆:圆心放在该族直线的法线方向上、离图心 处,三个圆心两两相隔 ;同一束里层号 取第 小的半径,于是层号沿半径递增的方向排开。直线是圆心退到无穷远的极限情形,弯过来之后两条圆不再交出一个点,而是交出两个,分居两圆心连线的两侧,一侧归 面、一侧归 面。
计数就此配平:三束两两配对得三组,每组 对圆,每对两个交点,共 个,与贴纸数一个不差。
命题 3.1 记两个圆心的间距为 。若同一束内最大与最小半径之差小于 ,且最小的两条半径之和大于 ,则任意两条异束的圆都恰有两个交点。
证明 两条圆有两个交点当且仅当 。左半边对所有圆对成立的最紧情形是取同一束内的最大与最小半径,右半边的最紧情形是取全局最小的两条半径。两条前提分别管住这两个极端,其余圆对更宽松。∎
每条圆经过哪些贴纸也随之定下。束 的第 条圆穿过所有「沿 的层号为 ,且不在 两面上」的贴纸,四个侧面各 张,共 张。 两面上的贴纸沿 的层号同样是 或 ,但它们的位置由另外两束定,不画在这条圆上。三束合计 ,与「每个交点恰在两条圆上」互相印证。
4 · 圆上的弧与转动
转动层
把这
张贴纸在四个侧面之间轮换一圈。按绕束
圆心的幅角把它们排成一条环形带子,四个面各占连续的一段弧,转动把整条带子挪
格。这条性质由 core/layout.test.ts 对 2 至 7 阶、全部
条圆、两个转向逐条验着:每条带子上
个位移值只有一种取值,且必为
或
,后者就是反向的
格。
转外层时还有一份账。那一面自己的 张贴纸不在这条圆上,它们在自己那一片曲边九宫格里转过 。这一片由另外两束的圆交出,两族在交点处的夹角按默认参数实测落在 到 之间,就是正六边形里那三个 菱形被圆弧扭过之后的样子。所以那 在图上读起来更像一次翻折:菱形没有四重对称,转四分之一圈落不回自己。
注 · 四段弧沿圆排得很不均匀。三阶 U 层那条圆上,十二张贴纸的行程分成四档:、、、,四档相加恰是一整圈。最长那一档跨在两片较远的九宫格之间,这两片分列圆心两侧,之间的弧要绕过圆的顶端。转动动画里因此有三张贴纸跑得比同伴远得多,那一截长途正是这 。
5 · 二阶到七阶的形状
构造的自由度只有两个:中间那条圆的半径 ,与最外最内两条的半径差 (圆心间距 取作长度单位)。把参考图的实测值换算过来即 、,本页的默认取值以它为准,并让 随阶数放大,免得圆条数变多之后相邻两条越挤越近。
的上限是扫出来的,结果有点出乎意料:命题 3.1 的可行域允许 一直取到 ,但 超过约 1.14 时「四个面各占一段连续的弧」就不再成立,而九宫格之间开始咬合更早,约在 1.05。更要紧的是这两个上限与阶数无关——一片九宫格的大小只由 与 决定,阶数只改变往这片里塞多少个点。默认值把 封在 1.0;七阶那 294 个点靠缩小点半径塞进同样大的一片九宫格。
实体那半边没有复用站内的 shared/geom3d.ts,理由是它的屏幕基满足
,与「沿 fwd 看过去」应有的右手系差一个镜像。立体几何的图形不在乎左右手,一个正方体的镜像还是正方体;魔方在乎,镜像之后 R 的顺时针会变成逆时针,页面上的记号与实体对不上。core/view.ts 改为自带一套十几行的正投影,并在单测里把
与「默认视角下 R 在右、F 在左」一起钉死。
另一处踩到的是 SVG 圆弧的 sweep-flag。转动去处的那些虚线弧本该严丝合缝地贴着圆走,第一版却整片横穿图心:给定半径与两个端点的圆弧有两个可能的圆心,sweep-flag 取反就选中了另一个。根子在画布的
轴朝下——数学坐标里的逆时针在屏幕上是顺时针,两套口径差一个镜像,与上一段是同一个坑的两种穿法。
6 · 参考文献
- Rubik's Cube. Wikipedia. 三阶魔方的构造、记号与状态数的推导。https://en.wikipedia.org/wiki/Rubik%27s_Cube
- Rubik's Cube group. Wikipedia. 以面转为生成元,魔方状态构成的置换群。https://en.wikipedia.org/wiki/Rubik%27s_Cube_group
- Optimal solutions for the Rubik's Cube. Wikipedia. 上帝之数:三阶任意状态在半转记号下 20 步内可解。https://en.wikipedia.org/wiki/Optimal_solutions_for_the_Rubik%27s_Cube
- Isometric projection. Wikipedia. 沿体对角线的正投影,正方体成正六边形、可见面成 60° 菱形。https://en.wikipedia.org/wiki/Isometric_projection
- Pencil (geometry). Wikipedia. 圆束的定义,同心圆束是其中最简单的一族。https://en.wikipedia.org/wiki/Pencil_(geometry)
- Incidence structure. Wikipedia. 点与线的关联结构;本页那张图是 个点与 条圆的关联图。https://en.wikipedia.org/wiki/Incidence_structure