В то время как лениво крутя кубик моего Рубика , мой сын заметил, что он продолжает возвращаться в решенное состояние. Я почти уверен, что сначала он подумал, что это какая-то магия вуду, но я объяснил, что если вы продолжите повторять одну и ту же последовательность движений, она всегда вернется в исходное состояние. В итоге.
Конечно, будучи ребенком, он должен был попробовать это сам и выбрал «случайную» последовательность, которую он считал хитрой. Он потерял трек после десяти повторений или около того, и спросил меня, сколько раз ему придется повторить это. Не зная последовательности, которую он использовал, я сказал ему, что не знаю, но мы могли бы написать программу, чтобы узнать.
Это то место, куда вы приходите. Конечно, я мог бы просто что-то взбить, но он хотел бы напечатать это сам. Хотя он еще не очень быстрая машинистка, поэтому мне нужна самая короткая из возможных программ .
Задача
При заданной последовательности поворотов выведите наименьшее количество раз, которое необходимо выполнить, чтобы вернуть куб в исходное состояние. Это код гольф, поэтому выигрывает минимум байтов. Вы можете написать программу или функцию, и все остальные обычные значения по умолчанию применяются.
вход
Ввод - это последовательность шагов, взятая в виде строки, списка или другого формата, подходящего для вашего языка. Не стесняйтесь использовать разделитель (или нет) между ходами, если в форме строки.
Есть шесть «основных» ходов, которые должны быть приняты во внимание, вместе с их обратными:
R - Turn the right face clockwise
L - Turn the left face clockwise
U - Turn the up (top) face clockwise
D - Turn the down (bottom) face clockwise
F - Turn the front face clockwise
B - Turn the back face clockwise
Обратное представлено добавлением простого знака '
после буквы. Это означает, что вы поворачиваете эту грань против часовой стрелки, поэтому F'
поворачиваете лицевую грань против часовой стрелки и сразу F F'
же возвращаете ее в исходное состояние.
Для заинтересованных в этой задаче используется ограниченный набор нотаций Singmaster . Ruwix имеет несколько хороших анимаций, если вы хотите увидеть его в действии.
Выход
Выход - это просто минимальное количество раз, которое должна быть выполнена последовательность ввода.
Примеры
Input Output
FF' -> 1
R -> 4
RUR'U' -> 6
LLUUFFUURRUU -> 12
LUFFRDRBF -> 56
LF -> 105
UFFR'DBBRL' -> 120
FRBL -> 315
Вот (довольно наивный) решатель для сравнения ваших ответов, написанных на Java. Он также принимает 2
двойные ходы (поэтому четвертый случай эквивалентен L2U2F2U2R2U2
).
import java.util.ArrayList;
import java.util.List;
public class CycleCounter{
public static void main(String[] args){
int[] cube = new int[54];
for(int i=0;i<54;i++)
cube[i] = i;
String test = args.length > 0 ? args[0] : "RUR'U'";
List<Rotation> steps = parse(test);
System.out.println(steps.toString());
int count = 0;
do{
for(Rotation step : steps)
cube = step.getRotated(cube);
count++;
}while(!isSorted(cube));
System.out.println("Cycle length for " + test + " is " + count);
}
static List<Rotation> parse(String in){
List<Rotation> steps = new ArrayList<Rotation>();
for(char c : in.toUpperCase().toCharArray())
switch(c){
case 'R':steps.add(Rotation.R);break;
case 'L':steps.add(Rotation.L);break;
case 'U':steps.add(Rotation.U);break;
case 'D':steps.add(Rotation.D);break;
case 'F':steps.add(Rotation.F);break;
case 'B':steps.add(Rotation.B);break;
case '\'':
steps.add(steps.get(steps.size()-1));
case '2':
steps.add(steps.get(steps.size()-1));
break;
}
return steps;
}
static boolean isSorted(int[] in){for(int i=0;i<in.length-1;i++)if(in[i]>in[i+1])return false;return true;}
enum Rotation{
R(new int[]{-1,-1,42,-1,-1,39,-1,-1,36, -1,-1,2,-1,-1,5,-1,-1,8, 20,23,26,19,-1,25,18,21,24, -1,-1,11,-1,-1,14,-1,-1,17, 35,-1,-1,32,-1,-1,29,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1}),
L(new int[]{9,-1,-1,12,-1,-1,15,-1,-1, 27,-1,-1,30,-1,-1,33,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1, 44,-1,-1,41,-1,-1,38,-1,-1, -1,-1,6,-1,-1,3,-1,-1,0, 47,50,53,46,-1,52,45,48,51}),
U(new int[]{2,5,8,1,-1,7,0,3,6, 45,46,47,-1,-1,-1,-1,-1,-1, 9,10,11,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1, 18,19,20,-1,-1,-1,-1,-1,-1, 36,37,38,-1,-1,-1,-1,-1,-1}),
D(new int[]{-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,24,25,26, -1,-1,-1,-1,-1,-1,42,43,44, 29,32,35,28,-1,34,27,30,33, -1,-1,-1,-1,-1,-1,51,52,53, -1,-1,-1,-1,-1,-1,15,16,17}),
F(new int[]{-1,-1,-1,-1,-1,-1,18,21,24, 11,14,17,10,-1,16,9,12,15, 29,-1,-1,28,-1,-1,27,-1,-1, 47,50,53,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,8,-1,-1,7,-1,-1,6}),
B(new int[]{51,48,45,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,0,-1,-1,1,-1,-1,2, -1,-1,-1,-1,-1,-1,26,23,20, 38,41,44,37,-1,43,36,39,42, 33,-1,-1,34,-1,-1,35,-1,-1});
private final int[] moves;
Rotation(int[] moves){
this.moves = moves;
}
public int[] getRotated(int[] cube){
int[] newCube = new int[54];
for(int i=0;i<54;i++)
if(moves[i]<0)
newCube[i] = cube[i];
else
newCube[moves[i]] = cube[i];
return newCube;
}
}
}
источник
Ответы:
Pyth,
6663 байтаПопробуйте онлайн: демонстрация или тестовый набор . Обратите внимание, что программа работает довольно медленно, и онлайн-компилятор не может вычислить ответ
RU2D'BD'
. Но будьте уверены, что он сможет вычислить его на моем ноутбуке примерно за 12 секунд.Программа (случайно) также принимает
2
для двойных ходов.Полное объяснение:
Разбор схватки:
Сначала я разберусь с простыми метками
'
во входных строках. Я просто заменяю их на «3
run-length» и декодирую эту строку. Поскольку формат декодирования Pyth требует числа перед символом, я заранее переворачиваю строку._r_Xz\'\39
, Так что потом я возвращаю его обратно.Опишите решенное состояние куба:
=Z"UDLRFB
назначает строку со всеми 6 ходамиZ
.Мы можем описать состояние куба, описав местоположение каждой части куба. Например, мы можем сказать, что край, который должен быть в UL (вверх-влево), в настоящее время находится в FR (передний-правый). Для этого мне нужно создать все части решаемой кубы:
f!s}RTcZ2yZ
.yZ
генерирует все возможные подмножества"UDLRFB"
. Это, очевидно, также генерирует подмножество"UDLRFB"
и подмножество"UD"
. Первый не имеет никакого смысла, так как нет никакого фрагмента, который виден со всех 6 сторон, а второй не имеет никакого смысла, так как нет краевого фрагмента, который виден сверху и снизу. , Поэтому я удаляю все подмножества, которые содержат подпоследовательность"UD"
,"LR"
или"FB"
. Это дает мне следующие 27 штук:Это также включает пустую строку и все шесть однобуквенных строк. Мы могли бы интерпретировать их как часть в середине куба и 6 центральных частей. Очевидно, они не обязательны (так как они не двигаются), но я их оставлю.
Делаем несколько ходов:
Я сделаю несколько переводов строк, чтобы выполнить движение. Чтобы визуализировать идею, взгляните на угол в
URF
. Что с ним происходит, когда я делаюR
ход? Наклейка наU
лице перемещается кB
лицу, наклейкаF
перемещается наU
лицо, а наклейка наR
лице остается наR
лице. Можно сказать, что фигура приURF
перемещении на свою позициюBRU
. Эта модель верна для всех фигур на правой стороне. Каждая наклейка наF
лице перемещается кU
лицу при выполненииR
перемещения, каждая наклейка наU
лице перемещается кB
лицу, каждая наклейкаB
перемещается вD
и каждая наклейкаD
перемещается вF
, Мы можем расшифровать измененияR
хода какFUBD
.Следующий код генерирует все 6 необходимых кодов:
И мы выполняем переход
H
в состояние кубаG
следующим образом:Подсчитайте количество повторений:
Остальное в значительной степени тривиально. Я просто выполняю вводную схватку с решенным кубом снова и снова, пока не достигну позиции, которую посещал ранее.
источник
GAP,
792 783 782749650 байтКажется, это работает. Если что-то напутает, дайте мне знать.
Спасибо @Lynn за предложение разложить некоторые примитивные движения.
Спасибо @Neil за предложение, что
Inverse(X)
я используюX^3
.Пример использования:
f("R");
Вот незагрязненный код с небольшим объяснением
источник
45
на5
в своих перестановках и сохранить три байта.A:=R*L*L*L*F*F*B*B*R*L*L*L;D:=A*U*A;
оно короче, чем ваше определение дляD
(но я не могу это проверить ...)^-1
Кстати, GAP не позволяет вам писать для инверсий?Mathematica,
413401 байтПояснения
Кубик Рубика состоит из 20 подвижных кубиков (8 углов, 12 ребер). Каждому кубику может быть присвоен номер:
углы :
края :
Обратите внимание, что когда кубик закручен, кубы больше не находятся на своих начальных позициях. Например, когда
R
все готово, куби1
перемещаетсяUFR
в новую позициюUBR
.В таких обозначениях поворот на 90 градусов можно описать 8 движениями кубиков. Например,
R
описываетсяПоскольку у каждого кубика есть уникальная стартовая позиция, у каждой позиции есть уникальный стартовый кубик. То есть правило
UFR->UBR
справедливо1->2
(означает, чтоR
куби переводится в исходное положение куби1
в исходное положение кубики2
). Таким образом, вR
дальнейшем можно упростить циклЧтобы полностью решить кубик Рубика, нам также необходимо выровнять кубики по их соответствующим начальным ориентациям. Грани куба окрашены в разные цвета, схема, которую я часто использую при решении кубов:
Когда мы анализируем ориентацию углов, цвета, отличные от желтого или белого, игнорируются, а желтый и белый считаются одним и тем же цветом.
Предположим, куби
1
находится в исходном положенииUFR
, желтая грань может быть выровнена по трем различным граням. Мы используем целое число для представления этих случаев,Пусть Cubie
1
наDFL
, его три возможных ориентацииКогда мы анализируем ориентацию ребер, красный и оранжевый игнорируются, а желтый и белый игнорируются, только если у ребра есть зеленая или синяя грань.
Предположим, куби
10
находится в исходном положенииUR
, зеленая грань может быть выровнена по двум разным граням. Его две возможные ориентацииПусть Cubie
10
наDF
, его две возможные ориентацииМассив используется для хранения состояния куба. Начальное состояние куба
это означает, что все кубики находятся в исходном положении с правильной ориентацией.
После того
R
, как состояние куба становитсяэто означает, что
5
теперь cubie находится в position1
(UFR
) с ориентацией2
, cubie1
теперь находится в position2
(UBR
) с ориентацией1
, cubie3
все еще находится в position3
(UBL
) с ориентацией0
и так далее.Контрольные примеры
источник
Haskell, 252 байта
Образцы прогонов:
Ключевое наблюдение здесь заключается в том, что кубик Рубика проще моделировать как сетку точек 5 × 5 × 5, а не как сетку ориентированных кубиков 3 × 3 × 3. Угловые кубики становятся кубами с размерами 2 × 2 × 2, краевые кубики становятся квадратами с размерами 2 × 2 × 1, а движения вращаются срезами по 5 × 5 × 2 точки.
источник
c:"'"
наc:_
экономит два байта._
также соответствует пустому списку.Рубин, 225 байт
Подобный ответ Андерс Kaseorg и вдохновленный Ян Дворжак ответа на предыдущий вопрос.
Однако, в отличие от этих ответов, мне не нужно 125 кубиков. Я использую кубик Рубика из 27 кубиков, но прямоугольных размеров. В решенном состоянии углы находятся на
+/-1,+/-4,+/-16
.Я генерирую массив из 64 кубов, каждый с выбранным центром
x=[-1,0,1,2], y=[-4,0,4,8], z=[-16-0,16,32]
. Кубики с координатами 2, 8 и 32 не нужны, но они не причиняют вреда, поэтому их оставляют по соображениям игры в гольф. Тот факт, что длина, ширина и глубина кубов различны: (1,4,16) означает, что легко определить, находятся ли они в нужном месте, но имеют неправильную ориентацию.Каждый кубик отслеживается, так как он перемещается по поворотам. Если координата куба на оси, соответствующей грани (умноженная на
e=-1
для U, F, R илиe=1
для D, B, L), положительна, то она будет повернута путем замены координат в двух других осях и применения соответствующее изменение знака одной из координат. Это контролируется умножением наe*d
.Входная последовательность сканируется в обратном порядке. Это не имеет значения, пока «нормальные» вращения выполняются против часовой стрелки, а не по часовой стрелке. Причина этого заключается в том, что если
'
символ найден, значениеd
можно изменить с 1 на -1, чтобы вызвать поворот следующей грани в противоположном направлении.Неуправляемый в тестовой программе
источник
Python 2, 343 байта
Ввод взят из стандартного ввода.
Данная последовательность поворотов выполняется многократно на виртуальном кубе, пока не вернется в разрешенное состояние. Состояние куба сохраняется как вектор ориентации и вектор перестановки длиной 20.
Ориентации несколько произвольно определены: ребро куба ориентировано правильно, если его можно переместить на место, не вызывая четверть оборота R или L. Ориентация угловых кубов рассматривается относительно граней F и B.
Образец использования
Демонстрация и тестирование онлайн .
источник
Clojure, 359 байтов
Это может быть мой второй самый длинный Codegolf. Понимая , я мог бы упасть конечные нули из векторов
A
дляF
меня очень счастливым: DМенее гольф:
Это просто реализует трехмерные вращения выбранных подмножеств
5 x 5 x 5
куба. Первоначально я собирался использовать,3 x 3 x 3
и мне потребовалось некоторое время, чтобы понять, почему я не получил правильные результаты. Хорошие тесты! Некоторые дополнительные байты для кодирования кулака"RUR'U'"
как"RURRRUUU"
.источник
Кубы ,
96 байтПопробуйте онлайн! (Не работает до тех пор, пока Деннис не обновит кубический переводчик TIO)
Объяснение:
Этот язык будет доминировать над всеми кубиками-кубиками >: D
источник
-7
означало вычесть семь, а не добавить один сердито трясет ходокаЧисто , 255 байт
Полученный отдельно от почти идентичного ответа на Haskell в качестве ответа на этот вопрос, который был закрыт как дубликат, когда он был почти закончен, поэтому я разместил ответ здесь.
Попробуйте онлайн!
источник