데이터 구조에서 루빅스 큐브를 나타내는 방법


58

Rubik 's Cube 를 시뮬레이트하려는 경우 측면 당 X 개의 타일 수를 사용하여 큐브의 상태를 메모리에 저장하는 데이터 구조를 어떻게 만들 수 있습니까?

고려해야 할 사항 :

  • 큐브는 모든 크기가 될 수 있습니다
  • 루빅스 큐브이므로 레이어를 회전 할 수 있습니다

2
숙제? 또는 실제 문제 ...
sdg

4
해당 Rubik 's Cube Solver의 소스 코드에 관심이있을 수 있습니다 .
mouviciel

22
큐브의 변의 수는 6이어야합니다.
Simon Bergot

3
Rubik 's Cube 모델이 평평 해져서 모든면을 동시에 볼 수 있을지 궁금합니다. 흠, 나는 지금 그것을 쓰고 싶어합니다. 그것은 가능하다면 T의 모양이거나 끝없이 바둑판 식으로 배열 될 수 있습니다 (후자는 생각하지 않았습니다).
Lee Kowalkowski

6
에릭 에반스 (Eric Evans)는 다음과 같이 인용했다. "모델이 옳지도 나쁘지도 않다. 그것들은 단순히 다소 유용하다"(메모리에서 인용했을 때 100 % 정확하지 않다)
Pete

답변:


37

크기가 평범한 오래된 배열의 문제는 무엇입니까 [6X][X]? 당신 은 그들을 볼 수 없기 때문에 내부 미니 큐브 에 대해 알 필요 가 없습니다; 그것들은 큐브 상태의 일부가 아닙니다. 보기 좋고 사용하기 쉬운 인터페이스 뒤에 2 개의 추악한 메소드를 숨기고, 유닛 테스트를 통해 죽음까지, 그리고 짜잔!


31
실제 루빅스 큐브조차도 내부 미니 큐브가 없습니다
jk.

8
이것은 작동하지만 알고리즘이 간단한 데이터 구조를 수용하기에는 지나치게 복잡 할 것입니다.
maple_shaft

6
As long as you know how the six surfaces are "threaded" together 더 강력한 데이터 구조가 제공하는 것입니다. 나는 우리가 같은 것을 주장하고 있다고 생각합니다. 배열 측면과 측면은 블록 배열이지만 "스레딩"을 이해하는 데 도움이되는 측면과 블록에 대한 흥미로운 속성이 많이 있습니다. )
maple_shaft

7
@maple_shaft "어느 것이 더 강력한 데이터 구조로 제공 될까요?" 이에 대해 잘 모르겠습니다. 더 "구조"가있는 데이터 구조 는 해당 구조의 개별 부분 설정, 유지 관리 및 액세스와 관련하여 추가적인 부수적 인 복잡성을 가져옵니다 . 더 복잡한 것이 무엇인지 말하기 어렵습니다. 일부 코너 케이스와 개별 셀에 액세스 할 때 "자유 라이드"가있는 평범한 배열에서 추악한 시프트를 구현하거나 다소 덜 복잡한 시프트와 다소 복잡한 판독을 갖는 구조.
dasblinkenlight

16
실제로 Rubik 's Cube를 조작하기위한 프로그램을 작성한 사람으로서 저는 얼굴 당 하나씩 6 개의 2 차원 배열을 사용하는 간단한 접근 방식을 취했습니다. 약간 성가신 큐브에 대한 몇 가지 기본 작업을 구현해야하지만 그 후에는 표현을 잊어 버릴 수 있습니다. 그것은 결코 문제가되지 않았습니다. 나는 종종 다른 표현이 성능 관점에서 어떻게 작동하는지 궁금해했지만 코딩 관점에서 부담을 느끼지 않았습니다.
PeterAllenWebb

39

필자는 열렬한 속도 큐브 러이지만 알고리즘 또는 데이터 구조에서 Rubik 큐브를 프로그래밍 방식으로 표현하려고 시도한 적이 없습니다.

큐브에서 각 블록의 고유 한 측면을 캡처하기 위해 별도의 데이터 구조를 만들 것입니다.

