--- title: "The 4x4x4 Cube" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{The 4x4x4 Cube} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") library(cayleyR) ``` The 4x4x4 is built by the same rules as the 3x3x3 (see `vignette("rubiks-cube")`): 96 stickers, 24 quarter turns. Two things are new. The cube has no fixed centres, and each edge is made of two separate pieces, called wings. That is why it is solved by **reduction**. ## Moves ```{r} cg4 <- cube_group(4) cg4 ``` The outer layers keep their usual letters. The two inner layers of each axis have no standard names, so they are written as layer index and axis: `"2x"` is layer 2 along x. ## Reduction A cube is **reduced** when: - the four centres of every face are the same colour, so each face acts as one; - the two wings of every edge are together, so each edge acts as one. A reduced 4x4x4 is a 3x3x3 with fat pieces, and any 3x3x3 method can finish it. `cube_is_reduced()` checks the first part only, not where the pieces are. A solved cube turned by `U` is still reduced: ```{r} cube_is_reduced(cube_identity(4)) cube_is_reduced(group_apply(cg4, cube_identity(4), "U")) cube_is_reduced(group_apply(cg4, cube_identity(4), "2x")) ``` ## `cube_solve4()`: always finishes This solver builds the centres, pairs the edges, and finishes the cube with a 3x3x3 method. There is no search, so it always gets there, but the solutions are long: a few hundred quarter turns. ```{r} set.seed(42) scramble <- generate_state(group = cg4, n_moves = 40) res <- cube_solve4(scramble) res$found length(res$path) res$stages ``` Two things can happen on a 4x4x4 that are impossible on a 3x3x3: OLL and PLL **parity**. After reduction the last layer can be in a state no 3x3x3 can reach. The solver repairs it with algorithms that turn the inner layers, and the repair shows up as its own stage. Some options make the solution shorter: - `method` picks the 3x3x3 solver for the end: `"cfop"` (the default), `"kociemba"`, `"lbl"`, `"m2"`, `"pochmann"`. `"kociemba"` gives the shortest finish. - `orientations` tries several ways of holding the cube and keeps the shortest answer. Eight is a good trade: about 11% shorter for a fifth more time. ```{r} res_k <- cube_solve4(scramble, method = "kociemba") length(res_k$path) cube_is_colour_solved(group_apply(cg4, scramble, res_k$path)) ``` ## `cube_kociemba4()`: short, but not always A four-phase search after Kociemba. Phases 1–3 search for a reduction, and phase 4 hands the reduced cube to `cube_kociemba()`. The solutions are a few dozen moves long instead of a few hundred. The catch is phase 3: its search grows about fifteen-fold per level. Scrambles of five moves reduce reliably; from seven moves on, the search usually runs out of budget. In that case `found` is `FALSE`, and `cube_kociemba4_report()` tells you which phase stopped. ```{r} set.seed(1) short <- generate_state(group = cg4, n_moves = 5) res4 <- cube_kociemba4(short) res4$found length(res4$reduction) # moves to the reduced cube length(res4$cube3) # moves to finish it as a 3x3x3 ``` ## `cube_solve4_cascade()`: the best of both The cascade tries the search first and falls back to `cube_solve4()` when the search does not pay off. It tries several orientations of the cube at a small node budget, then a larger one. If nothing reduces the cube, `cube_solve4()` finishes it. You always get an answer: short when the search succeeds, long otherwise. ```{r, eval = FALSE} r <- cube_solve4_cascade(scramble) r$method # "reduce" if the search won, "solve4" if it fell back r$n_moves r$ops # every step it took, with the time spent on each ``` This one takes seconds to minutes per cube, so it is not run here. ## Santa 2023 notation The Kaggle Santa 2023 puzzles write cube moves as `f0`, `r1`, `-d2`: an axis letter, a layer index, and a minus sign for the inverse. This is the same alphabet as the package's, under different names. `cube_santa_path()` and `cube_santa_path_out()` convert paths between the two notations, and `cube_santa_state()` and `cube_santa_state_out()` convert states: ```{r} cube_santa_path("f0.-d3.r1", n = 4) cube_santa_path_out(c("F", "U", "2x"), n = 4) ``` So a solution from any solver here can be written out in Santa's format: ```{r} substr(cube_santa_path_out(res_k$path, n = 4), 1, 60) ```