Карта кота Арнольда


21

Виклик

Давши кольорове растрове зображення * з однаковою шириною та висотою, виведіть зображення, трансформоване під мапу кота Арнольда . (* деталі див. нижче)

Визначення

Враховуючи розмір зображення, Nми припускаємо, що координати пікселя задаються як числа між 0іN-1 .

Карта кота Арнольда визначається наступним чином:

Піксель за координатами [x,y]переміщений до [(2*x + y) mod N, (x + y) mod N].

Це не що інше, як лінійне перетворення на торі: жовта, фіолетова та зелена частина повертаються на початковий квадрат за рахунок mod N.

візуалізація

Ця карта (назвемо її f) має такі властивості:

  • Це бієктивне , що означає оборотне: це лінійне перетворення з матрицею [[2,1],[1,1]]. Оскільки він має детермінант 1і має лише цілі записи, обернений також має лише цілі записи і задається [[1,-1],[-1,2]], це означає, що він є бієктивним і для цілих координат.

  • Це крутний елемент групи бієктивних карт N x Nзображень, це означає, що якщо застосувати його достатньо багато разів, ви отримаєте оригінальне зображення назад: f(f(...f(x)...)) = xкількість разів, яку карта, застосована до себе, призводить до ідентичності, гарантовано буде меншою або дорівнює 3*N. Далі ви можете побачити зображення кішки після заданої кількості ітераційних застосувань карти котів Арнольда та анімацію того, як виглядає повторна програма:

багаторазове повторне застосування

Деталі

  • Вашій програмі не обов'язково мати справу з зображеннями, але 2D-масиви / матриці, рядки або подібні 2D-структури теж прийнятні.

  • Не має значення, чи ваша (0,0)точка знаходиться внизу зліва або вгорі зліва. (Або в будь-якому іншому куточку, якщо це зручніше для вашої мови.) Будь ласка, вкажіть, яку умову ви використовуєте у своєму поданні.

Тестові шафи

У матричній формі ( [1,2,3,4]це верхній рядок, 1має індекс (0,0), 2має індекс (1,0), 5має індекс (0,1))

 1     2     3     4
 5     6     7     8
 9    10    11    12
13    14    15    16

maps to:

 1    14    11     8
12     5     2    15
 3    16     9     6
10     7     4    13

 --------------------

 1     2     3
 4     5     6
 7     8     9

 map to:

 1     8     6
 9     4     2
 5     3     7

Як зображення (зліва внизу (0,0)):


1
Бідна Лена. Я сподіваюся, що ви тривали ітерації досить довго
Луїс Мендо

2
Чи можемо ми взяти розмір зображення як вхідний? Це завжди квадрат?
xnor

1
Так, зображення завжди квадратне, і я не впевнений у розмірі, чи є щось проти цього дозволити?
невдача

Відповіді:



7

MATL , 23 байти