큐브에는 3 가지 유형의 블록이 있습니다.

  1. 코너 블록-3 개의 컬러면과 3 개의 인접한 조각이있어 언제라도 한면을 공유 할 수 있습니다.

  2. Edge Block-2 개의 컬러 페이스를 가지고 있으며 4 개의 인접한 조각이있어 언제라도 한면을 공유 할 수 있습니다. 3x3 블록에서는 항상 2 개의 중심 조각과 2 개의 모서리 조각이 있습니다.

  3. 중앙 블록-3x3 큐브에서이 조각은 움직일 수 없지만 회전 할 수 있습니다. 항상 4 개의 인접 에지 블록이 있습니다. 더 큰 큐브에는 다른 중심 블록 또는 가장자리 조각과 공유 할 수있는 여러 중심 블록이 있습니다. 중앙 블록은 모퉁이 블록에 인접하지 않습니다.

이것을 알면 블록은 다른 블록에 대한 참조 목록을 가질 수 있습니다. 하나의 큐브면을 나타내는 블록 목록과 모든 큐브면에 대한 참조를 유지하는 목록 인 다른 목록 목록을 유지합니다.

모든 큐브면은 고유 한면으로 나타납니다.

이러한 데이터 구조를 사용하면 각면에서 회전 변환을 수행하고 적절한 블록을 적절한 목록으로 이동하거나 제거하는 알고리즘을 작성하는 것이 매우 쉽습니다.

편집 : 중요 사항,이 목록은 물론 주문해야하지만 언급하는 것을 잊었습니다. 예를 들어, 오른쪽을 뒤집 으면 왼쪽 모서리 오른쪽 블록이 오른쪽의 오른쪽 모서리로 이동하고 시계 방향으로 회전합니다.


각 블록에는 고유 한 속성이 있어야한다는 데 동의합니다. 그러나 인접한 블록과에 대한 참조를 업데이트해야하기 때문에 변환이 지루하지 않습니다 list of lists. 아마도 당신이 쿼리 할 수있는 순서없는 블록 목록을 갖는 것이 좋습니다. 변환을 수행 할 때 인접한 블록 참조 만 업데이트하면됩니다. 면의 모든 블록 목록을 원한다면 중앙 블록에 인접한 모든 블록에 대한 목록을 쿼리 할 수 ​​있습니다.
Mel

@Mel 어느 쪽이든 할 수 있지만 dasblinkenlight와 이야기 한 후에 실제로 그의 접근 방식이 덜 복잡하다고 생각합니다. 그의 대답이 내 것보다 더 많은 표를 얻었 으면 좋겠다. 나는 알고리즘과 가장 효율적인 알고리즘이 전부는 아니지만 루빅스 큐브를 좋아하고 수집합니다 (전 세계에서 40 가지가 넘는 종류).
maple_shaft

하지만 dasblinknenlight의 대답 나는 당신의 대답은 같은 데이터 구조에 필요한 것 로직의 일부를 포함하는 사실과 다른 블록의 속성을 좋아하기 때문에 가장 간단한 솔루션, 난 당신에게 현상금을 수여하고 있습니다
레이첼

이 데이터 모델은 실제보다 더 사실적이지만, 필요한 것보다 더 어려운 일부 간단한 작업을 수행 할 수 있습니다. 큐브의 상태를 가져 오려면 번거로운 큐브 목록을 통해 재귀 적으로 이동해야합니다.
Ziv

@Ziv True 그러나 데이터 구조에 대한 질문은 알고리즘에 대한 질문 일 필요는 없습니다.
maple_shaft

13

이 문제를 생각할 때 알려진 패턴으로 색상이 움직이는 정적 큐브를 생각합니다. 그래서....

Cube 객체에는 고정 인덱스 0-5로 유지되는 6 개의 Side 객체가 있습니다. 각면에는 고정 인덱스 0-8로 유지되는 9 개의 위치 객체가 있습니다. 각 위치에는 색상이 포함되어 있습니다.

간단하게하기 위해 모든 작업을 1/4 회전 단위로 처리하십시오. 큐브에는 총 6 개의 가능한 동작에 대해 각각 2 개의 가능한 방향으로 3 개의 회전축이 있습니다. 이 정보를 사용하면 큐브에 가능한 6 가지 동작을 매핑하는 것이 매우 간단한 작업이됩니다.

