Пошук під маршовими квадратами


9

Marching Squares - алгоритм з комп'ютерної графіки, який використовується для відновлення 2D ізоконт з сітки зразків (див. Також його старший брат Marching Cubes для 3D-налаштувань). Ідея полягає в тому, щоб обробити кожну клітинку сітки незалежно та визначити контури, що проходять через неї, на основі значень у її кутах.

Перший крок у цьому процесі - визначити, які краї з'єднані контурами, виходячи з того, чи кути вище або нижче значення контуру. Для простоти ми розглянемо лише контури вздовж значення 0, такі, що нас цікавить, чи кути позитивні чи негативні. Існують випадки, які можна розрізнити:24 = 16

введіть тут опис зображення
Джерело зображення: Вікіпедія

Ідентифікація білого та чорного тут насправді не має значення, але для певності скажіть, що білий колір є позитивним, а чорний - негативним. Ми будемо ігнорувати випадки, коли один із кутів точно 0.

Точки сідла (випадки 5 та 10) створюють трохи додаткових труднощів: не ясно, які діагоналі слід використовувати, лише дивлячись на кути. Це можна вирішити, знайшовши середнє значення чотирьох кутів (тобто наближення до центрального значення) та вибравши діагоналі такі, що контури відокремлюють центр від кутів із протилежним знаком. Якщо середнє значення точно 0, може бути обраний будь-який випадок.

Зазвичай ці 16 випадків просто зберігаються в таблиці пошуку. Це чудово для ефективності, але, звичайно, ми вважаємо за краще, щоб код тут був коротким . Отже, ваше завдання - виконати цей крок пошуку та надрукувати ASCII-представлення справи у якомога меншому коді.

Змагання

Значення чотирьох кутів (ненульових цілих чисел) вам задано у встановленому вами порядку. Потім слід генерувати правильне розташування контурів, правильно розв’язуючи випадки точки сідла.

Ви можете написати програму або функцію, взявши введення через STDIN (або найближчу альтернативу), аргумент командного рядка або аргумент функції та вивівши результат через STDOUT (або найближчу альтернативу), значення повернення функції або параметр функції (out).

Введення даних може здійснюватися у будь-якому зручному форматі рядка чи списку.

16 випадків будуть представлені в мистецтві ASCII, використовуючи один з наступних блоків 5x5:

o---o  o---o  o---o
|   |  |   |  | | |
|   |  |---|  | | |
|   |  |   |  | | |
o---o  o---o  o---o

o---o  o---o  o---o  o---o
|/  |  |  \|  |   |  |   |
|   |  |   |  |   |  |   |
|   |  |   |  |\  |  |  /|
o---o  o---o  o---o  o---o

o---o  o---o
|/  |  |  \|
|   |  |   |
|  /|  |\  |
o---o  o---o

Ви не повинні друкувати жодної провідної чи кінцевої пробілів, але ви можете надрукувати один додатковий новий рядок.

Це кодовий гольф, тому найкоротша відповідь (у байтах) виграє.

Випробування

У тестових випадках передбачається, що введення подається в порядку ліворуч , зверху праворуч , знизу вліво , знизу праворуч . Тестові приклади представлені в 9 групах, по одному відповідає кожному з 9 поданих вище подань (у тому ж порядку, починаючи з порожньої комірки, закінчуючи двома точками сідла).

[1, 2, 1, 3]
[-9, -2, -2, -7]

[4, 5, -1, -2]
[-1, -2, 3, 4]

[7, -7, 7, -7]
[-5, 5, -5, 5]

[1, -6, -4, -1]
[-2, 3, 3, 4]

[-1, 6, -4, -1]
[2, -3, 3, 4]   

[-1, -6, 4, -1]
[2, 3, -3, 4]

[-1, -6, -4, 1]
[2, 3, 3, -4]

[3, -8, -9, 2]
[-3, 8, 9, -2]

[8, -3, -2, 9]
[-8, 3, 2, -9]

Крім того, наступні тестові випадки можуть повернути будь-яку з точок сідла (на ваш вибір):

