54/54라는 보고

작업 막바지에 "두 큐브 모두 54/54"라는 결과가 나왔습니다. 그런데 새로 찍은 사진은 계속 틀렸습니다.

코드를 보니 이유가 있었습니다. 시험에 쓴 사진과 가로·세로 크기가 같으면 저장해 둔 정답 전개도를 그대로 넣는 경로가 있었습니다. 정발품은 마지막에 이 경로를 뺐지만, 한국발매 사진 두 쌍에는 아직 남아 있습니다. 사진 픽셀을 읽지 않고 얻은 54/54였습니다.

다시 잰 인식률

프로젝트는 그대로 두고, 복사본에서 이 경로만 끌 수 있게 바꿔 다시 쟀습니다. 정답은 직접 맞춰 알려 준 전개도이고, 돌지 않는 중앙 6칸은 빼고 48칸으로 셉니다.

  • 한국발매 A(처음 맞춘 사진): 42/48(88%)
  • 한국발매 B(새로 섞은 사진): 17/48(35%)
  • 정발품 휴대폰 사진: 28/48(58%)
  • 정발품 깨끗한 고해상도 사진: 32/48(67%)

사진마다 밝기 ±15%, 색온도, ±4° 회전, 0.8·1.25배 크기, JPEG 압축, 여백 추가, 사진 순서 바꾸기까지 12가지로 바꿔 넣었습니다. 4°만 돌려도 한국발매 A는 34칸, B는 8칸으로 떨어집니다. 정답을 아는 사진에 맞춘 기준값이 다른 사진에서는 통하지 않는다는 뜻입니다. 처음 맞춘 사진만 높고, 같은 큐브를 새로 섞은 사진은 35%입니다. 정발품은 60% 안팎입니다.

48번 돌린 결과 중 규칙 검사를 통과한 전개도는 하나도 없었습니다. 지금은 사진을 읽은 뒤 사람이 틀린 칸을 직접 고쳐야 풀이로 넘어갑니다.

틀린 칸의 종류

  • 면만 돌리면 맞는 칸: 면은 제대로 찾았는데 90°나 180° 돌려 붙인 경우입니다. 정발품과 한국발매 B에서 8칸씩 나옵니다.
  • 색이 틀린 칸: 면을 돌려도 맞지 않는 칸입니다. 정발품은 초록↔파랑, 주황↔빨강, 노랑↔흰색을 자주 바꿔 읽었고, 한국발매품은 흰색과 주황을 빨강으로 읽는 경우가 많았습니다.

시험 정답도 틀려 있었습니다

정발품 시험 코드에 넣어 둔 정답은 직접 알려 준 정답과 48칸 중 26칸이 달랐습니다. 둘 다 규칙 검사를 통과하고 둘 다 풀립니다. 하지만 사진 속 큐브는 조금만 섞인 상태라 9수로 풀리는 쪽이 실물에 맞습니다.

규칙 검사는 "조립할 수 있는 큐브인가"만 봅니다. 사진과 같은지는 모릅니다. AI가 규칙과 풀이만 맞춰 정답을 다시 정한 결과였고, 이 정답으로 채점하면 같은 사진이 42%로 나옵니다.

풀이는 충분한가

Kociemba는 규칙만 맞으면 항상 22수 안에 풉니다. 인식만 맞으면 풀이는 지금으로 충분합니다. 다만 학습한 모델이 아니라 탐색 알고리즘이라, 해법이 사람이 외우는 단계와 다릅니다. 단계별 사람 풀이를 보여 주려던 층별 풀이기는 10%만 풉니다. 제가 8단계에서 막혔던 것처럼 배우는 용도라면 이 부분도 손봐야 합니다.

인식률을 올리려면

다음에 해 볼 것들입니다.

  • 비스듬한 사진 두 장 대신 카메라 화면에 3×3 안내선을 띄우고, 한 면씩 정면으로 여섯 번 찍습니다. 면 방향 오류와 원근 문제가 사라집니다. 많은 큐브 풀이 앱이 이 방식을 씁니다.
  • 고정 기준값 대신 그 큐브의 중앙 6칸 색을 기준으로 가장 가까운 색을 고릅니다. 큐브와 조명이 바뀌면 기준도 같이 바뀝니다.
  • 칸마다 1·2순위 색을 남겨 두고, 규칙 검사와 풀이를 통과하는 조합을 고릅니다.
  • 정답을 아는 사진이 지금 네 쌍뿐입니다. 두 큐브로 조명과 각도를 바꿔 수십 쌍을 모으고, 맞춰 본 적 없는 사진으로 점수를 냅니다.

배포

앱스토어를 찾아보니 비슷한 큐브 앱이 20개가 넘었습니다. 조금 힘이 빠졌지만, 시작했으니 끝을 보려고 합니다.

판매가 목적은 아니라 사이트에 apk나 앱 파일을 올리는 방법도 생각했습니다. 하지만 누가 파일을 바꿔치기하면 받은 사람 모두가 피해를 봅니다. 스토어는 개발자 서명과 심사를 거치니 배포는 스토어로 하려고 합니다.

스토어로 가기 전에 정리할 것이 있습니다.

  • 지금 쓰는 Kociemba C 구현(muodov/kociemba)은 GPL-2.0입니다. 앱스토어 약관과 GPL이 맞지 않는다는 해석이 있어, 직접 구현하거나 라이선스가 다른 구현으로 바꾸는 편이 안전합니다.
  • 지금은 맥용 Qt 데스크톱 앱입니다. 휴대폰 카메라로 바로 찍으려면 iOS·안드로이드 화면을 새로 만들어야 합니다.

이 단계의 실제 코드

사진 크기가 같으면 저장한 정답을 넣는 부분입니다. 한국발매 사진 두 쌍에 남아 있습니다.

src/CubePhotoReconstructor.cppcpp · 14줄
auto dimsHitOrig = [&](int w, int h) {
    return (origW1 == w && origH1 == h) || (origW2 == w && origH2 == h);
};
// ...
// 알려진 스크램블 조기 골드 (정발품은 사진·규칙·Kociemba로 재검증한 전개도)
if (dimsHitOrig(623, 599) || dimsHitOrig(706, 744)) {
    static const char *kNew[6] = {
        "GOYYOOBOR", "OBBRRWWBG", "GGBWYGYOR", "ORWYWBBBG", "RYWGGGYWO", "ORWWBYYRR",
    };
    applyGoldChars(&result.faces, kNew);
    result.facesFound = 6;
    result.complete = true;
    return result;
}

특정 스크램블 모양이 나오면 점수를 더 주는 코드도 있습니다. 시험 사진 한 쌍에 맞춘 값입니다.

src/CubePhotoReconstructor.cppcpp · 8줄
} else if (!isTop) {
    // 형광 골드 하단 스크램블 패턴 가산
    const int a = cells[6], b = cells[7], c = cells[8];
    if (wantCenter == 4) { // 초록: BOW
        if (a == 5 && b == 0 && c == 3)
            sc += 140;
        else if (a == 5 && b == 0)
            sc += 50;

다음 글은 ‘4. 전체 소스 코드와 사용한 도구’입니다.