Для предстоящей программки, где можно запускать обратимые клеточные автоматы я хочу сделать возможность задавать любые правила. Как я описывал в посте про Critters, любая перестановка массива от 0
до N
является корректным правилом. Значит должна быть возможность задавать перестановку в виде чего-то, что можно скопипастить и вставить в программу.
На одном сайте с обратимыми автоматами перестановка задаётся так:
0,2,8,3,1,5,6,7,4,9,10,11,12,13,14,15
По мне это довольно скучно и не очень удобно.
Поэтому я придумал, что это надо отображать одним числом, которое можно менять на +1
, -1
, и оно будет корректным. А затем вообще переводить это число в систему счисления с основанием 64
, чтобы оно было ещё короче.
Итак, для массива из N
различных элементов существует N!
возможных вариантов перестановки. Значит можно как-то пронумеровать каждую перестановку одним числом. И если сделать так, то пользователь сможет играться, меняя числа, у него всегда будет получаться корректное правило. Если он, конечно, не задаст число больше N!
, но не допустить такую ошибку довольно легко.
Итак, перестановка, показанная вначале может быть записана числом как:
125023449600
Или если же это число перевести в 64
-ричную систему счисления:
08D+rQ1
Я сделал маленькую библиотечку чтобы вычислять все эти вещи: permutation_string.
Всеми этими тремя способами в моей программе можно будет задавать правила.
Так же я хочу сделать GUI, чтобы правила можно было перетаскивать мышкой, и чтобы рядом писались все эти данные. Благо на megaui в macroquad сделать это довольно легко. Не знал кстати что Immediate Mode GUI такой простой о_О. Какой-то диссонанс происходит после того как ты делал гуй на всех этих коллбэках. Попробуйте почитать код, и потыкаться.
А теперь я расскажу как именно можно превратить перестановку в одно число.
Пусть у нас есть перестановка А
из пяти элементов: [4,1,2,3,0]
. Главное свойство любой перестановки - в ней все числа уникальны. Значит можно преобразовать этот массив в немного другой.
Пусть у нас ещё есть такой массив Б
: [0,1,2,3,4]
.
Далее берём нашу перестановку, и говорим по какому индексу находится первый её элемент? 4
находится по индексу 4
, так и записываем в массив Ц
. Удаляем из массива Б
и массива А
число 4
.
А = [1,2,3,0]. Б = [0,1,2,3]. Ц = [4].
Берём следующее число из А
: 1
. По какому индексу находится? 1
. Так и записываем, удаляем из Б
и А
эти элементы.
А = [2,3,0]. Б = [0,2,3]. Ц = [4,1].
И теперь начинается самое интересное. Берём следующее число из А
: 2
. Оно находится по индексу 1
. Так и записываем, и удаляем из А
и Б
.
А = [3,0]. Б = [0,3]. Ц = [4,1,1].
Ну и таким образом у нас в итоге получится: А = []. Б = []. Ц = [4,1,1,1,0]
.
Что интересного в массиве Ц
? У него в каждом следующем элементе максимальное возможное число уменьшается на 1
. То есть максимальный Ц = [4,3,2,1,0]
возможен для перестановки: [4,3,2,1,0]
. А Ц = [0,0,0,0,0]
получается для перестановки [0,1,2,3,4]
.
Получается в Ц
у нас хранятся цифры с необычной системой счисления, разной для каждого разряда. Ну и далее можно использовать Ц
чтобы получить номер перестановки:
0*0! + 1*1! + 1*2! + 1*3! + 4*4! = 105.
Получается это число находится в промежутке от 0
до N!-1
. Вот так мы и пронумеровали каждую перестановку.
Кстати несложно модифицировать алгоритм, чтобы обрабатывать перестановки с повторяющимися элементами.
Говорят что я переизобрёл факториальную Систему Счисления.