Desenhar meus contornos

25

Dada uma matriz retangular de elevações, desenhe seus contornos.

Tarefa

Dois elementos xe yestão no mesmo nível de contorno se floor(x/10) == floor(y/10). Por exemplo, 52e 58estão no mesmo nível de contorno, mas 58e 64não são.

O ato de desenhar contornos é definido da seguinte maneira: Para cada elemento e, substitua-o por uma sequência de dois caracteres escolhida da seguinte maneira:

  • o primeiro caractere é " "se o elemento abaixo eestiver no mesmo nível de contorno eou se não houver elemento no abaixo ee, "_"caso contrário,
  • o segundo caractere é " "se o elemento à direita de eestiver no mesmo nível de contorno eou se não houver nenhum elemento à direita ee de "|"outra forma

Os elementos nas linhas são unidos e, em seguida, as linhas são unidas com novas linhas.

Exemplo

Digamos que a entrada seja [[5,20],[3,6]]visualizada como

5 20
3 6

Primeiro olhamos 5. Como 3está no mesmo nível de contorno que 5, o primeiro caractere está " ". Como 20não está no mesmo nível de contorno que 5, o segundo caractere está "|".

Agora nós olhamos 20. Como 6não está no mesmo nível de contorno que 20, o primeiro caractere está "_". Como não há elemento à direita de 20, o segundo caractere é " ".

Agora nós olhamos 3. Como não há elemento abaixo 3, o primeiro caractere é " ". Como 6está no mesmo nível de contorno que 3, o segundo caractere está " ".

Agora nós olhamos 6. Como não há elemento abaixo 6, o primeiro caractere é " ". Como não há elemento à direita de 6, o segundo caractere é " ".

Com base nessas seqüências de dois caracteres, fazemos substituições para obter [[" |","_ "],[" "," "]]. Juntando isso, obtemos uma saída de

 |_ 
    

Regras

  • A matriz de entrada sempre será retangular e composta por números inteiros positivos.
  • Os espaços à direita ou novas linhas podem ter qualquer valor (incluindo 0) e não precisam ser consistentes de forma alguma.
  • Você não precisa seguir o mesmo algoritmo desde que produza os mesmos resultados.
  • Seu programa ou função pode gerar uma sequência separada por nova linha, lista de sequências ou equivalente.
  • Isso é , então o código mais curto em bytes vence.

Casos de teste

input
output

[[1,5,8,9],[3,11,13,8],[7,14,10,9],[4,8,7,6]]
  _ _  
 |   | 
 |_ _| 

[[0,10,20,30,40,50,60,70,80,90],[0,0,10,10,20,20,30,30,40,40],[0,0,0,10,10,10,20,20,20,30],[0,0,0,0,10,10,10,10,20,20],[0,0,0,0,0,10,10,10,10,10],[0,0,0,0,0,0,10,10,10,10],[0,0,0,0,0,0,0,10,10,10],[0,0,0,0,0,0,0,0,10,10],[0,0,0,0,0,0,0,0,0,10],[0,0,0,0,0,0,0,0,0,0]]
 |_|_|_|_|_|_|_|_|_
   |_  |_ _|_ _|_ _
     |_    |_ _  |_
       |_      |_ _
         |_        
           |_      
             |_    
               |_  
                 |_


[[5,5,5,5,5,5,5,5,5,5,5],[5,10,10,10,10,10,10,10,10,10,5],[5,10,15,15,15,15,15,15,15,10,5],[5,10,15,20,20,20,20,20,15,10,5],[5,10,15,20,25,25,25,20,15,10,5],[5,10,15,20,25,30,25,20,15,10,5],[5,10,15,20,25,25,25,20,15,10,5],[5,10,15,20,20,20,20,20,15,10,5],[5,10,15,15,15,15,15,15,15,10,5],[5,10,10,10,10,10,10,10,10,10,5],[5,5,5,5,5,5,5,5,5,5,5]]
  _ _ _ _ _ _ _ _ _  
 |                 | 
 |    _ _ _ _ _    | 
 |   |         |   | 
 |   |    _    |   | 
 |   |   |_|   |   | 
 |   |         |   | 
 |   |_ _ _ _ _|   | 
 |                 | 
 |_ _ _ _ _ _ _ _ _| 

