0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ポケットキューブ(2×2×2)— 367 万局面を 2 つの数え方で全部解いて公表値 446 個を突き合わせたら、Wikipedia の「最大位数 45」だけが群を取り違えていた

0
Posted at

ポケットキューブ(2×2×2 のルービックキューブ)をブラウザに実装した。ページを開くとタブの中で全 3,674,160 局面を幅優先でたどり(約 1 秒)、どの局面でも「あと何手か」を面回転(half turn も 1 手)と 90° 回転(half turn は 2 手)の両方で表示する。18 個の回転ボタンにはそれぞれ「押したら何手になるか」が出る。距離の表は Wikipedia(英・日)・OEIS A079761 / A079762・Jaap Scherphuis の 2 メトリクス同時分布(180 セル)とすべて一致し、6・24・48 対称で割った局面数、R と U だけで作る 2 生成元群(29,160 局面、直径 17、対蹠点 18 個)の Bump & Auerbach (2006) の表と対蹠点どうしの距離も一致した。公表値は論文の PDF や wikitext からスクリプトで抜き出して照合していて、手で写した数字は 1 つもない。446 個中 445 個が一致。合わなかった 1 個は Wikipedia の「この群(位数 3,674,160)の元の最大位数は 45。例: U R² L′」で、この群の最大位数は 36 だった。45 は角を 1 つも固定しない 24 倍の群(88,179,840)の値で、例の L′ は固定したはずの角を動かす。ただし実物のキューブで U R² L′ を繰り返すと、持ち替えを許しても 45 回目で初めて揃って見える。「周期 45 の手順」はあるが「位数 45 の元」は 367 万の群にはない。そのからくり(9 回で持ち方が戻り、その 18 手が位数 5)もページで確かめられる。テスト 11 件。ソルバー内蔵パズル第 78 弾。

デモ: https://sen.ltd/portfolio/pocket-cube/
リポジトリ: https://github.com/sen-ltd/pocket-cube

ポケットキューブ

ルールと 2 つの数え方

2×2×2 のキューブは 8 個の角のブロックだけでできている。6 面それぞれを 90°・180°・270° 回せるので、回し方は 18 通り(U, U2, U′, R, …, B′)。全面を 1 色ずつに揃えれば完成。

「何手」の数え方は 2 つある。

数え方 1 手とは 最大 平均
面回転(face turn, HTM) 1 つの面を 90°・180°・270° のどれか回す 11 8.7556
90° 回転(quarter turn, QTM) 1 つの面を 90° 回す(180° は 2 手) 14 10.6664

ページではどちらの数え方で Hint / Solve するかを選べる。距離パネルには両方の値と、「この距離にある局面は全体の何 %」が出る。

局面は 3,674,160 個、群は 2 つ

角 8 個の並べ方が 8!、ひねりは 7 個まで自由(合計は 3 の倍数)で 3^7。2×2×2 にはセンターがないので、キューブ全体の持ち方 24 通りは同じ局面とみなして割る。

$$\frac{8! \times 3^7}{24} = 7! \times 3^6 = 3{,}674{,}160$$

コードでは、群を 2 つ区別して持つ。

  • G: 18 通りの面回転で作れる状態すべて。8!·3^7 = 88,179,840 個。キューブ全体の持ち替えもこの中に入る(x = R L′ など)
  • H: 左下奥の角(DBL)を動かさない状態。U・R・F だけで作れる群で、7!·3^6 = 3,674,160 個

G のどの状態も「H の元 1 つ」×「持ち替え 24 通りのどれか」にちょうど 1 通りに分解できる。だから「持ち方を無視した局面」は H そのものになる。持ち替えで DBL を元の位置・向きに戻せばよい。

/**
 * The same position held so that DBL is home: the unique h in H and rotation r
 * with a · r = h. Positions "up to how you hold the cube" are exactly H.
 */
export function normalize(a: Cube): { h: Cube; r: number } {
  for (let r = 0; r < ROTATIONS.length; r++) {
    const h = mul(a, ROTATIONS[r]);
    if (inH(h)) return { h, r };
  }
  throw new Error('unreachable: every state is one of H times a rotation');
}