따라서 측면 6, 위치 3의 녹색은 수행되는 작업에 따라 측면 1 위치 3 또는 측면 2 위치 7로 이동할 수 있습니다. 수학 번역을 찾기에 충분하지는 않았지만 코드에서 활용할 수있는 패턴이 나타날 것입니다.

데이터 구조를 사용하여 특정 상태의 특정 큐브를 해결할 수 있는지 어떻게 알 수 있습니까? 나는이 질문으로 스스로 고투하고 있었고 아직 답을 찾지 못했습니다.

이렇게하려면 임의 큐브 상태로 시작하지 마십시오. 대신, 해결 된 상태로 시작하고 프로그래밍 방식으로 n 작업을 수행 하여 큐브를 임의의 시작 상태로 만듭니다. 현재 상태에 도달하기 위해 합법적 인 조치 만 취 했으므로 큐브를 해결할 수 있어야합니다.


1
고전적인 "여기에서 시작하고 싶지 않다"는 조언!
Ergwun

8

xyz 좌표계가 Rubik의 큐브를 처리하는 간단한 방법이고 회전 행렬이 회전을 구현하는 단순하고 일반적인 방법이라는 것을 알았습니다.

위치 벡터를 포함하는 Piece 클래스를 만들었습니다 (x, y, z). 회전 행렬을 해당 위치 (행렬-벡터 곱셈)에 적용하여 조각을 회전 할 수 있습니다. 조각은 또한 튜플에서 색상을 추적하여 (cx, cy, cz)각 축을 따라 색상을 향하게합니다. 적은 양의 논리는 회전 중에 이러한 색상이 적절하게 업데이트되도록합니다. XY 평면에서 90도 회전하면 cx및 의 값을 교환 할 수 있습니다 cy.

모든 회전 논리가 Piece 클래스에 캡슐화되어 있기 때문에 Cube는 정렬되지 않은 Piece 목록을 저장할 수 있으며 일반적인 방식으로 회전 할 수 있습니다. 왼쪽면을 회전 시키려면 x 좌표가 -1 인 모든 조각을 선택하고 각 조각에 적절한 회전 행렬을 적용하십시오. 전체 큐브의 회전을 수행하려면 모든 조각에 동일한 회전 행렬을 적용하십시오.

이 구현은 간단하고 몇 가지 장점이 있습니다.

  1. Piece 객체의 위치는 변하지 만 색상은 변하지 않습니다. 이것은 당신이 적록 조각을 요구하고, 물체에 매달리고, 회전을하고, 같은 물체를 검사하여 적록 조각이 끝나는 곳을 볼 수 있음을 의미합니다.
  2. 각 유형의 조각 (가장자리, 중심, 모서리)에는 고유 한 좌표 패턴이 있습니다. 3x3 큐브의 경우 모서리 조각의 위치 벡터 ( (-1, 1, 1))에 0이없고 가장자리의 정확히 하나의 0 ( (1, 0, -1))이 있고 가운데 조각에는 두 개의 0 ( (-1, 0, 0))이 있습니다.
  3. 3x3 큐브에서 작동하는 회전 행렬은 NxN 큐브에서 작동합니다.

단점 :

  1. 행렬-벡터 곱셈은 배열에서 값을 바꾸는 것보다 느립니다.
  2. 위치 별 조각에 대한 선형 시간 조회. 조각을 외부 데이터 구조에 저장하고 회전하는 동안 위치별로 일정 시간 조회를 위해 업데이트해야합니다. 이것은 회전 행렬을 사용하는 우아함을 없애고 회전 논리를 큐브 클래스로 누출시킵니다. 검색 기반 해결 알고리즘을 구현하는 경우 다른 구현을 사용합니다.
  3. 패턴 분석 (해결 중)은 그다지 좋지 않습니다. 한 조각은 인접한 조각에 대해 알지 못하며 위의 성능 문제로 인해 분석이 느려질 수 있습니다.

3
이러한 종류의 구현이 3D 그래픽 프로그램에서 큐브를 나타내는 데 가장 효과적이라는 것을 알았습니다. 행렬 곱셈을 사용하면 레이어 회전에 애니메이션을 적용 할 수 있습니다. 이 방법의 구현 예는 이 github 저장소 를 참조하십시오 . 3D 큐브에 솔버를 추가하려면 다른 답변 중 하나의 알고리즘 및 데이터 구조가 필요합니다.
Jonathan Wilson

