Поиск марширующих площадей


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]

Ответы:


4

Рубин, 201 180 176

Это анонимная лямбда-функция, которая вызывается так, как показано в примере без заглядывания.

Это не содержит переменных s. В разглаженной версии сложное выражение назначено sдля ясности, прежде чем оно будет использовано. 4 байта сохраняются в версии для гольфа, помещая ее в строку. Единственное другое различие между версиями - это пробел и комментарии.

Если допустимо возвращать вывод в виде массива из пяти строк по пять символов, вместо печати в стандартный вывод, можно сохранить еще один байт.

->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 (по крайней мере, в диапазоне ввода в тестовых примерах.) Затем они приводятся к AND, 1<<array indexчтобы дать 3-битное двоичное число, обозначающее шаблон (фактически 4-битное, но поскольку последний элемент всегда положителен, 4-й бит всегда равен нулю).

Затем это число из 0..7 подается в таблицу поиска (вздох), чтобы определить, какие символы в каждой строке не являются пробелами. Именно на этом этапе обрабатываются два разных отображения для случая седла, при этом используется альтернатива номеру в таблице поиска, если итоговое значение положительно (вопрос говорит о том, чтобы считать «средним», но поскольку мы только заинтересованы в знаке, не имеет значения, если мы рассмотрим итоговое значение.)

Надеемся, что способ отображения вывода понятен из комментариев в коде.

разряженный в тестовой программе

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.