Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions web/src/cases/pll-arrows.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ describe('pllArrows', () => {
expect(arrowsOf('T').filter((a) => a.both)).toHaveLength(2)
})

it('ignores the AUF at the end of the algorithm', () => {
// 動くパーツの数(片向きの矢印は1本で1つ、入れ替えは1本で2つ)
const moved = (name: string) => arrowsOf(name).reduce((n, a) => n + (a.both ? 2 : 1), 0)
const expected: Record<string, number> = {
Aa: 3, Ab: 3, E: 4, H: 4, Ua: 3, Ub: 3, Z: 4, F: 4, Ja: 4, Jb: 4, Ra: 4, Rb: 4, T: 4,
Ga: 6, Gb: 6, Gc: 6, Gd: 6, Na: 4, Nb: 4, V: 4, Y: 4,
}
for (const [name, n] of Object.entries(expected)) expect(moved(name), name).toBe(n)
// J・R・T・F・V・Y・N は、角の入れ替えとエッジの入れ替えが1組ずつ
for (const name of ['Ja', 'Jb', 'Ra', 'Rb', 'T', 'F', 'V', 'Y', 'Na', 'Nb', 'Z']) {
expect(arrowsOf(name).every((a) => a.both), name).toBe(true)
}
})

it('gives arrows for every PLL case, and none for a solved or non-PLL state', () => {
for (const c of ALL_CASES.filter((x) => x.set === 'PLL')) {
expect(pllArrows(casePattern(kpuzzle, c.alg)).length, c.name).toBeGreaterThan(0)
Expand Down
22 changes: 17 additions & 5 deletions web/src/cases/pll-arrows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,30 @@ const TOP = [...CORNER_SLOTS.slice(0, 4), ...EDGE_SLOTS.slice(0, 4)]

const sideKey = (faces: string[]) => [...faces].sort().join('')

// 解き終わりの AUF(U)は、側面の色の名前を巡回させるのと同じ
const NEXT: Record<string, string> = { F: 'R', R: 'B', B: 'L', L: 'F' }
const cycle = (face: string, k: number) => {
for (let i = 0; i < k; i++) face = NEXT[face] ?? face
return face
}

/**
* 各パーツを、今ある位置から戻るべき位置への矢印にする。2つのパーツの入れ替えは両向きの矢印1本にまとめる。
* 最終層の向きが揃っていない(PLL の状態でない)ときは空。
* 解き終わりの AUF は自由なので、動かすパーツが最も少なくなる AUF で考える(ケースの手順が AUF を含んでいても、
* 最終層全体が回っているようには描かない)。最終層の向きが揃っていない(PLL の状態でない)ときは空。
*/
export function pllArrows(pattern: string): PllArrow[] {
if (TOP.some((s) => pattern[s.facelets[0]] !== 'U')) return []
// 側面の色の組 → その色のパーツが戻るべき位置
const home = new Map(TOP.map((s) => [sideKey(s.facelets.slice(1).map((i) => SOLVED_FACELETS[i])), s.facelets[0]]))
const dest = new Map<number, number>()
for (const s of TOP) {
const to = home.get(sideKey(s.facelets.slice(1).map((i) => pattern[i])))
if (to !== undefined && to !== s.facelets[0]) dest.set(s.facelets[0], to)
let dest = new Map<number, number>()
for (let k = 0; k < 4; k++) {
const d = new Map<number, number>()
for (const s of TOP) {
const to = home.get(sideKey(s.facelets.slice(1).map((i) => cycle(pattern[i], k))))
if (to !== undefined && to !== s.facelets[0]) d.set(s.facelets[0], to)
}
if (k === 0 || d.size < dest.size) dest = d
}
const out: PllArrow[] = []
for (const [from, to] of dest) {
Expand Down
Loading