
루빅스 큐브를 아무렇게나 섞었을 때 나올 수 있는 상태의 수는 정확히 43,252,003,274,489,856,000개예요. 약 4325경 개죠. 지구상의 모래알 개수 추정치보다도 많은 수인데요. 이 모든 상태를 웹페이지에서 스크롤로 하나하나 구경할 수 있게 만든 사이트가 등장했어요. 페이지를 열면 큐브들이 끝없이 이어지고, 스크롤을 내리면 4325경 번째 큐브까지 이동할 수 있어요. 그런데 잠깐, 이게 어떻게 가능한 걸까요?
4325경 개를 '저장'할 수는 없어요
당연한 얘기지만 이 상태들을 미리 만들어 저장하는 건 불가능해요. 상태 하나를 단 1바이트로 압축해도 수백억 테라바이트가 필요하거든요. 전 세계 데이터센터를 다 합쳐도 어림없죠. 비결은 저장이 아니라 계산이에요. "N번째 큐브 상태"를 그 자리에서 수학적으로 만들어내는 함수를 쓰는 거예요.
이게 어떻게 되냐면, 큐브의 상태는 네 가지 요소로 완전히 분해돼요. 코너 조각 8개의 배치 순서(8! = 40,320가지), 코너 조각들의 회전 방향(3^7 = 2,187가지), 엣지 조각 12개의 배치 순서(12!의 절반 = 239,500,800가지), 엣지 조각들의 뒤집힘 방향(2^11 = 2,048가지). 이 네 수를 전부 곱하면 정확히 43,252,003,274,489,856,000이 나와요. 그러니까 0부터 4325경 사이의 번호 하나가 주어지면, 그 번호를 네 부분으로 쪼개서 각각을 순열과 방향으로 해석하면 유일한 큐브 상태 하나가 튀어나오는 거죠. 순열에 번호를 매기고 번호에서 순열을 복원하는 이 기법을 순열 랭킹/언랭킹이라고 하는데, 팩토리얼 진법(자릿수마다 가중치가 1!, 2!, 3!...으로 커지는 진법)을 쓰면 효율적으로 계산할 수 있어요.
브라우저와의 싸움
수학이 해결됐다고 끝이 아니에요. 브라우저는 이렇게 긴 페이지를 만들 수 없거든요. DOM 요소의 최대 높이가 브라우저마다 대략 수천만 픽셀 수준으로 제한돼 있어서, 4325경 개를 실제 요소로 늘어놓는 건 애초에 불가능해요. 그래서 가상 스크롤(virtual scrolling)이라는 기법을 써요. 이게 뭐냐면, 화면에 보이는 몇 개의 항목만 실제로 렌더링하고, 스크롤 위치는 별도의 숫자로 관리하면서 스크롤할 때마다 내용물만 갈아 끼우는 방식이에요. 여기에 더해 이 사이트는 스크롤 위치 자체가 자바스크립트의 안전한 정수 범위(2^53, 약 9천조)를 아득히 넘어가기 때문에, 임의 크기 정수를 다루는 BigInt로 위치를 계산해야 해요.
재미있는 사실 하나. 초당 100만 개씩 큐브를 넘기면서 평생 스크롤해도 전체의 티끌만큼도 못 봐요. 그리고 이 4325경 개 중에 완전히 맞춰진 큐브는 단 하나뿐이에요. 스크롤하다가 우연히 그걸 만날 확률은... 계산 안 해보는 게 정신 건강에 좋아요.
비슷한 프로젝트들, 그리고 배울 점
이런 "모든 경우의 수 구경하기" 장르에는 선배들이 있어요. 모든 가능한 책 페이지를 담았다는 바벨의 도서관(Library of Babel) 사이트, 모든 UUID를 스크롤하는 사이트 같은 것들이요. 공통 원리는 같아요. 전부 저장하는 대신, 인덱스에서 내용물을 결정적으로(같은 입력이면 항상 같은 출력이 나오게) 생성하는 것.
장난감 같아 보여도 실무에 닿아 있는 기법들이에요. 가상 스크롤은 수만 건짜리 목록을 렌더링하는 모든 서비스의 필수 기술이고(react-window 같은 라이브러리가 이걸 해줘요), 인덱스와 조합을 상호 변환하는 발상은 페이지네이션이나 샤딩 키 설계, 절차적 생성 게임에도 응용되거든요. 게임 '노 맨즈 스카이'가 1800경 개의 행성을 저장 없이 시드 값만으로 생성하는 것도 같은 원리예요.
정리하면, 이 사이트는 "저장 대신 계산"이라는 프로그래밍의 우아한 발상을 극단까지 밀어붙인 장난감이에요. 여러분이라면 이 기법으로 어떤 "모든 것의 목록"을 만들어보고 싶으세요?
🔗 출처: Hacker News