[[35,32,29,26,25,25,25,26,29,32,35],[32,28,25,22,20,20,20,22,25,28,32],[29,25,21,18,15,15,15,18,21,25,29],[26,22,18,14,11,10,11,14,18,22,26],[25,20,15,11,7,5,7,11,15,20,25],[25,20,15,10,5,0,5,10,15,20,25],[25,20,15,11,7,5,7,11,15,20,25],[26,22,18,14,11,10,11,14,18,22,26],[29,25,21,18,15,15,15,18,21,25,29],[32,28,25,22,20,20,20,22,25,28,32],[35,32,29,26,25,25,25,26,29,32,35]]
  _|             |_  
_|    _ _ _ _ _    |_
    _|         |_    
   |    _ _ _    |   
   |   |     |   |   
   |   |     |   |   
   |   |_ _ _|   |   
   |_           _|   
_    |_ _ _ _ _|    _
 |_               _| 
   |             |  
fireflame241
fonte
1
Eu nem comecei a ler isso antes de perceber o quão legal isso seria #
Christopher

Respostas:

6

Perl 6 , 135 bytes (131 caracteres)

{my$n="_";sub w{$^a.chop-$^b.chop??$n!!" "};my&q={|.[1..*],.tail};(($_ «[&w]».&q) ZZ~{$n="|";$_ «[&w]».map(*.&q)}()).map:{say |$_}}

Experimente online!

Ligeiramente não destruído:

{
    my $n = "_";
    sub w { $^a.chop - $^b.chop ?? $n !! " "};
    my &q = {|.[1..*],.tail};
    (
        ($_ «[&w]».&q)
        ZZ~
        {$n="|";$_ «[&w]».map(*.&q)}()
    ).map:{say |$_}
}

Explicação : Primeiro, definimos uma variável $n(linha 2) e uma função w(linha 3). Essa função retorna um espaço se seus dois argumentos estiverem na mesma "elevação" e o conteúdo da variável, $ncaso contrário. Em vez de dividir por 10 e por piso, abusamos do fato de que ints são Cool(podem ser tratadas como seqüências de caracteres) e usadas choppara remover o último caractere (= dígito). Em seguida, subtraímos calmamente, forçando-os a numerar novamente: --).

Depois disso (linha 4), criamos uma função qque pega uma lista e retorna essa lista com o primeiro elemento removido e o último elemento duplicado.

Nas próximas 3 linhas, criaremos mais 2 matrizes a partir da matriz de entrada: a primeira tem a primeira linha ausente e a última linha duplicada (isso é apenas .&q- usando .&, você pode chamar uma função em qualquer coisa como se fosse um método - a coisa na frente do ponto é o primeiro argumento), o outro tem a primeira coluna ausente e a última coluna duplicada (isso é .map(*.&q)).

Primeiro (linha 4), pegamos a matriz original $_, "sobrepomos" com a matriz "linhas deslocadas" e usamos a função wcomo um operador binário (é isso [&w]) nos elementos correspondentes. Aquele coloca um _onde quer que os elementos correspondentes estejam nas diferentes elevações e outro. Portanto, obtemos ½ do resultado (apenas os "primeiros caracteres").

Na linha 6, fazemos o mesmo, mas primeiro mudamos $npara |e agora "sobrepomos" a matriz original com a matriz com colunas deslocadas. O resultado tem um |em diferentes e nas mesmas elevações. Estes são os "segundos caracteres".

Agora nós apenas os combinamos. Fechamos as matrizes com um zip com uma concat (sim ...), o que resulta em uma matriz da forma original, cujos elementos são os 2 elementos correspondentes das "meias soluções" concatenadas. Finalmente, apenas mapeamos essa matriz (que é realmente uma lista de listas). Cada uma dessas listas é achatada e, em seguida, sayedificada (impressa com uma nova linha). Como saypode receber qualquer número de argumentos e os imprime sem separadores, criando a nova linha apenas no final, obtemos a imagem desejada no stdout. (E o bloco retorna uma lista de Trues (cada sayum retorna um True), mas quem se importa.)

