Pi Natural # 2 - Rio

12

Objetivo

Dada uma corda com um conjunto de hashes, calcule seu comprimento total e divida pela distância do início ao fim.

Simulação

O que estamos simulando? De acordo com este artigo , a relação entre o comprimento de um rio e a distância entre o início e o fim é de aproximadamente Pi! (Isso pode ter sido contestado empiricamente, mas eu pude encontrar os dados e, para esse desafio, assumiremos que é verdade).

Como estamos simulando isso?

  • Pegue uma entrada de string de espaço em branco e hashes
  • Cada hash terá dois outros adjacentes
    • Com exceção do primeiro e último hash, que terão apenas 1
  • Cada personagem está em um ponto de treliça (x, y)
  • x é o índice do personagem em sua linha
    • por exemplo, cé o quarto caractere em0123c567
  • y é o número da linha do personagem
    • por exemplo, cestá na terceira linha:
      0line
      1line
      2line
      3c...
  • Soma as distâncias entre os hashes adjacentes, chame-o S
  • Pegue a distância entre o primeiro e o último hashes, chame-o D
  • Retorna S/D

insira a descrição da imagem aqui

Especificação

  • Entrada
    • Flexível, receba informações de qualquer uma das formas padrão (por exemplo, parâmetro de função, STDIN) e em qualquer formato padrão (por exemplo, String, Binário)
  • Resultado
    • Flexível, produza de qualquer forma padrão (por exemplo, devolução, impressão)
    • Espaço em branco, espaço em branco à direita e à esquerda é aceitável
    • Precisão, forneça pelo menos 4 casas decimais de precisão (ou seja 3.1416)
  • Pontuação
    • O código mais curto vence!

Casos de teste

Estas são as minhas aproximações dos rios. Minhas aproximações podem ser ruins ou essas podem ser uma amostra ruim da população do rio. Além disso, fiz esses cálculos manualmente; Eu poderia ter errado calculado.

Rio Amarelo

        ### ####           
       #   #    #          
       #       #          #
       #       #         # 
       #       #        #  
      #         #      #   
##   #          # #####    
  ##  #          #         
    ##                     
1.6519

Rio Nilo

         #     
         #     
          #    
           #   
           #   
          #    
         #     
        #      
        #  #   
        # # #  
         #  #  
            #  
          ##   
         #     
         #     
        #      
        #      
       #       
       #       
       #       
       #       
   #  #        
  # ##         
  #            
  #            
   #           
    #          
     #         
     #         
      #        
     #         
    #          
     #         
      #        
1.5498

Rio Mississippi

 ###            
#   #           
     #          
     #          
    #           
   #            
  #             
  #             
  #             
   #            
    #           
     #          
      #         
       #        
        #       
        #       
        #       
         #      
          #     
           #    
          #     
       ###      
      #         
       #        
      #         
     #          
    #           
    #           
    #           
    #           
     #          
      ##        
        #       
        #       
         ##     
           ##   
             ## 
               #
              # 
             #  
            #   
           #    
          #     
         #      
        #       
        #       
        #       
        #       
        #       
       #        
      #         
     #          
      #         
       #        
        ####    
            #   
             #  
1.5257

TL; DR

Esses desafios são simulações de algoritmos que exigem apenas a natureza e seu cérebro (e talvez alguns recursos reutilizáveis) para aproximar o Pi. Se você realmente precisa de Pi durante o apocalipse zumbi, esses métodos não gastam munição ! Existem nove desafios no total.

NonlinearFruit
fonte
3
Eles são chamados de hashes por conta própria. "Hashtag" é apenas o termo para uma tag embutida significada com#<tag>
FlipTack
1
Suponho que a distância deve ser calculada usando o teorema de Pitágoras. Isso está correto?
Loovjo
Além disso, podemos considerar a entrada como uma lista de linhas?
Loovjo 26/12/16
@Loovjo ^^ Pode ser, é geometria euclidiana, então, no entanto, você deseja calcular que está bom. ^ Sim, a entrada é flexível.
NonlinearFruit
1
@NonlinearFruit Thanks. Então provavelmente é que as versões ASCII não são sinuosas suficiente :)
Luis Mendo

