Descasque a batata

20

Esta é uma batata:

  @@
 @@@@
@@@@@@
@@@@@@
 @@@@
  @@

De maneira mais geral, uma batata tamanho N é definida como a seguinte forma:

Se N for par, são 2 @símbolos centralizados , seguidos por 4 @símbolos centralizados , seguidos por 6 @símbolos centralizados , até N @símbolos centrais ; então, N @símbolos centralizados , seguidos por N-2 @símbolos centrais , até 2.
Se N for ímpar, uma batata tamanho N é gerada da mesma maneira como descrito acima, mas começamos com 1 @símbolo, em vez de 2 .

Uma batata é descascada começando no canto superior direito e removendo um @sinal a cada etapa, seguindo no sentido anti-horário. Por exemplo, descascar uma batata tamanho 3 é assim:

 @
@@@
@@@
 @

​
@@@
@@@
 @

 ​
 @@
@@@
 @

  ​
 @@
 @@
 @

 ​
 @@
 @@
 ​

 ​
 @@
 @
 ​

​
 @
 @
 ​

 ​
​
 @
 ​


Desafio

Escreva um programa que, com uma entrada inteira, exiba todas as etapas para descascar uma batata desse tamanho.
Espaços em branco / novas linhas à direita são permitidos.

Pontuação

Isso é ; o código mais curto em bytes vence.


Casos de teste de amostra

N = 2

@@
@@

@
@@


@@


 @



N = 7

   @   
  @@@  
 @@@@@ 
@@@@@@@
@@@@@@@
 @@@@@ 
  @@@  
   @   


  @@@  
 @@@@@ 
@@@@@@@
@@@@@@@
 @@@@@ 
  @@@  
   @   


   @@  
 @@@@@ 
@@@@@@@
@@@@@@@
 @@@@@ 
  @@@  
   @   


   @@  
  @@@@ 
@@@@@@@
@@@@@@@
 @@@@@ 
  @@@  
   @   


   @@  
  @@@@ 
 @@@@@@
@@@@@@@
 @@@@@ 
  @@@  
   @   


   @@  
  @@@@ 
 @@@@@@
 @@@@@@
 @@@@@ 
  @@@  
   @   


   @@  
  @@@@ 
 @@@@@@
 @@@@@@
  @@@@ 
  @@@  
   @   


   @@  
  @@@@ 
 @@@@@@
 @@@@@@
  @@@@ 
   @@  
   @   


   @@  
  @@@@ 
 @@@@@@
 @@@@@@
  @@@@ 
   @@  



   @@  
  @@@@ 
 @@@@@@
 @@@@@@
  @@@@ 
   @   



   @@  
  @@@@ 
 @@@@@@
 @@@@@@
  @@@  
   @   



   @@  
  @@@@ 
 @@@@@@
 @@@@@ 
  @@@  
   @   



   @@  
  @@@@ 
 @@@@@ 
 @@@@@ 
  @@@  
   @   



   @@  
  @@@  
 @@@@@ 
 @@@@@ 
  @@@  
   @   



   @   
  @@@  
 @@@@@ 
 @@@@@ 
  @@@  
   @   




  @@@  
 @@@@@ 
 @@@@@ 
  @@@  
   @   




   @@  
 @@@@@ 
 @@@@@ 
  @@@  
   @   




   @@  
  @@@@ 
 @@@@@ 
  @@@  
   @   




   @@  
  @@@@ 
  @@@@ 
  @@@  
   @   




   @@  
  @@@@ 
  @@@@ 
   @@  
   @   




   @@  
  @@@@ 
  @@@@ 
   @@  





   @@  
  @@@@ 
  @@@@ 
   @   





   @@  
  @@@@ 
  @@@  
   @   





   @@  
  @@@  
  @@@  
   @   





   @   
  @@@  
  @@@  
   @   






  @@@  
  @@@  
   @   






   @@  
  @@@  
   @   






   @@  
   @@  
   @   






   @@  
   @@  







   @@  
   @   







   @   
   @   








   @   
 ​
 ​
 ​
 ​  


Catálogo

Baseado em Este número é primo?

VarmirGadkin
fonte
5
Bem-vindo ao PPCG! Bela primeira pergunta, a propósito.
Clismique
1
Os espaços em branco / novas linhas à direita são permitidos?
Loovjo 27/11
1
Não tenho as habilidades de retina, mas estaria interessado em ver isso - se for possível.
Jerry Jeremiah
@JamesHolderness Thanks! Eu consertei isso.
VarmirGadkin

Respostas:

5

Perl, 129 bytes

128 bytes de código + -nsinalizador.

$p=($r=$"x$n++."@"x$_.$/).$p.$r,$_-=2while$_>0;say$_=$p;say y/A/ /r while s/(^| )A(.*
? *)@/$1 $2A/m||s/@( *
?.*)A/A$1 /||s/@/A/

Você precisará de -nEsinalizadores para executá-lo:

perl -nE '$p=($r=$"x$n++."@"x$_.$/).$p.$r,$_-=2while$_>0;say$_=$p;say y/A/ /r while s/(^| )A(.*
? *)@/$1 $2A/m||s/@( *
?.*)A/A$1 /||s/@/A/' <<< 7