状態は Kociemba の CubieCube と同じく、スロット i にある角 cp[i] とそのひねり co[i] の組で、積 mul(a, b) は「a をしてから b」。D を回すのは、U を回して全体を持ち替えたのと同じ(D と U は可換で、D = U·y′)。なので距離を調べるには U・R・F の 9 手だけで足りて、D・L・B の 9 手は持ち替えれば U・R・F のどれかになる。テストでは、ランダムな 200 局面すべてで「D, D2, D′, L, … B′ を押した後の距離」の列が「U, U2, U′, R, … F′」の列と一致することを確かめている。

幅優先: 置換表 5,040 × 9 とひねり表 729 × 9

H の局面に 0 〜 3,674,159 の番号を振る。動く 7 個の角の並び(Lehmer 符号で 0 〜 5,039)× 最初の 6 個のひねり(3 進 6 桁で 0 〜 728)。

回転は「角がどこへ行くか」と「ひねりがどう変わるか」を独立に変える。行き先はひねりに依存せず、新しいひねりは古いひねりと回転だけで決まる。なので探索の中ではキューブを掛け算せず、5,040 × 9 と 729 × 9 の 2 つの表を引くだけになる。

export function godsTable(tables: MoveTables, gens: number[]): Uint8Array {
  const dist = new Uint8Array(N_H).fill(UNSEEN);
  const nm = H_MOVES.length;
  const { perm, twist } = tables;
  dist[0] = 0;
  let found = 1;
  for (let d = 0; found > 0; d++) {
    found = 0;
    for (let i = 0; i < N_H; i++) {
      if (dist[i] !== d) continue;
      const p = (i / N_TWIST) | 0;
      const t = i - p * N_TWIST;
      for (const m of gens) {
        const j = perm[p * nm + m] * N_TWIST + twist[t * nm + m];
        if (dist[j] === UNSEEN) {
          dist[j] = d + 1;
          found++;
        }
      }
    }
  }
  return dist;
}

gens に 9 手全部を渡せば面回転、U, U′, R, R′, F, F′ の 6 手なら 90° 回転の距離になる。1 局面 1 バイトで 3.6 MB。2 つの表を両方作っても Node で 1.2 秒、手元の Chromium でも 1.1 秒前後で、ページはこれを開くたびに作っている。

距離 面回転 90° 回転
0 1 1
1 9 6
2 54 27
3 321 120
4 1,847 534
5 9,992 2,256
6 50,136 8,969
7 227,536 33,058
8 870,072 114,149
9 1,887,748 360,508
10 623,800 930,588
11 2,644 1,350,852
12 782,536
13 90,280
14 276

2 列とも OEIS A079761 / A079762、英語版・日本語版 Wikipedia の表と全項一致。Wikipedia の割合の列(a% と q%、30 個)も、ここで出した比をその桁数で丸めた値と全部一致した。

2 つの数え方の同時分布

Jaap Scherphuis のページには、面回転の距離を列、90° 回転の距離を行にした 15 × 12 の表がある。距離の表を 2 つ持っていれば、同時分布は 1 回なめるだけで出る。180 セル(空欄は 0)と行・列の合計 27 個がすべて一致し、平均の 8.7556 / 10.666 も一致した。

90° 回転で最も遠い 276 局面は、面回転では 9 手が 8 個、10 手が 160 個、11 手が 108 個で、面回転でも最遠(11 手)とは限らない。ページのスクリーンショットの局面も、面回転 11 手・90° 回転 13 手。

対称で割る: 48 通りをステッカーの置換で

英語版 Wikipedia にはもう 1 つ、「対称で同じとみなした局面数」の表がある。

  • 6 通り: 固定した角(DBL)の位置を保つ対称。対角線まわりの 3 回転 × 鏡映
  • 24 通り: キューブの回転すべて
  • 48 通り: 回転と鏡映すべて

局面 h と対称 s に対して s·h·s⁻¹(同じ手順を回した・鏡に映した世界でやったもの)を同じとみなす。鏡映は時計回りのひねりを反時計回りに変えるので、(cp, co) の算術では書きにくい。そこで対称は 24 枚のステッカーの場所の置換として作った。ステッカーの中心座標(面の法線方向に ±2、他の 2 軸に ±1)に 48 通りの符号付き置換行列を掛け、行き先のステッカーを探す。