Respostas:

6

MATL , 48 44 42 37 33 bytes

Poucos bytes salvos graças à idéia de rahnema1 (resposta de oitava) de recolher duas convoluções em uma

t5BQ4B&vX^Z+*ssGt3Y6Z+1=*&fdwdYy/

Isso leva a entrada como uma matriz binária, com ;como separador de linhas. 1corresponde ao de hash e 0para o espaço.

Experimente online! Ou verifique todos os casos de teste .

Aqui está um conversor de formato que recebe entradas como matrizes de caracteres 2D (novamente, com ;separador) e produz representações de seqüência de caracteres das matrizes binárias correspondentes.

Explicação

Isso foi divertido! O código usa três duas convoluções 2D, cada uma com uma finalidade diferente:

  1. Para detectar vizinhos verticais e horizontais, que contribuem com uma distância de 1, a máscara necessária seria

    0 1 0
    1 0 1
    0 1 0
    

    Mas queremos apenas que cada par de vizinhos seja detectado uma vez. Então pegamos metade da máscara (e a última linha de zeros pode ser removida):

    0 1 0
    1 0 0
    

    Da mesma forma, para detectar vizinhos diagonais, que contribuem com uma distância de sqrt(2), a máscara seria

    1 0 1
    0 0 0
    1 0 1
    

    mas pelo mesmo raciocínio acima, torna-se

    1 0 1
    0 0 0
    

    Se essa máscara for multiplicada sqrt(2)e adicionada à primeira, as duas convoluções poderão ser substituídas por uma convolução pela máscara combinada

    sqrt(2) 1  sqrt(2)
    1       0        0
    
  2. Os pontos inicial e final são, por definição, os pontos com apenas um vizinho. Para detectá-los, convolvemos com

    1 1 1
    1 0 1
    1 1 1
    

    e veja quais pontos dão 1como resultado.

Para produzir a máscara combinada do item 1, é mais baixo gerar seu quadrado e depois pegar a raiz quadrada. A máscara no item 2 é um literal predefinido.

t     % Take input matrix implicitly. Duplicate
5B    % 5 in binary: [1 0 1]
Q     % Add 1; [2 1 2]
4B    % 4 in binary: [1 0 0]
&v    % Concatenate vertically
X^    % Square root of each entry
Z+    % 2D convolution, maintaining size
*     % Multiply, to only keep results corresponding to 1 in the input
ss    % Sum of all matrix entries. This gives total distance
Gt    % Push input again. Duplicate
3Y6   % Predefined literal. This gives third mask
Z+    % 2D convolution, maintaining size
1=    % Values different than 1 are set to 0
*     % Multiply, to only keep results corresponding to 1 in the input
&f    % Push array of row indices and array of column indices of nonzeros
d     % Difference. This is the horizontal difference between start and end
wd    % Swap, difference. This is the vertical difference between start and end 
Yy    % Hypothenuse. This gives total distance in straight line
/     % Divide. Display implicitly
Luis Mendo
fonte
2
Algumas pessoas costumavam dizer que a convolução é a chave do sucesso !
flawr
4

Oitava, 99 bytes

@(a)sum((c=conv2(a,[s=[q=2^.5 1 q];1 0 1;s],'same').*a)(:))/2/{[x y]=find(c<2&c>0),pdist([x y])}{2}

quase o mesmo método que a resposta MATL, mas aqui o núcleo de convoluções é

1.41 ,  1  , 1.41
1    ,  0  , 1 
1.41 ,  1  , 1.41

isto sqrt(2) =1.41é para vizinhos diagonais e 1 para vizinhos diretos, portanto, quando somamos valores do resultado sobre o rio, obtemos o dobro da distância real.
versão não destruída :

a=logical([...
0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 
1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 1 1 1 1 0 0 0 0 
0 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 
0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ]);
sq = sqrt(2);
kernel = [...
    sq ,  1  , sq
    1  ,  0  , 1 
    sq ,  1  , sq];
%2D convolution
c=conv2(a,kernel,'same').*a;
#river length
river_length = sum(c (:))/2;
#find start and end points
[x y]=find(c<2&c>0);
# distance between start and end points
dis = pdist([x y]);
result = river_length/ dis 