Ramillies
fonte
+1 parabut who cares
HyperNeutrino 15/17
5

Geléia ,  25 23  22 bytes

-1 byte graças a milhas ( Ivetoriza)

:⁵I;€0ao⁶
Zç”_Zż"ç”|$Y

Um programa completo imprimindo o resultado. Como um link monádico, ele pega uma lista de listas de números, as elevações e retorna uma lista de listas; no entanto, essas "linhas" consistem em listas de "pares" de dois caracteres - se isso estiver correto, é possível salvar 1 byte removendo Y.

Experimente online!

Quão?

:⁵I;€0ao⁶ - Link 1, assignCharacters (row-wise): list of lists of numbers; character, c
 ⁵        - literal 10
:         - integer division (vectorises)
  I       - incremental differences (vectorises) (zero if the same else non-zero)
     0    - literal 0
   ;€     - concatenate for €ach (rightmost edge of a row has no contour mark)
      a   - logical and (vectorises) with c (replace non-zeros with the contour character)
        ⁶ - literal space character
       o  - logical or (vectorises) (replace the zeros with spaces)

Zç”_Zż"ç”|$Y - Main link: list of lists of numbers, contours
Z            - transpose the input (get the columns)
  ”_         - literal underscore character, '_'
 ç           - call the last link (1) as a dyad with '_'
    Z        - transpose the result
          $  - last two links as a monad:
        ”|   -   literal pipe character, '|'
       ç     -   call the last link (1) as a dyad with '|'
      "      - zip with the dyadic operation:
     ż       -   zip (interleave the column-wise characters with the row-wise ones)
           Y - join with newlines
             - implicit print
Jonathan Allan
fonte
grr 3 bytes. +1 mas vou tentar outgolf você;)
HyperNeutrino
Solução independente - acabei de ver a sua é muito parecida! poupa-lhe um fora em linha reta ...
Jonathan Allan
Você pode salvar um byte usando cada um na junção no auxiliar em :⁵I;€0ao⁶vez de no link principalZç”_Zż"ç”|$Y
milhas
@miles Oh uau, isso funciona? Obrigado! Eu imaginei Ique não iria vectorizar assim.
Jonathan Allan
Sim, Ivetoriza na profundidade 1, e ambos ae ovetoriza na profundidade 0
milhas
3

Python 2 , 199 186 157 155 bytes

lambda a:(lambda x:'\n'.join(''.join('_ '[x==z]+'| '[x==y]for x,y,z in zip(r,r[1:]+r[-1:],q))for r,q in zip(x,x[1:]+x[-1:])))([[v/10for v in r]for r in a])

Experimente online!

Chas Brown
fonte
3

Gelatina , 24 bytes

:⁵IṠ;€0
ZÇZị⁾_ +³Ç¤ị⁾| ¤

Experimente online!

Explicação

:⁵IṠ;€0           Helper Link; get contour data
:                 Floor division by
 ⁵                10
  I               Compute increments
   Ṡ              Sign; ±1 for different values and 0 for same values
    ;             Append
      0           Zero
     €            To each row