/** s · a · s⁻¹: the same position seen in the frame s. */
export function conjugate(a: Cube, s: Symmetry): Cube {
  const w = toStickers(a);
  const out = new Array<number>(24);
  for (let x = 0; x < 24; x++) out[s.perm[x]] = s.perm[w[x]];
  return fromStickers(out);
}

共役した結果は DBL を動かしていることがあるので、normalize で持ち直してから番号を引く。数え方は、番号順に見ていって未見の局面に当たったら、その軌道(高々 48 個)に全部印を付け、類を 1 つ数える。

面回転 対称なし 6 24 48
0 1 1 1 1
1 9 2 3 2
2 54 9 9 5
3 321 54 36 19
4 1,847 309 132 68
5 9,992 1,670 529 271
6 50,136 8,361 2,276 1,148
7 227,536 37,943 9,768 4,915
8 870,072 145,046 36,582 18,364
9 1,887,748 314,710 79,006 39,707
10 623,800 104,076 26,137 13,225
11 2,644 449 129 77
計 3,674,160 612,630 154,608 77,802

36 個と合計 4 個がすべて一致(3 種類で 20.8 秒)。テストでは、48 通りの共役が 18 手の集合をそれ自身に写すこと(鏡映は U を U′ 系に写す)と、共役しても距離が変わらないことも確かめている。

R と U だけの群: Bump & Auerbach (2006)

Wikipedia が引いている Daniel Bump と Daniel Auerbach の論文 "Unravelling the (miniature) Rubik's Cube through its Cayley Graph"(2006)は、R と U だけで作る群を調べている。元の URL は消えていて、Wayback Machine の PDF から数字を抜いた。

  • 位数 29,160、直径 17(R, R′, U, U′ を 1 手とする)
  • 距離ごとの局面数 1, 4, 10, 24, 58, 130, 271, 526, 980, 1750, 2731, 3905, 5229, 5848, 4792, 2375, 508, 18
  • 距離 17 の 18 個(対蹠点)の手順 A1 〜 A18
  • 対蹠点は 4 つの塊に分かれ、塊の中では 6 か 8 離れていて、名指しされた 8 組は 10 または 12、塊どうしは最低 10

同じ godsTable に R, R′, U, U′ の 4 手を渡すだけで、位数・直径・18 項すべてが一致した。18 個の手順はどれも距離 17 で、距離 17 の局面はこの 18 個で全部だった。

対蹠点どうしの距離は、最初は 8 個が合わなかった。名指しの 10 の 2 組が 12 になり、塊どうしの最小が 6 になる。原因は積の向き。論文の群は関数の合成と同じく右から左に掛けていて、ケイリーグラフの距離 x⁻¹y は、手順を左から右に読むこのコードでは x·y⁻¹ になる。そう読むと、名指しの 8 組、その他の塊内の 24 組、塊どうしの最小 10 がすべて一致した。PDF のテキストでは R′ が「R0」、U2 が「U 2」になっていたので、抽出スクリプトで戻している。

本題: 「この群の最大位数は 45」

英語版 Wikipedia の Pocket Cube の記事には、局面数の式のすぐ後にこうある。

7!·3⁶ = 3,674,160. This is the order of the group as well.
The largest order of an element in this group is 45. For example, one such element of order 45 is (U R² L′).

元の位数とは、その操作を何回繰り返すと完全に元に戻るか。数えてみる。

位数は巡回の長さとひねりで決まる

角の置換を巡回に分けると、長さ k の巡回は k 回で角が元の場所に戻る。そのとき巡回に含まれる角のひねりの合計が 3 の倍数でなければ、角はひねられた状態で戻ってくるので、さらに 3 倍の 3k 回かかる。元の位数は各巡回の値の最小公倍数。

export function order(a: Cube): number {
  const seen = [false, false, false, false, false, false, false, false];
  let L = 1;
  for (let i = 0; i < 8; i++) {
    if (seen[i]) continue;
    let j = i, len = 0, twist = 0;
    while (!seen[j]) {
      seen[j] = true;
      twist += a.co[j];
      j = a.cp[j];
      len++;
    }
    L = lcm(L, twist % 3 ? 3 * len : len);
  }
  return L;
}

