Я реализовал программу Cube Рубика, которая визуализирует куб с использованием OpenGL, и у него есть встроенный решатель. Решатель должен генерировать миллионы ходов и сравнивать каждое состояние куба миллионы раз, поэтому основная структура должна быть быстрой. Я пробовал следующие структуры:
- Трехмерный массив символов, 6x3x3. Цвет лица индексируется как куб [SIDE] [ROW] [COL]. Это было интуитивно понятно, но медленно.
- Один массив из 54 символов. Это было улучшение скорости, и ряд и шаг были вычислены вручную (тривиально).
- 6 64-битных целых. Этот метод, по сути, является битбордом, и он был самым быстрым из всех.
Каждая сторона куба состоит из 9 стикеров, но центр неподвижен, поэтому необходимо хранить только 8 стикеров. И есть 6 цветов, поэтому каждый цвет помещается в байте. Учитывая эти определения цвета:
enum class COLOR : uchar {WHITE, GREEN, RED, BLUE, ORANGE, YELLOW};
Лицо может выглядеть так, хранящееся в одном 64-разрядном целом числе:
00000000 00000001 00000010 00000011 00000100 00000101 00000000 00000001
Что расшифровывается как:
WGR
G B
WYO
Преимущество использования этой структуры заключается в том, что побитовые операторы rolq
и rorq
могут использоваться для перемещения лица. Роллинг на 16 бит приводит к повороту на 90 градусов; прокатка на 32 бита дает поворот на 180 градусов. Соседние части должны быть сохранены вручную, т.е. после поворота верхней грани также необходимо переместить верхний слой передней, левой, задней и правой граней. Поворот лица таким способом действительно быстр. Например, прокат
00000000 00000001 00000010 00000011 00000100 00000101 00000000 00000001
16 битными выходами
00000000 00000001 00000000 00000001 00000010 00000011 00000100 00000101
Расшифровано, это выглядит так:
WGW
Y G
OBR
Еще одним преимуществом является то, что сравнение состояний куба в некоторых случаях может быть выполнено с использованием некоторых умных битовых масок и стандартных целочисленных сравнений. Это может быть довольно большим ускорением для решателя.
В любом случае, моя реализация на github: https://github.com/benbotto/rubiks-cube-cracker/tree/master/Model См. RubiksCubeModel.{h,cpp}
.
Как уже упоминалось, программа также отображает куб. Я использовал другую структуру для этой части. Я определил класс "cubie", представляющий собой квадрат с 1, 2 или 3 цветными гранями для центра, ребра и угловых элементов соответственно. Кубик Рубика состоит из 26 кубиков. Грани вращаются с использованием кватернионов. Код для кубиков и кубов здесь: https://github.com/benbotto/rubiks-cube-cracker/tree/master/Model/WorldObject
Примечание: мой решатель не самый быстрый. Он похож на алгоритм Thistlethwaite, но моей целью было решить куб по-человечески, а не решить его за наименьшее количество возможных ходов. Мой ответ касается базовых структур данных, а не решения куба.