Алгоритм вращения кубика рубика
В настоящее время я работаю над заданием построить кубик Рубика. Программа не нуждается в графическом интерфейсе. Но он должен имитировать куб 3 X 3 с режимами вращения и обеспечивать графическое представление куба (я собираюсь с плоской буквенной структурой). В моем коде есть класс для граней, которые делают Face (другой класс), а затем есть класс куба, который содержит методы вращения.
У меня возникают проблемы при создании / выборе алгоритма, который бы точно моделировал куб и все возможные вращения. На этом сайте я нашел решение, ссылаясь на статью, предлагающую 7 различных способов сделать это (ссылка ниже). Но какой метод является наиболее интуитивно понятным / простым в написании кода? И что еще более важно, что лучше всего соответствует поведению, описанному ниже (в псевдокоде)?
У меня возникают проблемы с пониманием того, как я мог бы использовать любой метод для учета изменений на каждой грани сразу, особенно если учитывать поведение поворотов грани (в отличие от строк и столбцов).
Как бы вы представили кубик Рубика в коде?
Rotation Pseudocode:
map each cube numbers 1-54, faces 1 – 4 are 1 – 36 while top face is 37 - 45 and bottom is 46 – 54
1 turn: clockwise = +9
1 turn: counterclockwise = -9 loops back to 45
1 turn: up = + 37
1 turn: down = -37 loops back to 46
2 turns: clockwise = +9(2)
2 turns: counterclockwise = -9(2)
2 turns: up = +37(2)
2 turns: down = -37(2)
3 turns: clockwise = +9(3)
3 turns: counterclockwise = -9(3)
3 turns: up = +37(3)
3 turns: down = -37(3)
Этот псевдокод не учитывает изменения лица.
Есть ли лучший / более простой способ сделать это, отличающийся от метода, предлагаемого моим псевдокодом? Как мне учесть изменения лица?
Пример: (передняя сторона, 1 поворот, по часовой стрелке)
123 741
456 852
789 963
Примечание: я склоняюсь к вектору из 54 элементов, но не знаю, как им манипулировать.
Кроме того, это мой первый вопрос, поэтому дайте мне знать, если что-то не так (недостаточно информации, слишком много, неправильная тема и т. Д.)
Спасибо!
Примечание: это код, с которым я работаю.
Класс Граней:
public class Facets {
public Color color;
public Facets(Color color){
}
public enum Color {
B, G, R, Y, O, P
}
public String getName(){
return this.color.name();
}
}
Класс лица:
import java.util.Arrays;
public class Face {
public Facets[] face;
/*public Face(Facets.Color color, Facets.Color[] array){
face = new Facets[9];
for(int i = 0; i < face.length; i++){
face[i] = new Facets(array[i]);
face[i] = new Facets(color);
}
}*/
public Face(Facets.Color color){
face = new Facets[9];
for(int i = 0; i < face.length; i++){
face[i] = new Facets(color);
}
}
public Face(Facets.Color[] array){
face = new Facets[9];
for (int i = 0; i < face.length; i++){
face[i] = new Facets(array[i]);
//face[i] = face[i].toString();
}
}
//Returns a textual representation of Face
public String printFace(){
StringBuilder faceString = new StringBuilder();
for(Facets f: face){
faceString.append(f.getName());
System.out.println(f.toString());
}
return faceString.toString();
}
public static void main(String[] args){
Face face = new Face(Facets.Color.B);
System.out.println(face.toString());
}
}
Кубический класс:
public class Cube {
public Cube(Face front, Face right, Face back, Face left, Face top, Face bottom){
}
public Cube createCube(){
}
public Cube rotate(int row, int column, String direction, int turns){
/*Turns must be between 0 - 4
Row must be 1 or 2, column must be 1 or 2, direction must be clockwise, counterclockwise, up or down (0 means no turn, 1 is top row or left column; 2 is bottom row or right column)
*/
}
public int turns(){
}
public Cube row(){
}
public Cube column(){
}
public Cube clockwise(){
}
public Cube counterClockwise(){
}
public Cube up(){
}
public Cube down(){
}
public Cube random(Cube cube){
}
public Cube configuration(Cube cube){
}
}
Кубик Рубика:
public class RubiksCube {
public RubiksCube(Cube cube){
}
public RubiksCube(Face front, Face rightOfFront, Face back, Face leftOfFront, Face top, Face bottom){
}
//calls face and colors and initializes the arrays into a object
//default config: solid color on each side so each array, representing a face, is set to a solid color
public void createNewCube(){
}
public void rotation(Cube cube, int row, int column, String direction, int turns){
}
public Cube configuration(Cube cube){//should return 6 Faces? or cube?
return cube;
}
}
2 ответа
Подумайте, какая структура данных облегчает концептуализацию куба. Разные решения в приведенной вами ссылке имеют свои плюсы и минусы. Вы можете иметь более краткую структуру (то есть представление из пяти целых чисел), которая занимает меньше памяти и оптимизирует производительность. Но с этим представлением может быть трудно работать, если вы новичок в проблеме. На другом конце спектра находится объектно-ориентированное представление, которое моделирует то, как большинство людей думают о кубике Рубика. Это может быть лучшим подходом для кого-то новичка в кубиках Рубика.
После того, как у вас есть структура данных, которая имеет смысл для вас, подумайте о различных операциях, которые можно выполнить с кубом. Вы можете зафиксировать каждое из этих перемещений в функции, которая изменяет состояние данных. Если у вас есть настоящий кубик Рубика, поиграйте, каковы все различные ходы и как они меняют значения кубика Рубика. Затем попробуйте смоделировать их в своих собственных функциях. то есть поворот в верхнем направлении приведет к изменению пяти из шести граней, верно. Это приведет к тому, что четыре лица получат верхний ряд своего соседа. И это также вызовет сдвиг в верхней части лица. Нижняя поверхность не пострадает.
Если вы чувствуете себя перегруженными сложностью, попробуйте разбить вашу проблему на более мелкую. Возможно, вы можете попытаться написать представление для кубика Рубика размером 2 x 2, а не 3 x 3. Как только вы справитесь с меньшей задачей, вернитесь к более крупной.
Я только начал писать код для манипулирования кубом.
package p;
import java.util.Arrays;
import static p.Facet.*;
enum Facet { // used for face, color, and operations
u(1),d(1),r(2),l(0),f(1),b(3); // maybe FRULBD instead?
Facet(int pad) {
this.pad=pad;
}
// u pad n+1
// l pad 0
// f pad n+1
// r pad 2(n+1)
// b pad 3(n+1) or at the bottom.
// d pad n+1
final int pad; // for formatting
}
class Face {
Face(int n,Facet facet) {
this.n=n;
this.facet=facet;
facets=new Facet[n][n];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
facets[i][j]=facet;
}
Face(Face face) {
this.n=face.n;
this.facet=face.facet;
facets=new Facet[n][n];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
facets[i][j]=face.facets[i][j];
}
@Override public String toString() {
return toString(0);
}
public String toString(int pad) {
StringBuffer stringBuffer=new StringBuffer();
for(int i=0;i<n;i++) {
stringBuffer.append(pad(pad,n));
for(int j=0;j<n;j++)
stringBuffer.append(facets[i][j]);
stringBuffer.append('\n');
}
return stringBuffer.toString();
}
String pad() {
return pad(facet.pad,n);
}
static String pad(int length) {
StringBuffer stringBuffer=new StringBuffer(length);
for(int i=0;i<length;i++)
stringBuffer.append(" ");
return stringBuffer.toString();
}
static String pad(int length,int n) {
return pad(length*(n+1));
}
@Override public int hashCode() {
final int prime=31;
int result=1;
result=prime*result+((facet==null)?0:facet.hashCode());
result=prime*result+Arrays.deepHashCode(facets);
result=prime*result+n;
return result;
}
@Override public boolean equals(Object obj) {
if(this==obj) return true;
if(obj==null) return false;
if(getClass()!=obj.getClass()) return false;
Face other=(Face)obj;
if(facet!=other.facet) return false;
if(!Arrays.deepEquals(facets,other.facets)) return false;
if(n!=other.n) return false;
return true;
}
static void rotateClockwise(Object[][] objects) {
Object temp;
int n=objects.length;
// For each concentric square around the middle of the matrix to rotate...
// This value will be used as (m, n) offset when moving in.
// Integer division by 2 will skip center if odd length.
for(int i=0;i<n/2;i++)
// for the length of this ring
for(int j=0;j<n-2*i-1;j++) {
temp=objects[i][i+j];
objects[i][i+j]=objects[n-i-j-1][i];
objects[n-i-j-1][i]=objects[n-i-1][n-i-j-1];
objects[n-i-1][n-i-j-1]=objects[i+j][n-i-1];
objects[i+j][n-i-1]=temp;
}
}
static void rotateCounterClockwise(Object[][] objects) {
int n=objects.length;
for(int i=0;i<n/2;i++) {
for(int j=i;j<n-i-1;j++) {
Object temp=objects[i][j];
objects[i][j]=objects[j][n-1-i]; // move values from right to top
objects[j][n-1-i]=objects[n-1-i][n-1-j]; // move values from bottom to right
objects[n-1-i][n-1-j]=objects[n-1-j][i]; // move values from left to bottom
objects[n-1-j][i]=temp;
}
}
}
final int n;
final Facet facet;
final Facet[][] facets;
}
class Cube {
Cube(int n) {
u=new Face(n,Facet.u);
d=new Face(n,Facet.d);
r=new Face(n,Facet.r);
l=new Face(n,Facet.l);
f=new Face(n,Facet.f);
b=new Face(n,Facet.b);
}
void rotatex(Face face,Face old) {
for(int i=0;i<face.n;i++)
for(int j=0;i<face.n;j++)
face.facets[i][j]=old.facets[i][j];
}
void rotateConterClockwise(Face f,Face u,Face l,Face d,Face r) {
for(int i=0;i<3;i++)
rotate(f,u,l,d,r);
}
void rotate(Face f,Face u,Face l,Face d,Face r) {
Face.rotateClockwise(f.facets);
Facet[] top=new Facet[u.n];
for(int i=0;i<u.n;i++)
top[i]=u.facets[u.n-1][i];
for(int i=0;i<u.n;i++) // move left to u
u.facets[u.n-1][i]=l.facets[u.n-i-1][u.n-1];
for(int i=0;i<u.n;i++) // bottom to left
l.facets[u.n-i-1][u.n-1]=d.facets[0][i];
for(int i=0;i<u.n;i++) // right to bottom
d.facets[0][i]=r.facets[i][0];
for(int i=0;i<u.n;i++)
r.facets[i][0]=top[i];
}
void op(Facet facet) {
switch(facet) {
case b:
rotate(b,u,r,d,l);
break;
case d:
rotate(d,f,l,b,r);
break;
case f:
rotate(f,u,l,d,r);
break;
case l:
rotate(l,u,b,d,f);
break;
case r:
rotate(r,u,f,d,b);
break;
case u:
rotate(u,d,l,f,r);
break;
}
}
void opInverse(Facet facet) {
switch(facet) {
case b:
rotateConterClockwise(b,u,r,d,l);
break;
case d:
rotateConterClockwise(d,f,l,b,r);
break;
case f:
rotateConterClockwise(f,u,l,d,r);
break;
case l:
rotateConterClockwise(l,u,b,d,f);
break;
case r:
rotateConterClockwise(r,u,f,d,b);
break;
case u:
rotateConterClockwise(u,d,l,f,r);
break;
}
}
@Override public int hashCode() {
final int prime=31;
int result=1;
result=prime*result+((b==null)?0:b.hashCode());
result=prime*result+((d==null)?0:d.hashCode());
result=prime*result+((f==null)?0:f.hashCode());
result=prime*result+((l==null)?0:l.hashCode());
result=prime*result+((r==null)?0:r.hashCode());
result=prime*result+((u==null)?0:u.hashCode());
return result;
}
@Override public boolean equals(Object obj) {
if(this==obj) return true;
if(obj==null) return false;
if(getClass()!=obj.getClass()) return false;
Cube other=(Cube)obj;
if(b==null) {
if(other.b!=null) return false;
} else if(!b.equals(other.b)) return false;
if(d==null) {
if(other.d!=null) return false;
} else if(!d.equals(other.d)) return false;
if(f==null) {
if(other.f!=null) return false;
} else if(!f.equals(other.f)) return false;
if(l==null) {
if(other.l!=null) return false;
} else if(!l.equals(other.l)) return false;
if(r==null) {
if(other.r!=null) return false;
} else if(!r.equals(other.r)) return false;
if(u==null) {
if(other.u!=null) return false;
} else if(!u.equals(other.u)) return false;
return true;
}
@Override public String toString() { //ulfrbd
StringBuffer stringBuffer=new StringBuffer(3*4*(u.n+1));
for(int i=0;i<u.n;i++) {
stringBuffer.append(u.pad());
for(int j=0;j<u.n;j++)
stringBuffer.append(u.facets[i][j]);
stringBuffer.append('\n');
}
for(int i=0;i<u.n;i++) {
stringBuffer.append(l.pad());
for(int j=0;j<u.n;j++)
stringBuffer.append(l.facets[i][j]);
stringBuffer.append(' ');
for(int j=0;j<u.n;j++)
stringBuffer.append(f.facets[i][j]);
stringBuffer.append(' ');
for(int j=0;j<u.n;j++)
stringBuffer.append(r.facets[i][j]);
stringBuffer.append(' ');
for(int j=0;j<u.n;j++)
stringBuffer.append(b.facets[i][j]);
stringBuffer.append('\n');
}
for(int i=0;i<u.n;i++) {
stringBuffer.append(d.pad());
for(int j=0;j<u.n;j++)
stringBuffer.append(d.facets[i][j]);
stringBuffer.append('\n');
}
return stringBuffer.toString();
}
final Face u,d,r,l,f,b;
}
public class Main {
public static void main(String[] args) {
Cube initial=new Cube(3);
Cube cube=new Cube(3);
System.out.println(cube.u.facets[0][0]);
System.out.println(cube.u);
System.out.println(cube);
for(int i=0;i<4;i++) {
cube.op(Facet.f);
System.out.println(cube);
}
// F' U L' U'
cube=new Cube(3);
int i=0;
do {
fpulpup(cube);
System.out.println(i);
System.out.println(cube);
i++;
} while(!cube.equals(initial));
}
private static void fpulpup(Cube cube) {
cube.opInverse(f);
cube.op(u);
cube.opInverse(l);
cube.opInverse(f);
}
}