45 = lcm(15, 9) を作るには、ひねりの合計が 3 の倍数でない 5 巡回と 3 巡回が要る。角が 8 個必要になる。ところが位数 3,674,160 の群 H は DBL を固定しているので、動く角は 7 個しかない。

全元を歩く、紙の上で数える

2 通りで数えた。

  1. 全元を歩く: H の 3,674,160 元を番号から復元して位数を出す(2.8 秒)。G の 88,179,840 元は「H の元 × 持ち替え 24 通り」で全部作り、型付き配列で位数を出す(35.2 秒)
  2. 紙の上で数える: 角の巡回型(分割)ごとに、その型の置換の数 n!/∏k^{m_k} m_k! と、各巡回のひねりの合計が 0・1・2 になる割り当て(それぞれ 3^{k−1} 通り)を掛け、全体の合計が 3 の倍数になる組だけ足す。H は角 7 個、G は角 8 個

2 つの方法の表は完全に一致した。

位数 H(3,674,160、DBL 固定) G(88,179,840、全面回転)
1 1 1
2 3,843 21,819
3 40,418 355,994
4 56,700 1,440,180
5 40,824 108,864
6 521,766 8,859,102
7 524,880 4,199,040
8 · 11,022,480
9 215,460 2,340,576
10 122,472 979,776
12 657,720 12,950,280
15 326,592 4,790,016
18 714,420 16,057,440
21 · 8,398,080
30 244,944 7,838,208
36 204,120 4,898,880
45 · 3,919,104

位数 3,674,160 の群の最大位数は 36(204,120 元)。最短の手順は 4 手で、U R′ F R2 など 24 通りある。45 は G にしかなく、3,919,104 元。例の U R² L′ も G の元で、L′ は DBL を含む面を回すので H には入らない(H は U・R・F で作る群)。

位数 8(8 巡回)が H に無いのも同じ理由で、7 個の角では作れない。位数 21(ひねった 7 巡回)も H には無い。7 巡回は動く角 7 個を全部含むので、ひねりの合計は必ず 3 の倍数になる。同じ理屈で G でも 8 巡回はひねれず、位数 24 はどちらにも無い。

いつ誰が書いたか

記事の版履歴を二分探索した。この文は 2025 年 2 月 8 日 21:13(UTC)に匿名の IP ユーザーが追加していて、最初の例は (URL′R) だった。同じ IP が 34 分後に (UR²L′) に書き換えている(L′ と R は向かいの面なので可換で、U R L′ R = U R² L′。同じ元)。追加した版から 2026 年 9 月 13 日の最新版までの 93 版で、この文はずっと残っている(抜き取りで確認)。日本語版にはこの記述はない。

それでも 45 は実物で起きる

では 45 は間違いなのかというと、キューブを手に持って U R² L′ を繰り返すと、45 回目で初めて揃って見える。持ち替えを許して「どの向きで見ても揃っていればよい」としても 45 回。ページの「repeat a sequence」の ×45 ボタンで試せる。

ここで区別が要る。

  • 手順を k 回繰り返した状態は g^k(g は G の元)
  • 「揃って見える」は g^k が持ち替え 24 通りのどれかになること。その最小の k を周期と呼ぶ。周期は位数の約数で、G の位数 45 の元 3,919,104 個は全部、周期も 45 だった

DBL を固定して持ち直すと、U R² L′ の 1 回分は U R になる(L′ は R′ と、x の持ち替えを一緒にしたもの)。U R の位数は 15。ところが 2 回目の U R² L′ は、持ち替えた後の向きで回すので、固定した DBL から見ると別の面を回している。1 回ごとに DBL 固定の手順に翻訳すると:

U R · F R · U F · R F · U F · R U · F U · R U · F R

9 回で持ち方が最初に戻り、この 18 手(H の元)の位数は 5。だから 9 × 5 = 45 回で揃う。

つまり「周期 45 の手順」はあるが、「位数 45 の元」は 3,674,160 の群にはない。局面を「持ち方を無視したもの」とみなすと群 H と同じ集合になるが、L・D・B を含む手順は、毎回同じ H の元として働くわけではない。Wikipedia の文は、G の性質(位数 45)と H の大きさ(3,674,160)を 1 つの「群」として書いてしまっている。正しくは「DBL を固定した群(位数 3,674,160)の最大位数は 36。全面回転の群(位数 88,179,840)では 45 で、例えば U R² L′。この手順は実物でも 45 回で初めて揃って見える」。