5

간단한 배열 (면의 사각형에 1 대 1의 매핑이있는 각 요소)을 사용하고 특정 순열로 각 회전을 시뮬레이션 할 수 있습니다

3 개의 필수 순열만으로 벗어날 수 있습니다. 앞면을 통해 축으로 슬라이스를 회전하고, 수직 축을 중심으로 큐브를 회전하고 왼쪽과 오른쪽을 통해 큐브를 수평 축으로 회전시킵니다. 다른 모든 움직임은이 세 가지를 연결하여 표현할 수 있습니다.

큐브를 해결할 수 있는지 여부를 가장 간단하게 알 수있는 방법은 위치를 바꾼 두 개의 모서리, 하나의 뒤집힌 모서리, 하나의 뒤집힌 모서리 또는 끝이있는 경우이를 해결하는 것입니다 (입방체를 해결할 일련의 순열을 찾습니다). 당신은 unxolvable 큐브를 가지고 2 스왑 코너


1
the most straightforward way of know whether a cube is solvable is to solve it. 글쎄, 당신이 제안하는 모델을 사용하는 것이 사실이라고 생각합니다. 그러나 @maple_shaft에 더 가까운 모델을 사용하고 회전을 추적하는 경우 모서리 플립의 합 mod 2가 0이고 모서리 회전 mod 3이 0인지 확인하여 3x3x3 큐브를 해결할 수 있는지 신속하게 테스트 할 수 있습니다. 그런 다음 순열의 패리티를 확인하십시오. 에지 스왑 및 코너 스왑을 계산할 때 (복구해야 함) 합계 모드 2는 0이어야합니다 (총 패리티 짝수). 큐브가 풀릴 수 있음을 증명하기 위해 필요하고 충분한 테스트입니다.
jimhark

3

해결 가능한 첫 번째 조건은 각 조각이 존재하고 각 조각의 색상을 사용하여 "Sovled"큐브를 조립하는 것입니다. 이것은 간단한 점검표로 진실을 결정할 수있는 비교적 사소한 조건입니다. "표준"큐브의 색 구성표 가 정의 되어 있지만 표준 큐브를 다루지 않더라도 6 개만 있습니다! 해결 된면의 가능한 조합.

모든 조각과 색상이 올바르게 설정되면 주어진 물리적 구성을 해결할 수 있는지 여부를 결정하는 것이 중요합니다. 그들 모두가 아닙니다. 이를 확인하는 가장 순진한 방법은 큐브 해결 알고리즘을 실행하고 해결 된 큐브로 종료되는지 확인하는 것입니다. 실제로 큐브를 해결하려고 시도하지 않고 용해도를 결정하는 멋진 조합 기술이 있는지 모르겠습니다.

어떤 데이터 구조에 관해서는 거의 중요하지 않습니다. 까다로운 부분은 변환을 올바르게 수행하고 문헌에서 사용 가능한 알고리즘으로 깔끔하게 작업 할 수있는 방식으로 큐브 상태를 나타낼 수 있다는 것입니다. 메이플 샤프트에 표시된 것처럼 세 가지 유형의 조각이 있습니다. 루빅스 큐브 해결에 관한 문학은 항상 유형별로 조각을 말합니다. 변환도 일반적인 방식으로 표시됩니다 ( Singmaster 표기법 참조 ). 또한 내가 본 모든 솔루션은 항상 한 조각을 참조 점으로 간주합니다 (일반적으로 흰색 중앙 조각을 바닥에 놓음).


1
포인트 2의 경우 무작위 큐브로 시작하여 해결할 수 있는지 확인하는 대신. 나는 해결 된 큐브로 시작하고 큐브에 대해 임의의 상태로 만들기 위해 n 개의 임의 동작을 수행합니다.
Matthew Vines

그렇습니다. 이것은 물리적으로 해결할 수있는 구성을 생성하는 가장 간단한 방법입니다. 임의의 구성으로 시작하여 해결할 수 있는지 여부를 결정하는 것은 확실히 별개의 문제이지만 관련된 문제입니다.
Angelo

