Cómo empezó

A mi hijo le encantan los cubos. Ha resuelto un cubo de 8×8 e incluso uno que dicen que es el más difícil del mundo. Yo intenté aprender al menos el 3×3, pero me atasqué en el paso 8 del método y tampoco llegué a entender bien los principios.

Así que decidí hacer un programa que construyera el cubo en pantalla, leyera un cubo real a partir de fotos y mostrara la solución jugada a jugada.

El cubo 3D

  • Se dibuja con Qt6 y OpenGL. Al arrastrar con el ratón gira el cubo entero; al hacer clic izquierdo en una casilla, esa fila gira a izquierda o derecha, y con clic derecho, arriba o abajo.
  • Al principio, al pulsar la misma casilla, unas veces giraba bien y otras al revés. Cuando el cubo estaba inclinado, confundía la cara frontal con la lateral. Lo arreglamos después de probar todas las direcciones con un simulador de sentido de giro (simulate_moves).
  • Por la iluminación y las sombras, el blanco se veía gris y la cara inferior negra, así que quitamos los efectos de iluminación.

Con dos fotos, las 54 casillas

Si se fotografía el cubo desde una esquina, en una sola imagen se ven tres caras. Con otra foto desde la esquina opuesta aparecen las seis caras.

  1. Foto 1: con el amarillo arriba, se ven arriba, delante y derecha
  2. Foto 2: dado la vuelta con el blanco arriba, se ven abajo, detrás e izquierda

La casilla central de cada cara no se mueve al girar. Por eso, el color central determina qué cara es. El esquema de colores es amarillo arriba, blanco abajo, verde delante, naranja a la derecha, rojo a la izquierda y azul detrás.

Comprobación de reglas

Si una foto se lee mal, puede salir un cubo que en realidad sería imposible de montar. Por eso, al recibir el desarrollo plano, primero se comprueban las reglas.

  • Las 6 casillas centrales deben tener sus colores fijos.
  • Cada una de las 8 piezas de esquina debe tener tres colores distintos, y los colores opuestos (amarillo-blanco, verde-azul, rojo-naranja) no pueden aparecer juntos en la misma pieza.
  • Las 12 piezas de arista se comprueban de la misma manera, y tampoco puede aparecer dos veces la misma pieza.

Las casillas que no pasan se marcan con un borde rojo. Al pulsar una, aparecen los seis colores en círculo a su alrededor para poder corregirla al momento.

Esta es la pantalla inicial tras leer una foto del cubo de edición coreana. Los bordes rojos son las casillas que no cumplen las reglas.

Resolución

Si se superan las reglas, se busca la solución con la búsqueda en dos fases de Kociemba. No es un método que las personas memoricen, sino un algoritmo que usa tablas precalculadas para encontrar soluciones cortas. Resolvió los 60 cubos mezclados con 25 movimientos, con 20.7 movimientos de media y 22 como máximo. El tiempo mediano por resolución fue de 6 ms. Con los botones ◀ Anterior / Siguiente ▶ de la parte inferior de la pantalla se avanza movimiento a movimiento.

También hicimos un solucionador para principiantes por capas, más parecido a cómo resuelven las personas. Pero solo resolvió 6 de los mismos 60 (10%), y los que resolvió necesitaron 203~311 movimientos. Por eso la app usa primero Kociemba y solo recurre a otros métodos cuando falla.

El gráfico de tiempos usa escala logarítmica.

El código real de esta etapa

Esta es la comprobación de las piezas de esquina. Si se repite alguno de los tres colores, se marcan las tres casillas.

src/CubePhotoReconstructor.cppcpp · 25 líneas
// 2) 코너 (8개): 세 면 색은 모두 달라야 하고, 서로 다른 축 색이어야 함
for (int x : {-1, 1}) {
    for (int y : {-1, 1}) {
        for (int z : {-1, 1}) {
            const int fx = (x == 1) ? 0 : 1;
            const int fy = (y == 1) ? 2 : 3;
            const int fz = (z == 1) ? 4 : 5;
            const int cx = colorOnFace(faces, fx, x, y, z);
            const int cy = colorOnFace(faces, fy, x, y, z);
            const int cz = colorOnFace(faces, fz, x, y, z);
            if (cx < 0 || cy < 0 || cz < 0)
                continue;

            if (cx == cy || cy == cz || cx == cz) {
                v.ok = false;
                v.errors << QStringLiteral(
                                "· %1+%2+%3 모서리: 한 조각에 같은 색이 두 면 — "
                                "전개도에서 이 세 칸이 「왼|앞|오른」 접힘에 맞게 붙어 있는지 확인")
                                .arg(QString::fromUtf8(CubeModel::faceNameKo(fx)),
                                     QString::fromUtf8(CubeModel::faceNameKo(fy)),
                                     QString::fromUtf8(CubeModel::faceNameKo(fz)));
                markCell(v, fx, x, y, z);
                markCell(v, fy, x, y, z);
                markCell(v, fz, x, y, z);
            }

La resolución llama primero a Kociemba.

src/Oracle.cppcpp · 6 líneas
// 0) Kociemba two-phase — 임의 스크램블/사진 상태용 확실한 해법
if (!timedOut()) {
    auto koc = KociembaSolver::solve(start, 24, 8);
    if (!koc.empty())
        return compress(koc);
}

La siguiente entrada es "2. Segmentación por color en lugar de un VLM, y dos cubos de carácter distinto".