На некоторых старых телефонах Nokia была вариация пятнадцати пазлов под названием «Вращение». В этом варианте вместо скольжения одной плитки за раз вы поворачивали четыре плитки за раз в одном направлении.
В этой игре вы начнете с такой доски:
4 9 2
3 5 7
8 1 6
И, повернув нижний левый блок дважды по часовой стрелке и верхний левый блок один раз по часовой стрелке, вы получите следующее:
4 9 2
8 3 7
1 5 6
4 9 2
1 8 7
3 5 6
1 4 2
8 9 7
3 5 6
и 1
плитка будет в левом верхнем углу, где она должна быть. В конце концов, после нескольких ходов вы получите:
1 2 3
4 5 6
7 8 9
которая является "оригинальной" конфигурацией.
Ваша задача состоит в том, чтобы создать программу, которая будет принимать в качестве входных данных сетку чисел 3x3 от 1 до 9 (в любом формате, которую вы выберете) и возвращать в качестве выходной последовательности ходы, представляющие ходы, которые вы должны предпринять, чтобы вернуть доску обратно в исходное состояние. Конфигурация (опять же, в любом формате, который вы выберете). Под законными ходами понимается перемещение блока [верх / низ] - [влево / вправо] из 4 плиток [по часовой стрелке / против часовой стрелки].
Ваша программа должна быть в состоянии решить все возможные сетки 3х3 (все перестановки разрешимы).
Самый короткий код для этого выигрывает.
источник
...and return as output a sequence of moves representing the moves you must take to return the board back to its original
Означает ли это "вернуться к1 2 3\n4 5 6\n7 8 9
"? Я не уверен, как это читать.Ответы:
GolfScript, 39/83 байта
Скорость против размера
Оптимизированная по размеру версия случайным образом выбирает вращения по часовой стрелке, пока не будет достигнута нужная перестановка. Этого достаточно, поскольку вращение против часовой стрелки эквивалентно трем последовательным вращениям по часовой стрелке одного и того же квадрата.
Оптимизированная по скорости версия делает то же самое, за исключением следующего:
Если число 1 находится в верхнем левом углу, оно больше не поворачивает верхний левый квадрат.
Если число 9 находится в нижнем правом углу, оно больше не вращает нижний правый квадрат.
Шаги для изменения позиций 7 и 8 жестко закодированы, поэтому есть две позиции, которые позволяют разрывать петлю.
Помимо изменения алгоритма, оптимизированная по скорости версия выполняет вращение простым способом, тогда как оптимизированная по размеру версия использует встроенную сортировку GolfScript путем сопоставления. Он также жестко кодирует конечное состояние (для сравнения) вместо сортировки состояния в каждой итерации.
Оптимизированная по скорости версия требует меньше итераций, и каждая итерация намного быстрее сама по себе.
Ориентиры
Я использовал следующий код для рандомизации позиций чисел и выполнения тестовых прогонов, раскомментировав строку, соответствующую тестируемой версии:
Выходные данные показывают минимальное и максимальное количество шагов, необходимых для упорядочения чисел, среднего значения и медианы всех прогонов, а также истекшее время в секундах:
На моей машине (Intel Core i7-3770) среднее время выполнения оптимизированной по размеру версии составило 3,58 минуты. Среднее время выполнения оптимизированной по скорости версии составило 0,20 секунды. Таким образом, оптимизированная по скорости версия примерно в 1075 раз быстрее.
Оптимизированная по скорости версия дает в 114 раз меньше оборотов. Выполнение каждого поворота происходит в 9,4 раза медленнее, что в основном связано с тем, как обновляется состояние.
I / O
Выход состоит из 3-битных чисел. MSB установлен для вращения против часовой стрелки, средний бит установлен для нижних квадратов, а LSB установлен для правых квадратов. Таким образом, 0 (4) - верхний левый квадрат, 1 (5) - верхний правый, 2 (6) - нижний левый и 3 (7) - нижний правый.
Оптимизированная по скорости версия печатает все повороты в одну строку. Оптимизированная по размеру версия печатает один оборот на строку с последующим окончательным положением чисел.
Для версии с оптимизированной скоростью входные данные должны давать массив, содержащий цифры от 1 до 9 при оценке. Для версии с оптимизированным размером входные данные должны быть строкой без заключительного перевода строки; это не оценивается.
Пример работы:
Оптимизированный по размеру код
Обновление состояния достигается следующим образом:
Вращение 2 дает целое число 3 после добавления 1. Если состояние «123456789», то разделение состояния дает «456789».
Прямо перед выполнением «$» самые верхние элементы стека:
«$» Выполняет блок один раз для каждого элемента массива, который будет отсортирован, после нажатия самого элемента.
Индекс 1 в «[4 5 6 7 8 9]» равен -1 (отсутствует), поэтому последний элемент «1420344440» помещается. Это дает 48, код ASCII, соответствующий символу 0. Для 2 и 3, 48 также выдвигается.
Целые числа, заданные для 4, 5, 6, 7, 8 и 9: 49, 52, 50, 48, 51 и 52.
После сортировки первым элементом состояния будет один из элементов, дающих 48; последний будет одним из тех, которые дают 52. Встроенный тип сортировки в целом нестабилен, но я эмпирически подтвердил, что в данном конкретном случае он стабилен.
Результат - «[1 2 3 7 4 6 8 5 9]», что соответствует вращению нижнего левого квадрата по часовой стрелке.
Оптимизированный по скорости код
Обратите внимание, что повороты 3, 0, 7, 6 и 4 меняют местами элементы в позициях 7 и 8, не изменяя положения остальных семи элементов.
источник
Питон с Numpy - 158
Ввод должен быть в следующем формате:
Каждая выходная строка представляет собой ход, закодированный в виде строк
trw
или,blc
и должен читаться следующим образом:t
: верхb
: дноl
: осталосьr
: правоc
: по часовой стрелкеw
: против часовой стрелки (виддершин)Эта программа выполняет случайные перемещения, пока не будет достигнута целевая конфигурация. При приближенном предположении, что каждый ход имеет независимую вероятность 1/9! чтобы попасть в целевую конфигурацию¹, число вращений перед решением экспоненциально распределяется со средним (то есть, средним числом ходов), равным 9! ≈ 3,6 · 10⁵. Это в соответствии с коротким экспериментом (20 прогонов).
¹ 9! быть общее количество конфигураций.
источник
C ++ решение с наименьшим количеством ходов - сначала ширина (1847 символов)
Подумав немного больше, я думаю, что сделал это гораздо эффективнее и разумнее. Это решение, хотя оно, безусловно, не выигрывает в этом гольфе, пока является единственным, которое попытается найти минимальное количество вращений, которое решит доску. Пока что он решает каждую случайную доску, которую я бросил в нее, за девять или менее ходов. Это также работает значительно лучше, чем мой последний, и, надеюсь, в комментариях Денниса ниже.
Из предыдущего решения самым большим изменением было перемещение истории ключей из состояния платы (BS) в новый класс, который хранит историю на заданной глубине (DKH). Каждый раз, когда приложение делает ход, оно проверяет историю на этой глубине и на всех глубинах, прежде чем посмотреть, было ли оно когда-либо оценено, если так, то оно больше не будет добавлено в очередь. Похоже, это значительно уменьшает объем хранилища в очереди (удаляя всю эту историю из самого состояния платы) и, следовательно, в значительной степени уменьшает все глупые сокращения, которые я должен был сделать, чтобы не допустить исчерпания памяти в коде. Кроме того, он работает намного быстрее, так как копировать в очередь намного меньше.
Теперь это простой поиск в разных штатах. Плюс, как оказалось, я хочу изменить набор ключей (в настоящее время хранится как набор чисел в base-9, каждый из которых вычисляется с помощью BS :: key как представление платы base-9) на битовый набор имея 9! биты кажутся ненужными; хотя я узнал, как вычислить ключ в «системе факторных чисел», который можно было бы использовать для вычисления бита в наборе битов для проверки / переключения.
Итак, новейшее решение:
источник
int[]
наconst int[]
и установить флаг-fpermissive
.CJam - 39
Еще один случайный решатель :)
Он принимает строку, например 492357816, и выводит (длинный) ряд цифр от 0 до 3, каждая из которых представляет вращение блока по часовой стрелке: 0 = верхний левый, 1 = верхний правый, 2 = нижний левый, 3 = нижний правый.
Краткое объяснение:
4mr
генерирует случайное число от 0 до 3,_1>+
увеличивает число, если оно больше 1 (таким образом, мы получаем 0, 1, 3 или 4 - начальные индексы 4 блоков),m<
поворачивает строку влево (например, 492357816 -> 923578164, а не вращение блока), чтобы привести блок во вращение в первой позиции,[Z0Y4X]\f=
выполняется вращение блока, которое влияет на первые 5 символов, например 12345 -> 41352;X = 1, Y = 2, Z = 3, поэтому [Z0Y4X] на самом деле [3 0 2 4 1], и это индексы на основе 0 для повернутых тайлов,
5>
копирует остальную часть строки,m>
поворачивает (измененную) строку обратно в право__$>
проверяет, отсортирована ли строка (это условие остановки)источник
Mathematica, 104 символа
Мы можем интерпретировать задачу на языке групп перестановок. Четыре поворота - это всего лишь четыре перестановки, которые генерируют симметрическую группу S 9 , и задача состоит в том, чтобы просто написать перестановку как произведение генераторов. Mathematica имеет встроенную функцию для этого.
Пример:
Входные данные:
Выход:
1
: верхний левый по часовой стрелке2
: верхний правый по часовой стрелке3
: справа внизу по часовой стрелке4
: внизу слева по часовой стрелке-1
: верхний левый против часовой стрелки-2
: верхний правый против часовой стрелки-3
: внизу справа против часовой стрелки-4
: внизу слева против часовой стрелкиисточник