
시작
아들이 큐브를 참 좋아합니다. 8×8 큐브도 풀고, 세계에서 제일 어렵다는 큐브도 풀었습니다. 저도 3×3만큼은 배워 보려고 했지만 해법 8단계에서 막혔고, 원리도 잘 이해되지 않았습니다.
그래서 큐브를 화면에 직접 만들고, 실제 큐브를 사진으로 읽어 한 수씩 풀이를 보여 주는 프로그램을 만들기로 했습니다.
3D 큐브
- Qt6와 OpenGL로 그립니다. 마우스로 끌면 큐브 전체가 돌고, 칸을 좌클릭하면 그 줄이 좌우로, 우클릭하면 상하로 돕니다.
- 처음에는 같은 칸을 눌러도 어떤 때는 맞게, 어떤 때는 반대로 돌았습니다. 큐브가 비스듬할 때 앞면과 옆면을 잘못 판단한 것입니다. 회전 방향 시뮬레이터(simulate_moves)로 모든 방향을 시험한 뒤에 고쳤습니다.
- 조명과 그림자 때문에 흰색이 회색으로, 아래 면이 검게 보여서 조명 효과를 뺐습니다.
사진 두 장이면 54칸
큐브를 모서리 쪽에서 찍으면 한 장에 면 세 개가 보입니다. 반대 모서리에서 한 장 더 찍으면 여섯 면이 다 나옵니다.
- 사진 1: 노랑이 위로 오게 놓고 위·앞·오른쪽
- 사진 2: 흰색이 위로 오게 뒤집어 아래·뒤·왼쪽
면 중앙 칸은 돌려도 움직이지 않습니다. 그래서 중앙 색으로 어느 면인지 정합니다. 배색은 위 노랑, 아래 흰색, 앞 초록, 오른쪽 주황, 왼쪽 빨강, 뒤 파랑입니다.
규칙 검사
사진을 잘못 읽으면 실제로는 조립할 수 없는 큐브가 나옵니다. 그래서 전개도를 받으면 규칙부터 봅니다.
- 중앙 6칸은 정해진 색이어야 합니다.
- 모서리 조각 8개는 세 면 색이 모두 달라야 하고, 마주 보는 색(노랑·흰색, 초록·파랑, 빨강·주황)이 한 조각에 같이 올 수 없습니다.
- 가장자리 조각 12개도 같은 방식으로 보고, 같은 조각이 두 번 나와도 안 됩니다.
걸린 칸은 빨간 테두리로 표시합니다. 그 칸을 누르면 주위에 여섯 색이 둥글게 떠서 바로 고칠 수 있습니다.

한국발매 큐브 사진을 읽은 초기 화면입니다. 빨간 테두리가 규칙에 걸린 칸입니다.
풀이
규칙을 통과하면 Kociemba 2단계 탐색으로 해를 구합니다. 사람이 외우는 풀이법이 아니라, 미리 만든 표를 써서 짧은 해를 찾는 알고리즘입니다. 25수로 섞은 큐브 60개를 모두 풀었고 평균 20.7수, 가장 긴 해가 22수였습니다. 한 번 푸는 데 걸린 시간은 중앙값 6ms입니다. 화면 아래 ◀ 이전 / 다음 ▶ 버튼으로 한 수씩 넘겨 봅니다.
사람 풀이에 가까운 초보자 층별 풀이기도 만들었습니다. 하지만 같은 60개 중 6개(10%)만 풀었고, 푼 것도 203~311수였습니다. 그래서 앱은 Kociemba를 먼저 쓰고, 실패할 때만 다른 방법으로 넘어갑니다.

시간 그래프는 로그 눈금입니다.
이 단계의 실제 코드
모서리 조각 검사입니다. 세 면 색이 겹치면 세 칸을 모두 표시합니다.
src/CubePhotoReconstructor.cpp
// 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);
}풀이는 Kociemba를 먼저 부릅니다.
src/Oracle.cpp
// 0) Kociemba two-phase — 임의 스크램블/사진 상태용 확실한 해법
if (!timedOut()) {
auto koc = KociembaSolver::solve(start, 24, 8);
if (!koc.empty())
return compress(koc);
}다음 글은 ‘2. VLM 대신 색 분해로, 성격이 다른 두 큐브’입니다.
COMMENTS · CHAPTER 01
3D 큐브를 만들고 사진 두 장으로 상태 읽기 댓글 0
아직 댓글이 없습니다. 읽다가 궁금한 점이나 보탤 내용을 남겨 주세요.
댓글을 등록하려면 구글로 시작하기를 눌러 닉네임과 메일 주소를 등록해 주세요.
구글로 시작하기