Очистить картофель

20

Это картошка:

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

В целом, картофель размера N определяется как следующая форма:

Если N четное, это 2 центрированных @символа, за которыми следуют 4 центрированных @символа, за которыми следуют 6 центрированных @символов, вплоть до N центрированных @символов; затем N центрированных @символов, а затем N-2 центрированных @символов вплоть до 2.
Если N нечетно, размер N картошка генерируется так же, как описано выше, но мы начинаем с 1 @символа, а не с 2 ,

Картофель очищают, начиная с правого верхнего угла и убирая по одному @знаку на каждом шаге, двигаясь против часовой стрелки. Например, очистка картофеля размером 3 выглядит следующим образом:

 @
@@@
@@@
 @

​
@@@
@@@
 @

 ​
 @@
@@@
 @

  ​
 @@
 @@
 @

 ​
 @@
 @@
 ​

 ​
 @@
 @
 ​

​
 @
 @
 ​

 ​
​
 @
 ​


Вызов

Напишите программу, которая при целочисленном вводе отображает все этапы очистки картофеля такого размера.
Конечный пробел / переводы строки разрешены.

счет

Это ; выигрывает самый короткий код в байтах.


Примеры тестовых случаев

N = 2

@@
@@

@
@@


@@


 @



N = 7

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


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


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


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


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


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


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


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


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



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



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



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



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



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



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




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




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




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




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




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




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





   @@  
  @@@@ 
  @@@@ 
   @   





   @@  
  @@@@ 
  @@@  
   @   





   @@  
  @@@  
  @@@  
   @   





   @   
  @@@  
  @@@  
   @   






  @@@  
  @@@  
   @   






   @@  
  @@@  
   @   






   @@  
   @@  
   @   






   @@  
   @@  







   @@  
   @   







   @   
   @   








   @   
 ​
 ​
 ​
 ​  


Каталог

Основано на Это число простое?

VarmirGadkin
источник
5
Добро пожаловать в PPCG! Хороший первый вопрос, кстати.
clismique
1
Разрешены ли конечные пробелы / переводы строки?
Loovjo
1
У меня нет навыков работы с сетчаткой, но мне было бы интересно увидеть это - если это возможно.
Джерри Иеремия
@JamesHolderness Спасибо! Я исправил это.
ВармирГадкин

Ответы:

5

Perl, 129 байт

128 байт кода + -nфлаг.

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

Вам понадобятся -nEфлаги для его запуска:

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

Пояснения: (я опишу их подробнее, когда у меня будет время)
Первая часть, $p=($r=$"x$n++."@"x$_.$/).$p.$r,$_-=2while$_>0;генерирует начальный картофель: он начинается со средней строки картофеля и добавляет две строки на каждой итерации: одну перед предыдущей строкой, одну после. Обратите внимание, что $"это пробел, и поскольку $nон не инициализирован, он начинается с 0 и $/является новой строкой.

Обратите внимание на многое, что можно сказать о том, say$_=$p;что печатает исходный картофель при его хранении $_(которым позже будет легче манипулировать).

Наконец, say y/A/ /r while s/(^| )A(.*\n? *)@/$1 $2A/m||s/@( *\n?.*)A/A$1 /||s/@/A/чистит картошку. Последняя позиция, в которой @была удалена буква a, содержит A(произвольно, это может быть любой символ). Таким образом, каждая итерация состоит в том, чтобы найти A, заменить ее пробелом, а между тем заменить следующую @на A. Это делается благодаря двум регулярным выражениям: s/(^| )A(.*\n? *)@/$1 $2A/mкогда Aслева от картофеля ( A(.*\n? *)@позволяет идти вправо или вниз), и s/@( *\n?.*)A/A$1 /когда Aсправа ( @( *\n?.*)Aпозволяет идти вверх или слева). s/@/A/заменяет первое @на A(это инициализация). Поскольку у нас всегда есть Aстрока в строке, нам нужно заменить ее пробелом при печати, вот что y/A/ /rделает.


На первый взгляд , анимированная версия выглядит довольно красиво: (для запуска в терминале это примерно тот же код, но с clearи 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
папа
источник
1
Это круто! Мне никогда не было так весело смотреть мультипликационную программу :)
VarmirGadkin
3

Befunge, 319 254 байта

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

Мотивация для этого алгоритма состояла в том, чтобы постараться как можно больше избегать разветвлений, так как одиночный путь исполнения, как правило, легче играть в гольф. Таким образом, код состоит всего из двух циклов: внешнего цикла, повторяющегося по кадрам процесса очистки, и внутреннего цикла, отображающего картошку для каждого кадра.

Цикл рендеринга, по сути, просто выводит последовательность символов, причем символ для каждой итерации определяется довольно сложной формулой, которая принимает номер кадра процесса очистки и индекс выходной последовательности и возвращает либо @пробел, либо пробел, либо Новая строка, как требуется.

Попробуйте онлайн!

Джеймс Холдернесс
источник
1
Вау, это прекрасно.
416E64726577
2

Python 3.5.1, 520 байт

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

объяснение

Основная идея: чередуйте итерацию вниз по каждой строке и удаление крайнего левого символа и итерацию вверх по каждой строке, удаляя крайний правый символ, в то время как еще есть @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

В целом печальная попытка простой процедуры.

Bobas_Pett
источник