2
큐브가 풀 수있는 큐브인지 판별하기위한 "팬시 기술"이있을 수 있다고 추측합니다. 실제로 있습니다. 큐브를 분해하지만 스티커를 켠 상태에서 큐브를 다시 조립하는 경우 반드시 큐브를 얻을 수있는 것은 아닙니다. 실제로, 당신이 해결할 수있는 큐브를 가지고 있다는 것에 대한 확률은 1-12입니다. 가장자리와 모서리 의 패리티 분석을 통해 풀 수있는 상태인지 확인할 수 있습니다 . 실제로 큐브를 해결하려고 할 필요는 없습니다.
Eric Lippert

1
다음은 큐브를 해결할 수 있도록 유지해야하는 3 가지 종류의 큐브 쌍 속성에 대한 간략한 개요입니다. ryanheise.com/cube/cube_laws.html .
Eric Lippert

1
나는 match stackexchange 사이트에 그 질문을 게시하고 정말 좋은 답변을 얻었다 : math.stackexchange.com/questions/127577/…
Mel

3

이미 큰 답변을 받았으므로 세부 사항을 추가하겠습니다.

구체적인 표현에 관계없이, 렌즈 는 큐브의 다양한 부분에서 "확대"하기위한 매우 훌륭한 도구입니다. 예를 들어, 이 Haskell 코드 의 함수 cycleLeft를 보십시오 . 길이 4의 모든 목록을 주기적으로 바꾸는 일반적인 함수입니다. L 이동을 수행하는 코드는 다음과 같습니다.

moveL :: Aut (RubiksCube a)
moveL =
    cong cube $ cong leftCols cycleLeft
              . cong leftSide rotateSideCW

따라서 에 의해 주어진 관점에서cycleLeft 작동 합니다 leftCols . 마찬가지로 rotateSideCW회전 된 버전에 영향을 미치는 일반적인 함수 인,는에서 제공 한보기에서 작동합니다 leftSide. 다른 동작은 유사한 방식으로 구현 될 수 있습니다.

Haskell 라이브러리의 목표는 예쁜 그림을 만드는 것입니다. 나는 그것이 성공했다고 생각한다. 작동중인 diagrams-rubiks-cube 라이브러리


2

두 가지 별도의 질문을하는 것 같습니다.

  1. X면이있는 큐브를 나타내는 방법은 무엇입니까?