tt&n:qt&+&y\tb+&y\b*+Q(

Справа (0,0)вліво зліва, як у прикладах у тексті виклику.

Спробуйте в Інтернеті!

Пояснення

Матрицю в MATL можна індексувати одним індексом замість двох. Це називається лінійним індексуванням і використовує основний стовпець . Це проілюстровано наступною матрицею 4 × 4, у якій значення кожного запису збігається з його лінійним індексом:

1   5   9  13
2   6  10  14
3   7  11  15
4   8  12  16

Існує два подібних підходи для впровадження карти в завдання:

  1. Побудуйте матрицю індексації, яка представляє зворотне відображення Арнольда на лінійних індексах, і використовуйте її для вибору значень з вихідної матриці. Для випадку 4 × 4 матриця індексації була б

     1  8 11 14
    15  2  5 12
     9 16  3  6
     7 10 13  4
    

    говорячи, що, наприклад, оригінал 5при x = 2, y = 1 переходить до x = 3, y = 2. Ця операція називається опорною індексацією : використовуйте матрицю індексації, щоб вказати, який елемент вибрати з вихідної матриці. Це функтон ), який займає два входи (у його конфігурації за замовчуванням).

  2. Побудуйте матрицю індексування, яка представляє пряме відображення Арнольда на лінійних індексах, і використовуйте її для запису значень у вихідну матрицю. Для випадку 4 × 4 матриця індексації була б

     1 10  3 12
     6 15  8 13
    11  4  9  2
    16  5 14  7
    

    говорячи про те, що запис x = 2, y = 1 нової матриці буде переписаний на запис з лінійним індексом 10, тобто x = 3, y = 2. Це називається індексацією присвоєння : використовуйте матрицю індексування, матрицю даних та оригінальну матрицю та записуйте дані на вихідну матрицю за вказаними індексами. Це функція (, яка займає три входи (у конфігурації за замовчуванням).

Спосіб 1 більш простий, але спосіб 2 виявився коротшим.

tt     % Take the input implicitly and push two more copies
&n     % Get its size as two (equal) numbers: N, N
:qt    % Push range [0  1 ... N-1] twice. This represents the original x values
&+     % Matrix of all pairwise additions. This represents x+y
&y     % Push a copy of N onto the top of the stack
\      % Modulo. This is the new y coordinate: y_new
t      % Push another copy
b+     % Bubble up the remaining copy of [0 1 ... N-1] and add. This is 2*x+y
&y     % Push a copy of N onto the top of the stack
\      % Modulo. This is the new x coordinate: x_new
b*+    % Bubble up the remaining copy of N, multiply, add. This computes
       % x_new*N+y_new, which is the linear index for those x_new, y_new 
Q      % Add 1, because MATL uses 1-based indexing
(      % Assigmnent indexing: write the values of the original matrix into
       % (another copy of) the original matrix at the entries given by the
       % indexing matrix. Implicitly display the result

5

Математика, 44 байти

(n=MapIndexed[RotateLeft[#,1-#2]&,#]&)@*n

Порт фантастичного алгоритму Лінна . У кодуванні UTF-8 є невидимий 3-байтний символ U + F3C7 до останнього] ; Mathematica відображає це як суперскрипт T, і він приймає транспозицію матриці.

Математика, 54 байти

Table[#2[[Mod[2x-y-1,#]+1,Mod[y-x,#]+1]],{x,#},{y,#}]&

Безіменна функція, що приймає два аргументи, додатне ціле число #та 2D масив #2розмірів #x #та повертає 2D масив подібної форми. Як і в даному тестовому випадку, точка з координатами {0,0} знаходиться в лівій верхній частині, а вісь x горизонтальна. Пряма реалізація за допомогою зворотного [[1,-1],[-1,2]]згаданого у питанні, з -1першою координатою для обліку того, що масиви за своєю суттю є 1-індексованими в Mathematica. Якщо нам не дозволяється сприймати розмір матриці як додатковий аргумент, то це рішення стає на дев'ять байтів довше (замініть перший #—не на #2—з a=Length@#і всі наступні #s на as).


Данг, побили мене до цього
JungHwan Min

3

Python 2, 89 82 77 73 байт

def f(a):exec'a=[l[-i:]+l[:-i]for i,l in enumerate(zip(*a))];'*2;return a

Введення - це список списків
Рядок всередині exec переносить список списків і циклічно обертає кожен список за рядковим індексом (на основі 0 - 3-й рядок повертається 2 рази праворуч).
Цей процес робиться 2 рази на вхід.

+4 байти, які виконають перетворення N разів

def f(a,n):exec'a=[l[-i:]+l[:-i]for i,l in enumerate(zip(*a))];'*2*n;return a

2

Хаскелл, 55 байт

m#n|r<-[0..n-1]=[[m!!mod(2*y-x)n!!mod(x-y)n|x<-r]|y<-r]

Приклад використання: [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]] # 4->[[1,14,11,8],[12,5,2,15],[3,16,9,6],[10,7,4,13]] .

0,0- верхній лівий кут. При цьому використовується зворотне перетворення.


1

Пітон, 69 байт

lambda M:eval("[r[-i:]+r[:-i]for i,r in enumerate(zip(*"*2+"M))]))]")

Вдосконалення методу транспортування та зсуву Рода в два рази . Застосовує операцію M -> [r[-i:]+r[:-i]for i,r in enumerate(zip(*M))]двічі, створюючи та оцінюючи рядок

[r[-i:]+r[:-i]for i,r in enumerate(zip(*[r[-i:]+r[:-i]for i,r in enumerate(zip(*M))]))]

Це вузько перемагає пряме перетворення (70 байт), припускаючи, що зображення є квадратним, а його довжина може сприйматися як вхідне:

lambda M,n:[[M[(2*j-i)%n][(i-j)%n]for i in range(n)]for j in range(n)]

1

ImageJ макрос, 29 байт

v=getPixel((x+y)%w,(2*y+x)%h)
  • Відкрите зображення Лени
  • У меню Процес виберіть Математика / Макрос ...

Це не виконує f ^ (- 1)? Він отримує значення пікселя за координатами, до яких, як передбачається, перемістити його. Ви, мабуть, маєте на увазі v=getPixel((2*y-x)%w,(x-y)%h).
Робін Кох

@RobinKoch Спасибі, 2*x+yзмінив2*y+x
rahnema1

Це ні те, що я написав, ні те, що я мав на увазі. Для вашого підходу вам потрібна зворотна трансформація. Для f(x,y) = (2x+y, x+y)цього обернене перетворення описано f^(-1) = (x-y, 2y-x). (Інший мій коментар був невірним.) Отже, ваш код повинен бути v=getPixel((x-y)%w,(2*y-x)%h).
Робін Кох

Я перевірив свою формулу, і результат такий же, як зображення Лени у запитанні
rahnema1

@RobinKoch Ви можете завантажити ImageJ і перевірити обидві формули
rahnema1

1

Ява, 160

Гольф:

int[][]f(int[][]m){int x=0,y,l=m.length,r[][]=new int[l][];for(;x<l;++x)r[x]=new int[l];for(x=0;x<l;++x)for(y=0;y<l;++y)r[(x+y)%l][(2*x+y)%l]=m[y][x];return r;}

Безголівки:

  int[][] f(int[][] m) {
    int x = 0, y, l = m.length, r[][] = new int[l][];
    for (; x < l; ++x) {
      r[x] = new int[l];
    }
    for (x = 0; x < l; ++x) {
      for (y = 0; y < l; ++y) {
        r[(x + y) % l][(2 * x + y) % l] = m[y][x];
      }
    }
    return r;
  }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.