Obierz ziemniaka

20

To jest ziemniak:

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

Bardziej ogólnie, ziemniak w rozmiarze N jest zdefiniowany jako następujący kształt:

Jeśli N jest parzyste, oznacza to 2 wyśrodkowane @symbole, następnie 4 wyśrodkowane @symbole, a następnie 6 wyśrodkowane @symbole, aż do N wyśrodkowanych @symboli; następnie @symbole N na środku , a następnie symbole na środku N-2 @aż do 2.
Jeśli N jest nieparzysty, ziemniak o wielkości N jest generowany w taki sam sposób, jak opisano powyżej, ale zaczynamy od 1 @symbolu, a nie 2 .

Ziemniak obiera się, zaczynając od prawego górnego rogu i usuwając jeden @znak na każdym kroku, idąc w kierunku przeciwnym do ruchu wskazówek zegara. Na przykład obieranie ziemniaka wielkości 3 wygląda następująco:

 @
@@@
@@@
 @

​
@@@
@@@
 @

 ​
 @@
@@@
 @

  ​
 @@
 @@
 @

 ​
 @@
 @@
 ​

 ​
 @@
 @
 ​

​
 @
 @
 ​

 ​
​
 @
 ​


Wyzwanie

Napisz program, który po wprowadzeniu liczby całkowitej wyświetli wszystkie etapy obierania ziemniaka o tym rozmiarze.
Końcowe spacje / znaki nowej linii są dozwolone.

Punktacja

To jest ; najkrótszy kod w bajtach wygrywa.


Przykładowe przypadki testowe

N = 2

@@
@@

@
@@


@@


 @



N = 7

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


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


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


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


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


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


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


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


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



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



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



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



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



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



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




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




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




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




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




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




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





   @@  
  @@@@ 
  @@@@ 
   @   





   @@  
  @@@@ 
  @@@  
   @   





   @@  
  @@@  
  @@@  
   @   





   @   
  @@@  
  @@@  
   @   






  @@@  
  @@@  
   @   






   @@  
  @@@  
   @   






   @@  
   @@  
   @   






   @@  
   @@  







   @@  
   @   







   @   
   @   








   @   
 ​
 ​
 ​
 ​  


Katalog

Na podstawie Czy ta liczba jest liczbą pierwszą?

VarmirGadkin
źródło
5
Witamy w PPCG! Przy okazji, fajne pierwsze pytanie.
clismique
1
Czy dozwolone są końcowe białe znaki / znaki nowej linii?
Loovjo
1
Nie mam umiejętności Retina, ale chciałbym to zobaczyć - jeśli to możliwe.
Jerry Jeremiah
@JamesHolderness Thanks! Naprawiłem to.
VarmirGadkin

Odpowiedzi:

5

Perl, 129 bajtów

128 bajtów kodu + -nflaga.

$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/

Potrzebujesz -nEflagi, aby go uruchomić:

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

Objaśnienia: (opiszę je bardziej szczegółowo, gdy będę miał chwilę)
. Pierwsza część $p=($r=$"x$n++."@"x$_.$/).$p.$r,$_-=2while$_>0;generuje początkowego ziemniaka: zaczyna się od środkowej linii ziemniaka i dodaje dwie linie przy każdej iteracji: jeden przed poprzednim ciągiem, jeden po. Zauważ, że $"jest to spacja i ponieważ $nnie jest zainicjowana, zaczyna się od 0 i $/jest nową linią.

Zauważ wiele do powiedzenia na temat tego, say$_=$p;który drukuje początkowego ziemniaka podczas przechowywania go $_(który później będzie łatwiejszy do manipulowania).

Na koniec say y/A/ /r while s/(^| )A(.*\n? *)@/$1 $2A/m||s/@( *\n?.*)A/A$1 /||s/@/A/obiera ziemniaka. Ostatnia pozycja, w której @usunięto a, zawiera A(jest to dowolne, może to być dowolny symbol). Więc każda iteracja polega na znalezieniu A, zastępując go z miejsca, a w międzyczasie zastępując następny @z A. Dzieje się tak dzięki dwóm wyrażeniom regularnym: s/(^| )A(.*\n? *)@/$1 $2A/mkiedy Aznajduje się po lewej stronie ziemniaka ( A(.*\n? *)@pozwala iść w prawo lub w dół), a s/@( *\n?.*)A/A$1 /gdy Aznajduje się po prawej stronie ( @( *\n?.*)Apozwala iść w górę lub po lewej). s/@/A/zastępuje pierwszy @na A(to jest inicjalizacja). Ponieważ zawsze mamy Aciąg znaków, musimy go zastąpić spacją podczas drukowania, więc to y/A/ /rdziała.


Tylko dla oczu , animowana wersja wygląda całkiem ładnie: (do uruchomienia w terminalu, jest to mniej więcej ten sam kod, ale z cleari 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
źródło
1
To jest świetne! Nigdy nie bawiłem się tak dobrze oglądając program animowany :)
VarmirGadkin
3

Befunge, 319 254 bajtów

&: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

Motywacją tego algorytmu była próba uniknięcia rozgałęzień w jak największym stopniu, ponieważ jedna ścieżka wykonania jest ogólnie łatwiejsza do gry w golfa. Kod składa się zatem tylko z dwóch pętli: zewnętrznej pętli iterującej się po ramkach procesu obierania oraz wewnętrznej pętli renderującej ziemniaka dla każdej ramki.

Pętla renderująca generuje po prostu sekwencję znaków, przy czym znak dla każdej iteracji jest określany przez dość skomplikowaną formułę, która bierze numer klatki procesu obierania i indeks sekwencji wyjściowej i zwraca albo @, spację lub nowa linia, zgodnie z wymaganiami.

Wypróbuj online!

James Holderness
źródło
1
Wow, to jest piękne.
416E64726577
2

Python 3.5.1, 520 bajtów

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

Wyjaśnienie

Podstawowy pomysł: na przemian iteracja w dół każdej linii i usuwanie znaku znajdującego się najdalej z lewej strony oraz iteracja w górę każdej linii, usuwanie znaku znajdującego się najbardziej z prawej strony, gdy są jeszcze @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

Ogólnie smutna próba prostej procedury.

Bobas_Pett
źródło