Explicações: (detalharei mais quando tiver um momento)
A primeira parte $p=($r=$"x$n++."@"x$_.$/).$p.$r,$_-=2while$_>0;gera a batata inicial: começa na linha do meio da batata e adiciona duas linhas a cada iteração: uma antes da sequência anterior, uma depois de. Observe que $"é um espaço e, como $nnão é inicializado, inicia em 0 e $/é uma nova linha.

Observe muito a dizer sobre o say$_=$p;que imprime a batata inicial enquanto a armazena $_(que mais tarde será mais fácil de manipular).

Finalmente, say y/A/ /r while s/(^| )A(.*\n? *)@/$1 $2A/m||s/@( *\n?.*)A/A$1 /||s/@/A/descasca a batata. A última posição em que um @foi removido contém um A(é arbitrário, poderia ter qualquer símbolo). Portanto, cada iteração consiste em encontrar o A, substituindo-o por um espaço e, enquanto isso, substituindo o próximo @por a A. Isso é feito graças a duas expressões regulares: s/(^| )A(.*\n? *)@/$1 $2A/mquando Aestá no lado esquerdo da batata ( A(.*\n? *)@permite ir à direita ou para baixo) e s/@( *\n?.*)A/A$1 /quando Aestá no lado direito ( @( *\n?.*)Apermite subir ou à esquerda). s/@/A/substitui o primeiro @por um A(que é a inicialização). Como sempre temos um Ana string, precisamos substituí-lo por um espaço ao imprimi-lo, é isso que y/A/ /racontece.


Apenas para os olhos , a versão animada parece bastante agradável: (para rodar em um terminal, é aproximadamente o mesmo código, mas com cleare sleep)

perl -nE 'system(clear);$p=($r=$"x$n++."@"x$_.$/).$p.$r,$_-=2while$_>0;say$_=$p;select($,,$,,$,,0.1),system(clear),say y/A/ /r while(s/(^| )A(.*\n? *)@/$1 $2A/m||s/@( *\n?.*)A/A$1 /||s/@/A/)&&/@/' <<< 10
dada
fonte
1
Isso é ótimo! Eu nunca me diverti muito assistindo a um programa de animação :)
VarmirGadkin
3

Befunge, 319 254 bytes

&:00p1+:40p2/10p>:40g%20p:40g/30p\:10g30g`:!00g:2%!-30g-*\30g*+:20g1+v
+10g-::40g\-*2*30g+\-1+00g2%!+\00g2/1++20g-:::40g\-*2*+30g-\4*00g2*-v>
v+1\,-**2+92!-g02g00**84+1`\+*`g02g01\*!`g02g01+**!-g02\`g03:/2g00-4<
>:40g00g:2%+*`!#v_$1+:55+,00g::*1-2/+`#@_0

A motivação para esse algoritmo foi tentar evitar o máximo possível de ramificação, uma vez que um único caminho de execução é geralmente mais fácil de jogar golfe. O código é, portanto, composto de apenas dois loops: o loop externo iterando sobre os quadros do processo de peeling e o loop interno renderizando a batata para cada quadro.

O loop de renderização está basicamente emitindo apenas uma sequência de caracteres, o caractere para cada iteração sendo determinado por uma fórmula bastante complicada que pega o número do quadro do processo de peeling e o índice da sequência de saída e retorna um @, um espaço ou um nova linha, conforme necessário.

Experimente online!

James Holderness
fonte
1
Uau, isso é lindo.
416E64726577
2

Python 3.5.1, 520 bytes

n=int(input())L=lenR=rangeP=printdefg(a,b):f=list(a)ifb:foriinR(L(f)):iff[i]=="@":f[i]=""breakelse:foriinR(L(f)-1,-1,-1):iff[i]=="@":f[i]=""breakreturn"".join(f)l=[]s=(2-n%2n)*(((n-2n%2)/2)1)i=2-n%2whilei<=n:l.append("@"*i)i=2j=L(l)-1whilej>=0:l.append(l[j])j-=1y=[rforrinR(int((L(l)/2)-1),-1,-1)]forhinR(L(y)-1,-1,-1):y.append(y[h])defH(q):foreinR(L(l)):P((""*y[e])q[e])P("")H(l)k=0m=0whilek<s:fortinR(L(l)):if'@'inl[t]andm%2==0:l[t]=g(l[t],True)k=1H(l)if'@'inl[t]andm%2==1:l[t]=g(l[t],False)k=1p=l[:]p.reverse()H(p)m=1

Explicação

Ideia básica: alterne entre iterar cada linha e remover o caractere mais à esquerda e iterar cada linha removendo o caractere mais à direita enquanto ainda @restar s.

n=int(input())
L=len
R=range
P=print
# g() returns a line in the potato with leftmost or rightmoxt '@' removed
def g(a,b):
    f=list(a)
    if b:
        for i in R(L(f)):
            if f[i]=="@":
                f[i]=" "
                break
    else:
        for i in R(L(f)-1,-1,-1):
            if f[i]=="@":
                f[i]=" "
                break
    return "".join(f)

l=[]
# s is the total number of '@'s for size n
s=(2-n%2+n)*(((n-2+n%2)/2)+1)
i=2-n%2

# store each line of potato in l
while i<=n:
    l.append("@"*i)
    i+=2
j=L(l)-1
while j>=0:
    l.append(l[j])
    j-=1

# this is used for spacing
y=[r for r in R(int((L(l)/2)-1),-1,-1)]
for h in R(L(y)-1,-1,-1):
    y.append(y[h])

# print the potato
def H(q):
    for e in R(L(l)):
        P((" "*y[e])+q[e])
    P("\n")

H(l)
k=0
m=0

# while there are still '@'s either
# go down the potato removing leftmost '@' 
# go up the potato removing rightmost '@'
while k<s:
    for t in R(L(l)):
        if '@' in l[t] and m%2==0:
            l[t]=g(l[t],True)
            k+=1
            H(l)               
        if '@' in l[t] and m%2==1:
            l[t]=g(l[t],False)
            k+=1
            p=l[:]
            p.reverse()
            H(p)
    m+=1

No geral, uma triste tentativa de um procedimento direto.

Bobas_Pett
fonte