# Cubejs

> cubejs (Rubik's Cube solver, Kociemba two-phase) 使用指南。當需要實作魔術方塊自動解法、狀態字串序列化、或 scramble 產生時使用。

- Skill: `recca0120/cubejs` (Agent Skill)
- Install (CLI): `npx skillmds@latest add recca0120/cubejs`
- Raw SKILL.md: https://api.skillmd.com/api/skills/recca0120/cubejs/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: recca0120 (https://skillmd.com/u/recca0120)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/recca0120/cubejs

---


# cubejs 魔術方塊 Solver

> 注意：npm 有兩個同名套件！**魔術方塊 solver 是 `cubejs`（lgarron/cubejs）**，另一個 `@cubejs-client/*` 是 Cube.dev BI 工具，完全不同。

## 套件選擇

| 套件 | 演算法 | 解長度 | 初始化 | 備註 |
|---|---|---|---|---|
| **cubejs** | Kociemba 2-phase | ~20 | ~2-5s load tables | 老但穩定、檔案小 |
| **min2phase** | Kociemba 優化 | ~20 | 類似 | 更快解，TypeScript 較差 |
| **cubing.js** | 多演算法 | 依需求 | 較重 | 完整 cube 生態，推薦 |
| **rubiks-cube-solver** | Layer-by-layer | 100+ | 即時 | 適合教學步驟（長但易理解） |

**本專案建議**：
- **自動解（最短解）**：`cubejs` 或 `cubing.js`
- **教學模式（Layer-by-Layer 步驟）**：自己實作 LBL，不用 solver（教學需要固定步驟邏輯）

## 安裝

```bash
pnpm add cubejs
```

無 types，加一份 `src/types/cubejs.d.ts`：

```ts
declare module 'cubejs' {
  export default class Cube {
    static fromString(s: string): Cube
    static random(): Cube
    static scramble(): string
    static initSolver(): void
    static asyncInitSolver?(): Promise<void>
    asString(): string
    solve(maxDepth?: number): string
    move(alg: string): Cube
    isSolved(): boolean
    clone(): Cube
  }
}
```

## 狀態字串格式

54 字元，URFDLB 面順序，每面 9 格 row-major（從左上到右下）：

```
UUUUUUUUU RRRRRRRRR FFFFFFFFF DDDDDDDDD LLLLLLLLL BBBBBBBBB
(共 54 字元，無空格)
```

面字母也代表顏色（U=白, R=紅, F=綠, D=黃, L=橘, B=藍 — 依標準配色）。

## 基本用法

```ts
import Cube from 'cubejs'

// 1. 初始化 solver tables（耗時，只需一次）
Cube.initSolver()  // 或 await Cube.asyncInitSolver()

// 2. 建 cube
const cube = Cube.fromString('UUUUUUUUURRR...')  // 54 char
// 或 const cube = new Cube()  // 已還原
// 或 const cube = Cube.random()  // 隨機打亂

// 3. 解
const solution = cube.solve()  // e.g. "R U R' U' F2 L"

// 4. Scramble
const scrambleAlg = Cube.scramble()  // 25 moves 字串
```

## Worker 初始化（必做）

solver table 載入 2-5 秒會阻塞 UI，一定要放 Web Worker：

```ts
// src/workers/solver.worker.ts
import Cube from 'cubejs'
Cube.initSolver()
self.onmessage = (e: MessageEvent<string>) => {
  const cube = Cube.fromString(e.data)
  self.postMessage(cube.solve())
}
```

```ts
// 使用端
import SolverWorker from './workers/solver.worker.ts?worker'
const worker = new SolverWorker()
worker.postMessage(facelets)
worker.onmessage = (e) => setSolution(e.data)
```

## 與 3D 狀態互轉

把 3D cube 的 54 貼紙按 URFDLB 順序組字串；若顏色不是預設，做一層 color → face 字母的 map（中心塊決定哪個顏色代表哪面）。

```ts
function faceletsFromColors(colors: Color[]): string {
  const centers = [colors[4], colors[13], colors[22], colors[31], colors[40], colors[49]]
  const face = ['U','R','F','D','L','B']
  const map = new Map(centers.map((c, i) => [c, face[i]]))
  return colors.map((c) => map.get(c)!).join('')
}
```

## 常見陷阱

1. **忘記 initSolver**：`solve()` 會丟 "solver not initialized"。
2. **非法狀態**：貼紙數量錯、對應不合法會拋錯，呼叫前先驗證。
3. **狀態字串大小寫**：必須大寫 URFDLB。
4. **solve() 在主執行緒**：單次解也要 100ms~1s，建議 worker。
5. **scramble vs random**：`Cube.scramble()` 回傳 moves 字串，`Cube.random()` 回傳 Cube 物件。
6. **TypeScript types 沒有**：自己寫 .d.ts（見上）。

## 驗證合法狀態

cubejs 的 `fromString` 不會完整驗證（corner/edge parity 等）。可先用自己的驗證：
- 每色恰 9 個貼紙
- 12 edges、8 corners 的組合存在
- corner twist sum ≡ 0 (mod 3)、edge flip sum ≡ 0 (mod 2)、permutation parity 一致

