Las rejillas pueden ser curvas. ¿Cuánto dura el tuyo?

12

Considere la posibilidad de representar una curva bidimensional simple , abierta en una cuadrícula de texto de ancho W por alto H donde Xrepresenta parte de la curva y .representa el espacio vacío y no se utilizan otros caracteres.

Cada espacio de cuadrícula tiene 8 espacios de cuadrícula vecinos, su vecindario Moore . Los espacios de cuadrícula más allá de los bordes se consideran vacíos.

Una cuadrícula contiene una curva si tiene exactamente una X O si tiene más de una Xdonde:

  • Exactamente dos Xs tienen solo un vecino X. Estos son los puntos finales de la curva.
  • Todos, Xademás de los puntos finales vecinos, exactamente dos Xs. Estos forman la mayor parte de la curva.

Por ejemplo, esta cuadrícula donde W = 9 y H = 4 contiene una curva:

....X....
.X.X.X.X.
X..X..X.X
.XX.....X

Del mismo modo, estas cuadrículas (W = 4, H = 3) tienen curvas:

....  .X..  ....  ....  .X.X
....  X..X  ..X.  XX..  X.X.
..X.  .XX.  .X..  ....  ....

Sin embargo, estas cuadrículas no contienen una curva:

....  .XX.  ...X  XX..  ....  X.X.
....  X..X  ..XX  XX..  .X.X  .X..
....  .XX.  .X..  ....  ...X  X.X.

Podemos encontrar la longitud de una curva sumando las distancias entre todos los pares vecinos de Xs:

  • La distancia entre dos Xs adyacentes ortogonalmente es 1 unidad.

    XX
    X
    X
  • La distancia entre dos Xs adyacentes en diagonal es √2 unidades.

    X.
    .X
    .X
    X.

Por ejemplo, la longitud de la curva en la cuadrícula

XXX.
...X
..X.

se puede visualizar como

ejemplo de longitud

entonces podemos ver que es 1 + 1 + √2 + √2 = 4.828427 ...

La longitud de una curva con solo uno Xes cero.

Cuando una cuadrícula no forma una curva, su longitud no está bien definida.

Desafío

Dada una cuadrícula de texto de Xsys ., muestre la longitud de la curva que contiene, o bien, muestre algo como -1o Nullpara indicar que la cuadrícula no tiene curva.

Para la entrada, puede usar otros caracteres que Xy .si lo desea, y H y W pueden tomarse como entrada si es necesario. La entrada como una lista anidada o matriz llena de 1s y 0s en lugar de una cadena también está bien.

Puede generar un flotante para la longitud de la curva o, alternativamente, dos enteros A y B donde length = A + B*√2.

El código más corto en bytes gana.

Casos de prueba

XXX.
...X
..X.
2 + 2*√2 = 4.828427...

....X....
.X.X.X.X.
X..X..X.X
.XX.....X
3 + 8*√2 = 14.313708...

....
....
..X.
0 + 0*√2 = 0

.X..
X..X
.XX.
1 + 3*√2 = 5.242640...

....
..X.
.X..
0 + 1*√2 = 1.414213...

....
XX..
....
1 + 0*√2 = 1

.X.X
X.X.
....
0 + 3*√2 = 4.242640...

....
....
....
....
-1

.XX.
X..X
.XX.
-1

...X
..XX
.X..
-1

....
.X.X
...X
-1

X.X.
.X..
X.X.
-1
Pasatiempos de Calvin
fuente
Recomiendo permitir que el solucionador elija su formato de salida para las cuadrículas que no tienen curvas (cualquier valor consistente que no sea de la forma m + n * sqrt (2) para cualquier m, n≥0).
Greg Martin
@ Greg Suena bien. Hecho
Hobbies de Calvin
[x.x,...,.x.]No es una curva válida, ¿verdad?
Magic Octopus Urn
@carusocomputing correcto
Hobbies de Calvin

Respuestas:

3

MATL , 52 51 bytes

t2Y6~Z+*ssGt3Y6Z+*tt1=z2=wssGzqE=*Gz1=+?}_q]ssy-h2/

La entrada es una matriz de ceros y unos.

La salida es B, entonces A. Las no curvas dan un negativo A.

Pruébalo en línea! O verificar todos los casos de prueba .

Explicación

Para calcular la longitud de la curva se utilizan dos circunvoluciones 2D 1 : una con la máscara de Moore y otra con una máscara que contiene solo los vecinos diagonales. Los resultados son dos matrices con el mismo tamaño de la entrada, que se denotarán como M y D, respectivamente. M da el número total de vecinos para cada punto, mientras que D da el número de vecinos diagonales.

Los resultados en M y D se deben filtrar para descartar puntos que no pertenecen a la curva. Además, deben dividirse entre 2, porque "ser vecino de" es una relación simétrica, por lo que cada punto de la curva se cuenta dos veces.