ページの実装

  • 最短解は U・R・F だけで足りる。どの角が DBL の位置にあっても、U・R・F は向かい合う面の組から 1 つずつなので、持ち直した後の 9 手に対応する。Solve は「距離が 1 減る手」を表から選んでいくだけ
  • ボタンのヒント: 18 手それぞれについて「押した後の距離」を表から引き、縮むなら緑、伸びるなら赤。D と U のように向かいの面は常に同じ値になる
  • スクランブル: 距離ごとの局面数が分かっているので、「ちょうど 11 手」「ちょうど 14 手(90° 回転)」の局面を一様に引ける
  • repeat a sequence: 手順を入力すると位数・周期・DBL を保つかを表示し、周期の回数だけ繰り返せる。x・y・z の持ち替えも書ける
  • アニメーションの各手は、クリック時にまとめて setTimeout を予約している。タイマーを連鎖させるとヘッドレスのブラウザで途中で止まるため

公表値は手で写さない

tools/fetch-literature.mts が、英語版 Wikipedia の wikitext(版番号つき)、日本語版の wikitext、Jaap のページの HTML の表、OEIS の JSON、Bump & Auerbach の PDF(pdftotext)から数字を抜いて tools/literature.json に書く。tools/stats.mts がそれを読み、全部計算し直して項目ごとに突き合わせ、不一致は止めずに記録する。

丸めて印刷された値(平均や %)は、「こちらの正確な比を、その値が表示している桁数で丸めると一致するか」で判定している。

照合 値の数 一致
距離ごとの局面数(Wikipedia 英・日、OEIS) 81 81
同時分布と合計(Jaap) 207 207
局面数・神の数・平均 10 10
割合 a%・q%(Wikipedia) 30 30
対称で割った局面数(Wikipedia) 40 40
R・U の群: 位数・直径・距離ごと(Bump & Auerbach、Wikipedia) 21 21
対蹠点 18 個と、その間の距離 53 53
関係式 2 つ 2 2
「最大位数 45」とその例 2 1
計 446 445

npm run stats は全部で 60.5 秒(ほとんどが G の全元の位数と対称類)。

まとめ

  1. 群を 2 つ区別する。 18 手で作れる G(88,179,840)と、DBL を固定した H(3,674,160)。G の元は H の元 × 持ち替えに一意に分解できるので、H が「持ち方を無視した局面」そのものになる
  2. 置換とひねりは独立に動く。 5,040 × 9 と 729 × 9 の表で、2 つの数え方の幅優先が 1 秒あまり。ブラウザで毎回作れる
  3. 鏡映はステッカーの置換で。 (cp, co) の算術ではなく 24 か所の置換にすると、48 対称が同じコードで扱える
  4. 積の向きを確かめる。 Bump & Auerbach の距離は、右から左に掛けたときだけ一致する
  5. 「群の元の位数」と「手順の周期」は別物。 3,674,160 の群の最大位数は 36。45 は 24 倍の群の値で、実物では U R² L′ が 45 回で揃って見えるが、その理由は 9 回で持ち方が戻ることと、その間の 18 手が位数 5 であること

数値はすべて npm run stats が出力する src/stats.json から、ページの notes とこの記事に写している。テスト 11 件。ソルバー内蔵パズル第 78 弾。

参考文献:

  • Wikipedia, "Pocket Cube"(revision 1374673355, 2026年9月13日版。2026年9月29日参照)
  • Wikipedia, 「ポケットキューブ」(2026年9月29日参照)
  • Jaap Scherphuis, "Pocket Cube / Mini Cube", https://www.jaapsch.net/puzzles/cube2.htm (2026年9月29日参照)
  • OEIS A079761, A079762
  • D. Bump, D. Auerbach, "Unravelling the (miniature) Rubik's Cube through its Cayley Graph" (2006), Wayback Machine 経由
  • H. Kociemba, "Cube Explorer" の CubieCube の定義(角の番号と回転)

デモ: https://sen.ltd/portfolio/pocket-cube/
リポジトリ: https://github.com/sen-ltd/pocket-cube

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?