Búsqueda de cuadrados de marcha

9

Marching Squares es un algoritmo de gráficos de computadora, que se utiliza para recuperar isocontornos 2D de una cuadrícula de muestras (ver también, su hermano mayor Marching Cubes para configuraciones 3D). La idea es procesar cada celda de la cuadrícula de forma independiente y determinar los contornos que pasan por esa celda en función de los valores en sus esquinas.

El primer paso en este proceso es determinar qué bordes están conectados por contornos, en función de si las esquinas están por encima o por debajo del valor del contorno. Para simplificar, solo consideraremos los contornos a lo largo del valor 0, de modo que nos interese saber si las esquinas son positivas o negativas. Hay casos para distinguir:24 = 16

ingrese la descripción de la imagen aquí
Fuente de la imagen: Wikipedia

La identificación del blanco y el negro realmente no importa aquí, pero para ser claros, digamos que el blanco es positivo y el negro es negativo. Ignoraremos los casos en que una de las esquinas es exactamente 0.

Los puntos de silla (casos 5 y 10) proporcionan un poco de dificultad adicional: no está claro qué diagonales se deben usar solo mirando las esquinas. Esto se puede resolver encontrando el promedio de las cuatro esquinas (es decir, una aproximación del valor del centro) y eligiendo las diagonales de manera que los contornos separen el centro de las esquinas con el signo opuesto. Si el promedio es exactamente 0, se puede elegir cualquier caso.

Normalmente, estos 16 casos simplemente se almacenan en una tabla de búsqueda. Esto es excelente para la eficiencia, pero, por supuesto, preferiríamos que el código sea corto por aquí. Por lo tanto, su tarea es realizar este paso de búsqueda e imprimir una representación ASCII del caso en el menor código posible.

El reto

Te dan los valores de las cuatro esquinas (enteros distintos de cero) en un orden fijo de tu elección. Luego debe generar el diseño correcto de los contornos, resolviendo correctamente los casos de punto de silla de montar.

Puede escribir un programa o función, tomando la entrada a través de STDIN (o la alternativa más cercana), argumento de línea de comando o argumento de función y generando el resultado a través de STDOUT (o la alternativa más cercana), el valor de retorno de la función o el parámetro de función (out).

La entrada puede tomarse en cualquier cadena conveniente o formato de lista.

Los 16 casos se representarán en el arte ASCII utilizando uno de los siguientes bloques 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

No debe imprimir ningún espacio en blanco inicial o final, pero puede imprimir una nueva línea opcional.

Este es el código de golf, por lo que gana la respuesta más corta (en bytes).

Casos de prueba

Los casos de prueba suponen que la entrada se da en orden superior izquierda , superior derecha , inferior izquierda , inferior derecha . Los casos de prueba se presentan en 9 grupos, uno correspondiente a cada una de las 9 representaciones dadas anteriormente (en el mismo orden, comenzando desde la celda vacía, terminando con los dos puntos de silla).

[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]

Además, los siguientes casos de prueba pueden devolver cualquiera de los puntos de silla (su elección):

[1, -4, -2, 5]
[-1, 4, 2, -5]
Martin Ender
fuente

Respuestas:

4

Rubí, 201 180 176

Esta es una función lambda anónima, que se llamará de la manera que se muestra en el ejemplo no reflejado.

Esto no contiene ninguna variable s. En la versión sin golf, se asigna una expresión compleja spara mayor claridad, antes de usarla. 4 bytes se guardan en la versión de golf poniéndolo en línea. La única otra diferencia entre las versiones es el espacio en blanco y los comentarios.

Si es aceptable devolver el resultado como una matriz de cinco cadenas de cinco caracteres, en lugar de imprimir en stdout, se puede guardar un byte más.

->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}

Estoy contento con el análisis de la matriz, pero creo que puede haber formas más cortas de formar la salida.

Los cuatro elementos de la matriz de entrada se multiplican por el último elemento. Esto garantiza que el último elemento sea positivo y reduce el número de casos de 16 a 8. Los elementos se desplazan a la derecha 9 lugares, de modo que todos los números positivos se vuelven 0 y todos los números negativos se vuelven -1 (al menos en el rango de entrada dado en los casos de prueba.) Luego son AND 1<<array indexpara dar un número binario de 3 bits que indica el patrón (en realidad 4 bits, pero como el último elemento siempre es positivo, el 4to bit siempre es cero).

Este número de 0..7 se alimenta a una tabla de búsqueda (suspiro) para determinar qué caracteres de cada fila no son espacios en blanco. Es en esta etapa que se manejan las dos pantallas diferentes para el caso de la silla de montar, con una alternativa al número en la tabla de búsqueda que se utiliza si el total es positivo (la pregunta dice considerar el "promedio", pero como solo somos interesado en el letrero, no importa si consideramos el total).

Se espera que la forma en que funciona la visualización de la salida sea clara a partir de los comentarios en el código.

sin golf en el programa de prueba

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)}
Level River St
fuente