Data structures 你会如何表现一个魔方';代码中的立方体是什么?
如果你正在开发软件来解魔方,你会如何表示魔方?有很多方法可以做到这一点。有些方法比其他方法更有效地利用内存 我见过人们使用3 x 3 x 3长方体对象数组,其中长方体对象需要存储颜色信息(是的,从未使用过中心对象)。我见过人们使用6个数组,每个数组都是3 x 3的长方体数组。我看到了一个3 x 18的长方体阵列。有很多可能性 可能更大的问题是如何表示各种转换。旋转物理立方体的单个面(所有立方体移动本质上都是单个面的旋转)必须通过围绕大量长方体对象交换来表示 您的选择应该对您正在编写的任何应用程序都有意义。可能您只是在渲染多维数据集。可能是没有用户界面。你可能正在解立方体Data structures 你会如何表现一个魔方';代码中的立方体是什么?,data-structures,rubiks-cube,Data Structures,Rubiks Cube,如果你正在开发软件来解魔方,你会如何表示魔方?有很多方法可以做到这一点。有些方法比其他方法更有效地利用内存 我见过人们使用3 x 3 x 3长方体对象数组,其中长方体对象需要存储颜色信息(是的,从未使用过中心对象)。我见过人们使用6个数组,每个数组都是3 x 3的长方体数组。我看到了一个3 x 18的长方体阵列。有很多可能性 可能更大的问题是如何表示各种转换。旋转物理立方体的单个面(所有立方体移动本质上都是单个面的旋转)必须通过围绕大量长方体对象交换来表示 您的选择应该对您正在编写的任何应用程序
我会选择3 x 18阵列。一种方法是关注视觉外观 立方体有六个面,每个面是三乘三的正方形阵列。所以
Color[][][] rubik = new Color[6][3][3];
然后,每次移动都是一种方法,可以排列一组特定的彩色正方形。您可以将立方体想象为三个垂直圆形链表,它们与三个水平链表相交 每当立方体的某一行旋转时,您只需旋转相应的指针 它看起来是这样的:
struct cubeLinkedListNode {
cubedLinkedListNode* nextVertical;
cubedLinkedListNode* lastVertical;
cubedLinkedListNode* nextHorizontal;
cubedLinkedListNode* lastHorizontal;
enum color;
}
WGW
Y G
OBR
实际上,您可能不需要2个“最后”指针
[我用C实现了这一点,但也可以用Java或C实现#只需为cubeLinkedListNode使用一个简单的类,每个类都包含对其他节点的引用。]
记住,有六个互锁的循环链表。3垂直3水平
对于每个旋转,您只需在相应的循环链接列表中循环,顺序移动旋转圆以及连接圆的链接
像这样的东西,至少…有20个立方很重要。一种方法是将其作为20个字符串的数组。字符串将包含指示颜色的2或3个字符。任何一次移动都会影响7个立方体。因此,您只需要为六个面中的每一面重新映射 注意:此解决方案无法记住位于白色中心的徽标标签的方向 顺便说一句,大概15年前,我曾帮助某人制作过一个软件魔方,但我不记得我们是如何表示它的。本文介绍了几种用于表示魔方的替代方法,并将它们相互比较。遗憾的是,我没有获得全文的账户,但描述中指出: 提出并比较了七种不同的魔方表示法:3位整数的3×3×3数组;6×3×3的文字数组;5×12的文字矩阵;逐ll稀疏文字矩阵;54个元素的向量;四维数组;和一个3乘3乘3的嵌套数组。APL函数用于方向移动和四分之一转弯,以及一些用于求解立方体的有用工具
此外,该文件包含一个非常干净的表示,以及用于旋转节的相关代码(如果您正在寻找实际代码)。它使用了一个单元格和面数组。其他的描述了物理立方体,但是关于立方体的状态。。。我会尝试使用向量变换数组来描述立方体的变化。这样,您可以在进行更改时保留rubiks多维数据集的历史记录。我想知道你能不能把向量乘成一个变换矩阵,找到最简单的解?作为48个可以移动的面的排列。基本旋转也是置换,置换可以组合,它们形成一个群
在一个程序中,这种排列将由包含数字0到47的48个元素的数组表示。与数字对应的颜色是固定的,因此可以从排列中计算视觉表示,反之亦然。软件“多维数据集浏览器”使用了一种有趣的表示多维数据集的方法。使用许多聪明的数学,这种方法只能用5个整数来表示立方体。作者在他的电脑上解释了他的程序背后的数学原理。根据作者的说法,该表示法适用于实现快速求解器。避免优化;让它成为面向对象的。我使用的伪代码类大纲是:
class Square
+ name : string
+ accronym : string
class Row
+ left_square : square
+ center_square : square
+ right_square : square
class Face
+ top_row : list of 3 square
+ center_row : list of 3 square
+ bottom_row : list of 3 square
+ rotate(counter_clockwise : boolean) : nothing
class Cube
+ back_face : face
+ left_face : face
+ top_face : face
+ right_face : face
+ front_face : face
+ bottom_face : face
- rotate_face(cube_face : face, counter_clockwise : boolean) : nothing
使用的内存量非常小,处理量非常小,因此完全不需要进行优化,尤其是在牺牲代码可用性的情况下。简单的回答是,这取决于如何解决多维数据集。如果您的解算器将使用人工方法,如逐层方法或Fridrich方法,那么底层数据结构将不会有太大的区别。计算机可以用人类的方法在很短的时间内(不到一秒钟)解出一个立方体,即使是用最慢的编程语言。但是,如果你打算使用计算量更大的方法来求解立方体,比如Thistlethwaite的52-move算法、Reid的29-move算法或Korf的20-move算法,那么数据结构和编程语言是至关重要的 我实现了一个使用OpenGL渲染立方体的魔方程序,它内置了两种不同类型的解算器(Thistlethwaite和Korf)。解算器必须生成数十亿次移动,并对每个立方体状态进行数十亿次比较,因此底层结构必须快速。我尝试了以下结构:
00000000 00000001 00000010 00000011 00000100 00000101 00000000 00000001
WGR
G B
WYO
00000000 00000001 00000010 00000011 00000100 00000101 00000000 00000001
00000000 00000001 00000000 00000001 00000010 00000011 00000100 00000101
WGW
Y G
OBR
0 1 2 3 4 5 6 7 8 9 10 11 // Index.
UB UR UF UL FR FL BL BR DF DL DB DR // Position (up-back, ..., down-right).
RY RG RW RB WG WB YB YG OW OB OY OG // Colors (red-yellow, ..., orange-green).
0 1 2 3 4 5 6 7
ULB URB URF ULF DLF DLB DRB DRF
RBY RGY RGW RBW OBW OBY OGY OGW
const byte // symmetry
M[] = {2,4,3,5},
I[] = {2,0,4,6};
byte cube[55]; // 0,0,0,0,0,0,0,0,0, 1,1,1,1,1,1,1,1,1, ... need to be filled first
#define m9(f, m) (m6(f, m)*9)
byte m6(byte f, byte m) {return ((f&~1)+M[m+(f&1)*(3-2*m)])%6;}
void swap(byte a, byte b, byte n) {
while (n--) {byte t=cube[a+n]; cube[a+n]=cube[b+n]; cube[b+n]=t;}
}
void rotate(byte f, byte a) { // where f is face, and a is number of 90 degree turns
int c=m9(f, 3), i;
swap(c, c+8, 1);
while (a--%4) for (i=2; i>=0; --i)
swap(m9(f, i) + I[i], m9(f, i+1) + I[i+1], 3),
swap(f*9+i*2, f*9+i*2+2, 2);
swap(c, c+8, 1);
}