Determinar si la curva es válida es más engorroso de lo que esperaba. Para hacer esto, el código prueba tres condiciones:

  1. ¿El número de unos en M es igual 2? (Es decir, ¿hay exactamente dos puntos con un solo vecino?)
  2. ¿La suma total de M es igual al número de puntos en la curva de entrada por 2menos 2? (Junto con la condición 1, esto prueba si todos los valores distintos de cero en M excepto dos de ellos son iguales 2)
  3. ¿La curva de entrada contiene un solo punto?

La curva es válida si las condiciones 1 y 2 son verdaderas, o si la condición 3 lo es.

t       % Implicit input matrix of zeros and ones. Duplicate
2Y6~    % Push [1 0 1; 0 0 0; 1 0 1]
Z+      % 2D convolution, keeping size
*       % Multiply to zero out results for non-curve points. Gives matrix D
ss      % Sum of matrix D
Gt      % Push input again wtice
3Y6     % Push [1 1 1; 1 0 1; 1 1 1]
Z+      % 2D convolution, keeping size
*       % Multiply to zero out results for non-curve points. Gives matrix M
tt      % Duplicate twice
1=z     % Number of ones
2=      % Does it equal 2? This is condition 1
wss     % Swap. Sum of matrix
G       % Push input again
zqE     % Number of nonzeros values minus 1, and then multiplied by 2
=       % Are they equal? This is condition 2
*       % Multiply. This is a logical AND of conditions 1 and 2
G       % Push input again
z1=     % Does it contain exactly one nonzero value? This is condition 3
+       % Add. This is a logical OR with condition 3
?}      % If result was false
  _q    %   Negate and subtract 1. This makes sure we get a negative value
]       % End
ss      % Sum of matrix M
y       % Duplicate sum of matrix D from below
-       % Subtract
h       % Concatenate horizontally
2/      % Divide by 2. Implicitly display

1 La convolución es la clave del éxito .

Luis Mendo
fuente
1

Python 3 , 316 315 311 bytes

Creo que esto cubre todos los casos; al menos los casos de prueba funcionan.

Además, seguramente todavía hay mucho para jugar golf, probablemente al principio donde se manejan los casos extremos.

def f(d,R,C):
 s=sum;d=[0]*(C+2),*[[0,*r,0]for r in d],[0]*(C+2);o=-1,0,1;k=[[[(1,0),(0,1)][i*j]for i in o for j in o if d[r+i][c+j]and i|j]for c in range(1,-~C)for r in range(1,-~R)if d[r][c]];w=[x/2for x in map(s,zip(*s(k,[])))]or[0,0];print([w,-1][s(w)!=s([s(z)for z in d])-1or[len(t)for t in k].count(1)>2])

Pruébalo en línea!

Cómo funciona:

  1. d,R,C son 1. una lista de listas con 1 como curva y 0 como fondo, 2. recuento de filas y columnas
  2. Inserte una fila de 0 antes y después y una columna de 0 antes y después dpara que no tengamos que preocuparnos por el borde de la matriz 2d
  3. Por cada 1 en la matriz 2d, escanee el vecindario en busca de 1 y agregue (1,0) a una lista si la relación es diagonal, de lo contrario agregue (0,1)
  4. Suma todas las tuplas, de modo que (n, m) represente el número de vecinos diagonales y no diagonales, respectivamente
  5. Compruebe si el número de relaciones es exactamente el número de 1 menos uno; si no, no es una curva.

Gracias a @Helka Homba por señalar un caso perdido. Gracias a @TuukkaX y @Trelzevir por los consejos de golf.

Nilo
fuente
Parece d=[[1,0,1],[0,1,0],[1,0,1]]que fallará aquí (caso de prueba agregado).
Hobbies de Calvin
@HelkaHomba Tienes razón, lo supervisé. ¡Gracias! Lo solucionó (ahora desafortunadamente con más bytes).
nilo
1
s=sumahorra 4 bytes.
Trelzevir
0

Mathematica, 153 150 bytes

Switch[Sort[Join@@BlockMap[If[#[[2,2]]<1,Nothing,Tr[Tr/@#]]&,#~ArrayPad~1,{3,3},1]],{1},0,{2,2,3...},1/.#~ComponentMeasurements~"PolygonalLength",_,]&

Toma una matriz 2D, con 0s para .sy 1s para Xs. Salidas Nullpara no curvas.

1/.#~ComponentMeasurements~"PolygonalLength"&

Mathematica tiene una función de 45 bytes incorporada para esto, pero genera algunos números para no curvas y 1 / sqrt (2) para entrada {{1}}. Corregir estos costos de 105 bytes (¿podría jugar golf?).

JungHwan Min
fuente