Experimente (cole) no Octave Online

rahnema1
fonte
Sua idéia de agrupar os dois primeiros circunvoluções em um me salvou alguns bytes :)
Luis Mendo
{[x y]=find(c<2&c>0),pdist([x y])}{2}é tão inteligente !!!
flawr
uma boa notícia é que não temos restrições do MATLAB!
rahnema1
2
@flawr Concordou. Isso deve ir para as dicas de golfe da Octave !
Luis Mendo
@LuisMendo algumas entradas incluídas nas dicas
rahnema1
2

JavaScript (ES6), 178

Entrada como uma string com novas linhas na forma retangular : cada linha preenchida com espaços com o mesmo comprimento (como nos exemplos)

r=>r.replace(/#/g,(c,i)=>([d=r.search`
`,-d,++d,-d,++d,-d,1,-1].map((d,j)=>r[i+d]==c&&(--n,s+=j&2?1:Math.SQRT2),n=1),n||(v=w,w=i)),w=s=0)&&s/2/Math.hypot(v%--d-w%d,~(v/d)-~(w/d))

Menos golfe

r=>(
  r.replace(/#/g, // exec the following for each '#' in the string
    (c,i) => // c: current char (=#), i: current position
    ( // check in 8 directions
      // note: d starts as the offset to next row, prev x position
      // and is incremented up to offset to next row, succ x position
      // note 2: there are 2 diagonal offsets, then 2 orthogonal offsets
      //         then other 2 diagonal, then 2 more orthogonal
      [d=r.search`\n`,-d, ++d,-d, ++d,-d, 1,-1].map( // for each offset
        (d,j) => // d: current offset, j: array position (0 to 7)
        r[i+d] == c && // if find a '#' at current offset ...
          ( 
            --n, // decrement n to check for 2 neighbors or just 1
            s += j & 2 ? 1 : Math.SQRT2 // add the right distance to s
          ),
      n = 1), // n starts at 1, will be -1 if 2 neighbors found, else 0
      // if n==0 we have found a start or end position, record it in v and w
      n || (v=w, w=i)
   ),
  w=s=0), // init s and w, no need to init v
  // at the end 
  // d is the length of a line + 1
  // s is twice the total length of the river
  // v and w can be used to find the x,y position of start and end
  s/2/Math.hypot(v%--d-w%d,~(v/d)-~(w/d))
)

Teste

F=
r=>r.replace(/#/g,(c,i)=>([d=r.search`\n`,-d,++d,-d,++d,-d,1,-1].map((d,j)=>r[i+d]==c&&(--n,s+=j&2?1:Math.SQRT2),n=1),n||(v=w,w=i)),w=s=0)&&s/2/Math.hypot(v%--d-w%d,~(v/d)-~(w/d))

Yellow=`        ### ####           
       #   #    #          
       #       #          #
       #       #         # 
       #       #        #  
      #         #      #   
##   #          # #####    
  ##  #          #         
    ##                     `

Nile=`         #     
         #     
          #    
           #   
           #   
          #    
         #     
        #      
        #  #   
        # # #  
         #  #  
            #  
          ##   
         #     
         #     
        #      
        #      
       #       
       #       
       #       
       #       
   #  #        
  # ##         
  #            
  #            
   #           
    #          
     #         
     #         
      #        
     #         
    #          
     #         
      #        `

Missi=` ###            
#   #           
     #          
     #          
    #           
   #            
  #             
  #             
  #             
   #            
    #           
     #          
      #         
       #        
        #       
        #       
        #       
         #      
          #     
           #    
          #     
       ###      
      #         
       #        
      #         
     #          
    #           
    #           
    #           
    #           
     #          
      ##        
        #       
        #       
         ##     
           ##   
             ## 
               #
              # 
             #  
            #   
           #    
          #     
         #      
        #       
        #       
        #       
        #       
        #       
       #        
      #         
     #          
      #         
       #        
        ####    
            #   
             #  `
console.log('Yellow River',F(Yellow))
console.log('Nile River',F(Nile))
console.log('Mississippi River',F(Missi))

edc65
fonte