실제 Rubic의 큐브를 시뮬레이트하려는 경우 모든 Rubik의 큐브에는 6 개의면이 있습니다. 내 말은 "면당 차원 당 X 타일 수"입니다. 원본 Rubic 큐브의 각면은 3x3입니다. 다른 크기로는 4x4 (Professor 's Cube), 5x5 및 6x6이 있습니다.

"표준"큐브 해결 표기법을 사용하여 6면으로 데이터를 표현합니다.

  • 앞면 : 솔버를 향한면
  • 권리
  • 왼쪽
  • 쪽으로
  • 내려가는

각 변은 X by X의 2 차원 배열입니다.


17x17 큐브를 구입할 수 있습니다 ! 기계적 손상이 있지만 실제로는 동형입니다.
RBerteig

1

나는 @maple_shaft의 아이디어가 다른 조각 (미니 큐브)을 다르게 표현하는 것을 좋아합니다 : 중앙, 가장자리 및 모서리 조각은 각각 1, 2 또는 3 색을 나타냅니다.

인접한 조각을 연결하는 가장자리를 가진 (양방향) 그래프로 이들 간의 관계를 나타냅니다. 각 조각에는 가장자리 (연결) 용 슬롯 배열이 있습니다. 중앙 조각에 4 개 슬롯, 가장자리 조각에 4 개 슬롯, 모서리 조각에 3 개 슬롯. 대안 적으로, 중심 조각은 에지 조각에 4 개의 연결부 및 개별적으로 모서리 조각에 대한 4 개의 연결을 가질 수 있고 / 있거나 에지 조각은 중심 조각에 대한 2 개의 연결 및 개별적으로 모서리에 대한 2 개의 연결을 가질 수있다.

이러한 배열은 그래프 가장자리를 반복 할 때 큐브의 회전을 모듈로하여 항상 '동일한'회전을 나타내도록 정렬됩니다. 즉, 예를 들어 중앙 부분의 경우,면이 위로 오도록 큐브를 회전하면 연결 순서는 항상 시계 방향입니다. 가장자리와 모서리 조각도 비슷합니다. 이 속성은 얼굴 회전 후 유지됩니다 (또는 지금 나에게 보입니다).

  • 가장자리에 속하는 조각을 찾는 것은 쉽지 않습니다.
  • 얼굴에 속하는 조각을 찾는 것은 쉽지 않습니다.
  • 주어진면 또는 반대쪽면에 대해 주어진 방향으로있는면을 찾으면 2 개 또는 3 개의 잘 정의 된 링크를 통과하는 것입니다.
  • 면을 회전 시키려면면의 중앙 부분에 연결된 모든 조각의 연결을 업데이트하십시오.

특정 유형의 조각과 그 방향을 찾는 것이 간단하기 때문에 명확하게 해결할 수없는 조건 (스왑 / 플립 모서리, 스왑 코너)을 쉽게 감지 할 수 있습니다.


1

노드와 포인터는 어떻습니까?

항상 6 개의면이 있고 1 개의 노드가 1면의 1 정사각형을 나타낸다고 가정합니다.

r , g , b
r , g , b
r , g , b
|   |   |
r , g , b - r , g , b
r , g , b - r , g , b
r , g , b - r , g , b

노드에는 옆에있는 각 노드에 대한 포인터가 있습니다. 원 회전은 포인터 (노드 수 /면 수) -1 노드 (이 경우 2) 위로 이동합니다. 모든 회전이 원 회전이므로 하나의 rotate함수 만 작성하면 됩니다. 재귀 적이며 각 노드를 한 공간 이동 한 후 노드 수를 수집하므로 항상 4 개의면이 있으므로 충분히 이동했는지 확인합니다. 그렇지 않은 경우 이동 한 횟수 값을 늘리고 다시 회전하십시오.

이중으로 연결된 것을 잊지 마십시오. 새로 지정된 노드도 업데이트하십시오. 항상 노드 당 하나의 포인터가 업데이트 된 Height * Width 수의 노드가 이동하므로 Height * Width * 2 수의 포인터가 업데이트되어야합니다.

모든 노드가 서로를 가리 키므로 각 노드를 업데이트 할 때 원을 따라 걸어보세요.

이것은 에지 케이스 또는 복잡한 로직없이 모든 크기의 큐브에 적용됩니다. 포인터 걷기 / 업데이트 일뿐입니다.


-1

큐브의 각 회전 부분을 추적하는 세트를 사용하는 개인적인 경험에서 잘 작동합니다. 각 서브 큐브는 3 세트로 루빅 큐브의 크기에 영향을 미치지 않습니다. 따라서 루빅스 큐브에서 하위 세트를 찾으려면 세 세트의 교차점을 가져옵니다 (결과는 하나의 하위 큐브입니다). 이동하려면 영향을받는 서브 큐브를 이동과 관련된 세트에서 제거한 다음 다시 이동의 결과로 가져 오는 세트에 넣습니다.

4 x 4 큐브에는 12 세트가 있습니다. 6 개의면에 6 세트, 큐브 주위에있는 6 개의 밴드에 6 세트. 면에는 각각 16 개의 서브 큐브가 있고 밴드에는 12 개의 서브 큐브가 있습니다. 총 56 개의 서브 큐브가 있습니다. 각 서브 큐브에는 색상 및 색상 방향에 대한 정보가 있습니다. 매직 큐브 자체는 4 x 4 x 4 배열이며 각 요소에는 해당 위치에서 하위 큐브를 정의하는 3 개의 세트로 구성된 정보가 있습니다.

다른 11 개의 답변과 달리이 데이터 구조는 집합의 교차점을 사용하여 큐브의 각 하위 블록 위치를 정의합니다. 이렇게하면 변경시 니어 서브 블록을 업데이트해야하는 작업이 줄어 듭니다.


이것은 이전의 11 가지 답변에서 언급되고 설명 된 내용에 비해 실질적인 내용을 제공하지 않는 것 같습니다
gnat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.