[1, -4, -2, 5]
[-1, 4, 2, -5]

Відповіді:


5

Рубі, 201 180 176

Це анонімна лямбда-функція, яку слід викликати так, як показано на прикладі невольфів.

Це не містить змінної s. У безгольовій версії складний вираз присвоюється sдля ясності перед його використанням. 4 байти зберігаються у гольф-версії, поставивши її в рядку. Єдина інша відмінність між версіями - це пробіл та коментарі.

Якщо прийнятно повернути висновок у вигляді масиву з п'яти рядків з п’яти символів, замість друку до stdout, можна зберегти ще один байт.

->a{p=t=0
4.times{|i|t+=a[i]*=a[3];p+=a[i]>>9&1<<i}
q=p==6&&t>0?19:'@AC@P*10'[p].ord
puts c='o---o',(0..2).map{|i|b=p*i==3?'|---|':'|   |';b[q%4]='|/|\|/'[q%4+(i&2)];q/=4;b},c}

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

Усі чотири елементи вхідного масиву множать на останній елемент. Це гарантує, що останній елемент є позитивним, і зменшує кількість випадків з 16 до 8. Елементи змінюються на 9 місць, так що всі додатні числа стають 0, а всі від’ємні числа стають -1 (принаймні в діапазоні введення наведені в тестових випадках.) Потім вони ANDed, 1<<array indexщоб дати 3-бітове двійкове число, що вказує на шаблон (насправді 4-бітний, але оскільки останній елемент завжди позитивний, 4-й біт завжди дорівнює нулю.)

Це число від 0..7 потім подається в таблицю пошуку (зітхання), щоб визначити, які символи кожного рядка не є пробілом. Саме на цьому етапі обробляються два різних дисплеї для справи сідла, альтернативно тому, що число в таблиці пошуку використовується, якщо загальна величина є позитивною (у питанні йдеться про те, щоб вважати "середнім", але як тільки ми зацікавлений у знаку, не має значення, якщо ми вважаємо його загалом.)

Сподіваємось, спосіб відображення результатів виходить із коментарів у коді.

unolfolf у тестовій програмі

f=->a{p=t=0
  4.times{|i|                      #for each number in the input
    t+=a[i]*=a[3];                   #multiply each number by a[3]; totalize the sum in t
    p+=a[i]>>9&1<<i                  #shift right to find if negative; AND with 1<<i to build index number for pattern 
  }                                #q is a 3-digit base 4 number indicating which character of each line is non-whitespace (if any). 
  q=p==6&&t>0?19:'@AC@P*10'[p].ord #It's encoded in the magic string, except for the case of saddles with a positive total, which is encoded by the number 19.
  s=(0..2).map{|i|                 #build an array of 3 strings, indexes 0..2
    b=p*i==3?'|---|':'|   |';        #IF p is 3 and we are on row 1, the string is |---| for the horizontal line case. ELSE it is |   |.
    b[q%4]='|/|\|/'[q%4+(i&2)];      #The numbers in q indicate which character is to be modified. The characters in the string indicate the character to replace with.
    q/=4;                            #If q%4=0, the initial | is replaced by | (no change.) i&2 shifts the string index appropriately for the last row.
    b                                #divide q by 4, and terminate the loop with the expression b so that this is the object loaded into array s.  
  }
puts c='o---o',s,c}                #print the array s, capped with "o---o" above and below.


[[1, 2, 1, 3],
[-9, -2, -2, -7],

[4, 5, -1, -2],
[-1, -2, 3, 4],

[7, -7, 7, -7],
[-5, 5, -5, 5],

[1, -6, -4, -1],
[-2, 3, 3, 4],

[-1, 6, -4, -1],
[2, -3, 3, 4],

[-1, -6, 4, -1],
[2, 3, -3, 4],

[-1, -6, -4, 1],
[2, 3, 3, -4],

[3, -8, -9, 2],
[-3, 8, 9, -2],

[8, -3, -2, 9],
[-8, 3, 2, -9],

[1, -4, -2, 5],
[-1, 4, 2, -5]].each{|k|f.call(k)}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.