As grades podem ser curvilíneas. Quanto tempo dura a sua?

12

Considere a possibilidade de representar uma curva bidimensional simples , aberta , em uma grade de texto com largura W de largura por H, onde Xrepresenta parte da curva e .representa o espaço vazio e nenhum outro caractere é usado.

Todo espaço de grade possui 8 espaços de grade vizinhos, seu bairro Moore . Espaços de grade além das bordas são considerados vazios.

Uma grade contém uma curva se tiver exatamente um X OU se tiver mais de um em Xque:

  • Exatamente dois Xs têm apenas um vizinho X. Estes são os pontos finais da curva.
  • Cada Xalém dos endpoints vizinhos exatamente dois Xs. Estes formam a maior parte da curva.

Por exemplo, esta grade em que W = 9 e H = 4 contém uma curva:

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

Da mesma forma, essas grades (W = 4, H = 3) têm curvas:

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

Essas grades, no entanto, não contêm uma curva:

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

Podemos encontrar o comprimento de uma curva somando as distâncias entre todos os pares vizinhos de Xs:

  • A distância entre dois Xs ortogonais vizinhos é de 1 unidade.

    XX
    X
    X
  • A distância entre dois Xs diagonalmente vizinhos é √2 unidades.

    X.
    .X
    .X
    X.

Por exemplo, o comprimento da curva na grade

XXX.
...X
..X.

pode ser visualizado como

exemplo de comprimento

então podemos ver que é 1 + 1 + √2 + √2 = 4.828427 ...

O comprimento de uma curva com apenas uma Xé zero.

Quando uma grade não forma uma curva, seu comprimento não está bem definido.

Desafio

Dada uma grade de texto de Xs e .s, imprima o comprimento da curva que ela contém, ou imprima algo como -1ou Nullpara indicar que a grade não tem curva.

Para entrada, você pode usar outros caracteres além de Xe .se desejar, e H e W podem ser considerados como entrada, se necessário. A entrada como uma lista ou matriz aninhada preenchida com 1s e 0s em vez de uma sequência também é boa.

Você pode emitir uma flutuação para o comprimento da curva ou, alternativamente, dois números inteiros A e B, onde length = A + B*√2.

O código mais curto em bytes vence.

Casos de teste

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
Passatempos de Calvin
fonte
Eu recomendo permitir que o solucionador escolha seu formato de saída para grades que não têm curvas (qualquer valor consistente que não seja da forma m + n * sqrt (2) para qualquer m, n≥0).
Greg Martin
@Greg Parece bom. Concluído
Calvin's Hobbies
[x.x,...,.x.]não é uma curva válida, certo?
Magic Octopus Urn
@carusocomputing correct
Calvin's Hobbies

Respostas:

3

MATL , 52 51 bytes

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

Entrada é uma matriz de zeros e uns.

Saída é B, então A. As não curvas dão um negativo A.

Experimente online! Ou verifique todos os casos de teste .

Explicação

A computação do comprimento da curva usa duas convoluções 2D 1 : uma com a máscara de Moore e outra com uma máscara que contém apenas os vizinhos diagonais. Os resultados são duas matrizes com o mesmo tamanho da entrada, que serão indicadas como M e D, respectivamente. M fornece o número total de vizinhos para cada ponto, enquanto D fornece o número de vizinhos na diagonal.

Os resultados em M e D devem ser filtrados para descartar pontos que não pertencem à curva. Além disso, eles devem ser divididos por 2, porque "ser vizinho de" é uma relação simétrica, de modo que cada ponto da curva é contado duas vezes.

Determinar se a curva é válida é mais complicado do que eu esperava. Para fazer isso, o código testa três condições:

  1. O número de unidades em M é igual 2? (Ou seja, existem exatamente dois pontos com um único vizinho?)
  2. A soma total de M é igual ao número de pontos na curva de entrada vezes 2menos 2? (Juntamente com a condição 1, isso testa se todos os valores diferentes de zero em M, exceto dois deles iguais 2)
  3. A curva de entrada contém um único ponto?

A curva é válida se as condições 1 e 2 forem verdadeiras ou se a condição 3 for.

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 Convolução é a chave do sucesso .

Luis Mendo
fonte
1

Python 3 , 316 315 311 bytes

Eu acho que isso cobre todos os casos; pelo menos os casos de teste funcionam.

Além disso, certamente ainda há muito para jogar golfe, provavelmente no começo, onde os casos extremos são tratados.

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

Experimente online!

Como funciona:

  1. d,R,C são 1. uma lista de listas com 1 como curva e 0 como plano de fundo, 2. contagem de linhas e colunas
  2. Insira uma linha de 0 antes e depois e uma coluna de 0 antes e depois dpara que não tenhamos que nos preocupar com a borda da matriz 2D
  3. Para cada 1 na matriz 2D, varra a vizinhança por 1 e adicione (1,0) a uma lista se a relação for diagonal; caso contrário, adicione (0,1)
  4. Soma todas as tuplas, para que (n, m) represente o número de vizinhos diagonais e não diagonais, respectivamente
  5. Verifique se o número de relações é exatamente o número de 1 menos um; se não, não é uma curva.

Agradecemos a @Helka Homba por apontar um caso ausente. Obrigado a @TuukkaX e @Trelzevir pelas dicas de golfe.

Nilo
fonte
Parece que d=[[1,0,1],[0,1,0],[1,0,1]]falhará aqui (adicionou caso de teste).
Calvin's Hobbies
@HelkaHomba Você está certo, eu supervisionei isso. Obrigado! Corrigido (agora infelizmente com mais bytes).
Nilo 14/03
1
s=sumsalva 4 bytes.
Trelzevir 14/03/19
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",_,]&

Leva uma matriz 2D, com 0s para .s e 1s por Xs. Saídas Nullpara não curvas.

1/.#~ComponentMeasurements~"PolygonalLength"&

O Mathematica possui 45 bytes incorporados para isso, mas gera alguns números para não curvas e 1 / sqrt (2) para entrada {{1}}. Corrigir esses custos 105 bytes (pode ser jogado no golfe?).

JungHwan Min
fonte