ZÇZị⁾_ +³Ç¤ị⁾| ¤  Main Link
Z                 Zip the input (for vertical contours _)
 Ç                Get the contour data
  Z               Zip the data (because it's zipped from the first Z)
   ị              Index into the string
    ⁾_            "_ "
       +          Add (vectorizing twice) to
        ³ ¤    ¤  Nilad starting from (input)
         Ç        Get contour data (horizontal contours |)
           ị      Index into the string
            ⁾|    "| "

-2 bytes graças a Jonathan Allan

HyperNeutrino
fonte
Sua solução pode realmente acabar com o Y- ele retornará uma lista de listas de caracteres, que eu acredito que esteja OK (enquanto a minha possui pares dentro das "linhas").
Jonathan Allan
@JonathanAllan oh yeah verdade ... obrigado!
HyperNeutrino 15/09
2

Python 2 , 226 bytes

l=[[j/10for j in i]for i in input()]
for i,j in enumerate(l[:-1]):print''.join('_ '[h==l[i+1][g]]+'| '[h==j[g+1]]for g,h in enumerate(j[:-1]))+'_ '[j[-1]==l[i+1][-1]]
print''.join(' '+'| '[i==j]for i,j in zip(l[-1],l[-1][1:]))

Experimente online!

Uau, isso foi um delírio para descobrir a lógica. Agora vejo o Hyper Neutrino me ninja com uma resposta mais curta, mas gastei muito trabalho nisso para não publicá-la. : P

Além disso, posso apenas dizer, esta é uma maneira incrível de criar arte ASCII. Com licença enquanto eu faço um barco carregar mais desses.

totalmente humano
fonte
> Ninja'd: cara tem sido 45 minutos
HyperNeutrino
Sim, eu não olhei para as respostas ...: P
totallyhuman
Você pode salvar 4 bytes, definindo uma variável para, em enumeratevez de usar o nome completo duas vezes.
Jonathan Frech
218 bytes , removendo os primeiros enumerate(obs, eu tinha que remover algumas entradas para ser capaz de vinculá-lo aqui)
Felipe Nardi Batista
2

J, 58 bytes

f=.{~0==/@]
[:(,/"2)2 2((' _'f{."1),' |'f{.);.3 1:+<.@%&10

Experimente online!

Uma função anônima que pega uma matriz e gera os contornos.

Muito espaço para melhorias aqui. Como não tive tempo de experimentar todos os casos de teste, informe-me se houver algum problema. Vai tentar jogar mais e explicar mais tarde.

(Rápido) Explicação

Função auxiliar: indexa em uma cadeia de comprimento 2 com base em se o primeiro elemento de uma matriz de 2 comprimentos é igual ao segundo. Se for igual, indexa no elemento zeroth; se for desigual, indexa no primeiro. Uma matriz de 1 comprimento sempre indexa o elemento zeroth da string.

f=.{~0==/@]

Função principal

[:(,/"2)2 2((' _'f{."1),' |'f{.);.3 1:+<.@%&10

1:+<.@%&10 coloca cada elemento dividido por 10 e adiciona 1 (portanto, nunca obteremos 0 - isso é importante para a função auxiliar).

2 2((' _'f{."1),' |'f{.);.3corta a matriz em 2 x 2 segmentos, se puder (caso contrário, fornecerá um segmento 2 x 1, 1 x 2 ou 1 x 1 próximo às bordas) e aplica a função usada fpara comparar o elemento superior esquerdo ao topo direito e o elemento superior esquerdo no canto inferior esquerdo.

(,/"2)nivela o resultado na forma desejada. Eu realmente sinto que devo evitar usar isso (e muitas outras coisas, mas discordo).

Cole
fonte
2

JavaScript (ES6), 120 118 bytes

a=>a.map(b=>b.map(c=>c/10|0)).map((b,i,a)=>b.map((c,j)=>((a[i+1]||0)[j]-c?'_':' ')+(b[j+1]-c?'|':' ')).join``).join`\n`

Onde \nrepresenta o caractere literal de nova linha. Editar: salvou 2 bytes graças a @ Bálint.

f=
a=>a.map(b=>b.map(c=>c/10|0)).map((b,i,a)=>b.map((c,j)=>((a[i+1]||0)[j]-c?'_':' ')+(b[j+1]-c?'|':' ')).join``).join`
`
;[
[[5,20],[3,6]]
,
[[1,5,8,9],[3,11,13,8],[7,14,10,9],[4,8,7,6]]
,
[[0,10,20,30,40,50,60,70,80,90],[0,0,10,10,20,20,30,30,40,40],[0,0,0,10,10,10,20,20,20,30],[0,0,0,0,10,10,10,10,20,20],[0,0,0,0,0,10,10,10,10,10],[0,0,0,0,0,0,10,10,10,10],[0,0,0,0,0,0,0,10,10,10],[0,0,0,0,0,0,0,0,10,10],[0,0,0,0,0,0,0,0,0,10],[0,0,0,0,0,0,0,0,0,0]]
,
[[5,5,5,5,5,5,5,5,5,5,5],[5,10,10,10,10,10,10,10,10,10,5],[5,10,15,15,15,15,15,15,15,10,5],[5,10,15,20,20,20,20,20,15,10,5],[5,10,15,20,25,25,25,20,15,10,5],[5,10,15,20,25,30,25,20,15,10,5],[5,10,15,20,25,25,25,20,15,10,5],[5,10,15,20,20,20,20,20,15,10,5],[5,10,15,15,15,15,15,15,15,10,5],[5,10,10,10,10,10,10,10,10,10,5],[5,5,5,5,5,5,5,5,5,5,5]]
,
[[35,32,29,26,25,25,25,26,29,32,35],[32,28,25,22,20,20,20,22,25,28,32],[29,25,21,18,15,15,15,18,21,25,29],[26,22,18,14,11,10,11,14,18,22,26],[25,20,15,11,7,5,7,11,15,20,25],[25,20,15,10,5,0,5,10,15,20,25],[25,20,15,11,7,5,7,11,15,20,25],[26,22,18,14,11,10,11,14,18,22,26],[29,25,21,18,15,15,15,18,21,25,29],[32,28,25,22,20,20,20,22,25,28,32],[35,32,29,26,25,25,25,26,29,32,35]]
].forEach(a=>document.write(['<pre>','</pre>'].join(f(a))));

Neil
fonte
Você pode transformar as (a[i] || [])[j]construções em(a[i] || 0)[j]
Bálint
Além disso, no último join`\n`você pode remover a \npeça e substituí-la por uma nova linha real
Bálint
114 bytes:a=>a.map(b=>b.map(c=>c/10|0)).map((b,i,a)=>b.map((c,j)=>" _"[(a[i+1]||0)[j]-c&1]+" |"[b[j+1]-c&1]).join``).join`<new line here>`
Bálint 15/09
@ Bálint Bah, continuo esquecendo de fazer essa \nparte; Eu testo em um REPL para que novas linhas literais atrapalhem.
Neil
@ Bálint Mas sua última sugestão falha no exemplo original, que eu adicionei à lista de saídas.
Neil
1

Próton , 202 bytes

R=(L=len)+range
k=[map((//)&10,r)for r:eval(input())]
d=(x,y,X,Y)=>X>=L(k)or Y>=L(k[X])or k[x][y]==k[X][Y]
print('\n'.join(map(''.join,[['_ '[d(x,y,x+1,y)]+'| '[d(x,y,x,y+1)]for y:R(k[x])]for x:R(k)])))

Experimente online!

-2 bytes graças a Jonathan Frech
-15 bytes mudando para Proton em vez de Python 2

HyperNeutrino
fonte
Você pode salvar dois bytes, substituindo lencom Le definir L=len;.
Jonathan Frech
1

Java 8, 200 170 169 bytes

a->{String r="";for(int l=a.length,i=0,j;i<l;i++,r+="\n")for(j=0;j<l;r+=(i>l-2||a[i][j]/10==a[i+1][j]/10?" ":"_")+(j++>l-2||a[i][j-1]/10==a[i][j]/10?" ":"|"));return r;}

Explicação:

Experimente aqui.

Observe que a divisão inteira no Java é automaticamente pavimentada.

a->{                   // Method with 2D int-array as parameter and String return-type
  String r="";         //  Result-String
  for(int l=a.length,  //  Length of the input array
      i=0,j;           //  Index integers
      i<l;i++,         //  Loop (1) over the rows of the input array
          r+="\n")     //  and append a new-line to the result after every iteration
    for(j=0;j<l;       //   Inner loop (2) over the columns of a row
      r+=              //    Append the String with:
         (i>l-2        //      If it's the last row,
         ||a[i][j]/10==a[i+1][j]/10?
                       //      or the current and next rows are equal floored/10:
          " "          //       Use a space
         :             //      Else:
          "_")         //       Use a "_"
        +              //     Plus
         (j++>l-2      //      If it's the last column in the row,
         ||a[i][j-1]/10==a[i][j]/10?
                       //      or the current and next columns are equal floored/10:
          " "          //       Use a space
         :             //      Else:
          "|")         //       Use "|"
    );                 //   End of column loop (2)
                       //  End of row-loop (1) (implicit / single-line body)
  return r;            //  Return the result-String
}                      // End of method
Kevin Cruijssen
fonte
1

R, 159 bytes

f=function(m){M=m%/%10;a=cbind(0,t(apply(M,1,diff)));b=rbind(apply(M,2,diff),0);a[!!a]="|";b[!!b]="_";M[]=gsub("0"," ",paste0(a,b));write(t(M),"",ncol(m),,"")}

Com novas linhas e recuos:

f=function(m){
    M=m%/%10
    a=cbind(0,t(apply(M,1,diff))) #row-wise difference
    b=rbind(apply(M,2,diff),0) #column-wise difference
    a[!!a]="|"
    b[!!b]="_"
    M[]=gsub("0"," ",paste0(a,b)) # M[] is a trick to force the result to have the same structure as M
    write(t(M),"",ncol(m),,"")
    }

Faz a divisão de número inteiro da matriz, mede as diferenças de linha por linha e coluna-sábio, e quando não nula substitua por |e_ respectivamente, cola as duas (indolor, graças à vetorização de R) e as saídas.

Casos de teste:

> m=matrix(c(0,10,20,30,40,50,60,70,80,90,0,0,10,10,20,20,30,30,40,40,0,0,0,10,10,10,20,20,20,30,0,0,0,0,10,10,10,10,20,20,0,0,0,0,0,10,10,10,10,10,0,0,0,0,0,0,10,10,10,10,0,0,0,0,0,0,0,10,10,10,0,0,0,0,0,0,0,0,10,10,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0),byrow=T,ncol=10)
> f(m)
  |_|_|_|_|_|_|_|_|_
    |_  |_ _|_ _|_ _
      |_    |_ _  |_
        |_      |_ _
          |_        
            |_      
              |_    
                |_  
                  |_

> m=matrix(c(5,5,5,5,5,5,5,5,5,5,5,5,10,10,10,10,10,10,10,10,10,5,5,10,15,15,15,15,15,15,15,10,5,5,10,15,20,20,20,20,20,15,10,5,5,10,15,20,25,25,25,20,15,10,5,5,10,15,20,25,30,25,20,15,10,5,5,10,15,20,25,25,25,20,15,10,5,5,10,15,20,20,20,20,20,15,10,5,5,10,15,15,15,15,15,15,15,10,5,5,10,10,10,10,10,10,10,10,10,5,5,5,5,5,5,5,5,5,5,5,5),byrow=T,ncol=11)
> f(m)
   _ _ _ _ _ _ _ _ _  
  |                 | 
  |    _ _ _ _ _    | 
  |   |         |   | 
  |   |    _    |   | 
  |   |   |_|   |   | 
  |   |         |   | 
  |   |_ _ _ _ _|   | 
  |                 | 
  |_ _ _ _ _ _ _ _ _| 
plannapus
fonte
0

Perl 5 , 130 126 bytes

124 bytes de código + 2 para -apsinalizadores

push@a,[map 0|$_/10,@F]}{map{say map{($a[$r+1][$c]-$_&&$r<$#a?'_':$").($a[$r][++$c]-$_&&$c<@{$a[0]}?'|':$")}@$_;$c=0;$r++}@a

Experimente online!

O formato de entrada é a grade 2-D de números separados por espaço.

Explicação

Isso é de uma iteração anterior do código.

push@a,[map 0|$_/10,@F]     # read the input, divide it by 10, and store it in a 2-D array
}{                          # end the implicit while loop and start the final block
map{                        # repeat this for each line
  $_=($a[$r+1][$c]-$_&&$r<$#a?'_':$")       # set appropriate characters to output based
     .($a[$r][++$c]-$_&&$c<@{$a[0]}?'|':$") # on the given rules
  for@$_;                                   # repeat for each number on the line
  $c=0;$r++;                         # setup row and column counters for next iteration
  say@$_                             # output this line
}@a
Xcali
fonte