Вывести перевернутую палатку

27

Учитывая целое число, выведите перевернутую палатку.

Вход определяет как размер палатки (абсолютное значение), так и то, находится ли вход слева (отрицательные числа) или справа (положительные числа).

If input = -1:
____
\/_/

If input = -2:
________
\  /   /
 \/___/

If input = -3:
____________
\    /     /
 \  /     /
  \/_____/

If input = 1:
____
\_\/

If input = 2:
________
\   \  /
 \___\/

If input = 3:
____________
\     \    /
 \     \  /
  \_____\/

et cetera

Обратите внимание, что верхняя часть палатки (то есть последняя строка) имеет 2 * abs(input) - 1подчеркивание.

Там не может быть не ведущие пробелы, так что первая линия непосредственно начинается с символа подчеркивания.

Предположим, что ввода никогда не будет 0.

Ваш код должен быть максимально коротким.

Это испытание основано на мини-соревновании в чате от Helka Homba , которое разрешено использовать в реальных соревнованиях в соответствии с условиями общественной лицензии Calvin's Hobbies .

user48538
источник
1
Конечные пробелы в порядке? Имеется в виду, можем ли мы вывести четыре строки длиной 12 (прямоугольник) для ввода, 3например?
AdmBorkBork
1
@TimmyD Они будут разрешены.
user48538
2
@TimmyD уверен, что кто-то, вероятно, тоже обманщик, я не совсем уверен, где начинается цепочка. Я просто думаю, что мы уже видели достаточно из них.
Натаниэль
5
Я не вижу, как вопросы даже отдаленно похожи. Конечно, это обе задачи ascii-art, которые принимают число и заставляют вас выводить n-ю итерацию чего-либо, но на этом сходство заканчивается. Если этого достаточно, чтобы закрыть глаза, мы не должны больше принимать вызовы ascii-art .
DJMcMayhem
2
@Nathaniel Нашим общепринятым принципом для двух задач, являющихся дубликатами, является вопрос о том, можно ли повторно использовать ответы одного (конкурентно) другого без каких-либо изменений или без изменений. Вопрос о том, принесут ли проблемы что-то новое, не является частью этого руководства. Пожалуйста, используйте отрицательные оценки для вызовов, которые вы хотите обескуражить, или просто игнорируйте их, если они не думают, что они интересны, и дайте возможность тем, кто действительно наслаждается ими.
Мартин Эндер

Ответы:

11

MATL , 55 53 52 51 байт

|95cy4*Y"DXytPEt0*yvG0>?P_]!'\/ 'w)95JG|G0<yEq:++&(

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

объяснение

Позвольте Nобозначить вход. Код продолжается в три этапа.

Во-первых , первая строка 4*Nподчеркивания строится как строка и отображается (что удаляет ее из стека).

Во-вторых , «каркас» палатки строится с использованием двух типов слешей. Для этого создается числовой двумерный массив, который содержит 1и 2соответствует двум типам слешей, а также 0для пространства.

Это делается путем объединения четырех матриц:

  1. Единичная матрица размера abs (N);
  2. Матрица того же размера, содержащая 2в антидиагонале;
  3. Нулевая матрица того же размера;
  4. Копия матрицы 2.

Конкатенация этих четырех матриц по вертикали дает N=3на примере следующую 4*N × Nматрицу:

1 0 0
0 1 0
0 0 1
0 0 2
0 2 0
2 0 0
0 0 0
0 0 0
0 0 0
0 0 2
0 2 0
2 0 0

(который, транспонированный, начинает выглядеть как палатка).

Теперь мы позаботимся о знаке ввода. Если оно положительное, мы просто перемещаем вышеуказанную матрицу и индексируем в строку '\/ '. Индексирование основано на 1 и является модульным, поэтому 1становится '\', 2становится '/'и 0становится ' ', создавая массив двумерных символов

\    /     /
 \  /     / 
  \/     /  

С другой стороны, если входной сигнал отрицательный, мы вертикально переворачиваем и арифметически отрицаем 4*N × Nматрицу, производя

-2  0  0
 0 -2  0
 0  0 -2
 0  0  0
 0  0  0
 0  0  0
-2  0  0
 0 -2  0
 0  0 -2
 0  0 -1
 0 -1  0
-1  0  0

Индекс -1теперь относится '/'и -2к '\'. Таким образом, два типа косых черт были заменены, как требуется. Снова транспонирование и индексирование в строку, '\/ 'таким образом, дает обратную палатку:

\     \    /
 \     \  / 
  \     \/  

В-третьих , подчеркивания необходимо заполнить частью последней строки двумерного массива символов. Горизонтальное положение этой линии зависит от знака ввода и его длины abs(N).

Как только соответствующие пробелы были заменены символами подчеркивания, результат неявно отображается ниже начальной строки символов подчеркивания, которая уже отображалась на первом этапе.

Луис Мендо
источник
Разве эти подчеркивания в начале не должны быть пробелами?
DJMcMayhem
@DJMcMayhem Извините, что вы имеете в виду?
Луис Мендо
Когда я запускаю ваш код, первая строка подчеркивается. Вывод, который дал Зябин, не имеет этого.
DJMcMayhem
@DJMcMayhem Я не следую. Первая строка в тестовых случаях подчеркивает, не так ли? И другие ответы (не ваши) тоже это делают?
Луис Мендо
1
@DJMcMayhem :-D действительно странно. Попробуйте другой браузер?
Луис Мендо
9

Javascript (ES6), 139 байт

Строит палатку рекурсивно:

f=(N,n=N>0?N:-N,i=0,r=(j,i)=>' _'[i||0].repeat(j),a=`\\${r(i)}/`,b=r(n*2+i-1,+!i))=>n--?f(N,n,i+2)+`
`+r(n)+(N<0?a+b+'/':'\\'+b+a):r(i*2,1)

Разоблаченный и прокомментированный

f = (
  N,                                  // N is the original parameter (remains unchanged)
  n = N > 0 ? N : -N,                 // n is initialized to abs(N)
  i = 0,                              // i is the row counter (*2)
  r = (j, i) => ' _'[i||0].repeat(j), // helper function to repeat ' ' or '_' j times
  a = `\\${r(i)}/`,                   // a = '\ /' pattern
  b = r(n*2+i-1, +!i)                 // b = padding pattern filled with ' ' or '_'
) =>
  n-- ?                               // if we haven't made it yet to the top row:
    f(N, n, i+2) + `\n` +             //   - compute next row(s) / append line break
    r(n) +                            //   - append leading spaces
    (N < 0 ? a+b+'/' : '\\'+b+a)      //   - append a/b patterns according to N sign
  :                                   // else:
    r(i*2, 1)                         //   - return top row, made of '_' characters

Примеры

var f=(N,n=N>0?N:-N,i=0,r=(j,i)=>' _'[i||0].repeat(j),a=`\\${r(i)}/`,b=r(n*2+i-1,+!i))=>n--?f(N,n,i+2)+`
`+r(n)+(N<0?a+b+'/':'\\'+b+a):r(i*2,1)

console.log(f(3));
console.log(f(-4));

Arnauld
источник
6

Python 2, 143, 141, 139, 138, 137 байт.

-2 байта благодаря @ Sp3000 (нет необходимости заключать в скобки exec в Python 2)
-1 байт благодаря @ Sp3000 (использовать cmp)

def f(n):d=cmp(n,0);a,b='\/'[::-d];s=n*d;x=2*s-1;y=4*s;print'_'*y;i=0;exec"print' '*i+(b+' '*(y-3-x-i-i)+a+'_ '[s-i>1]*x+a)[::d];i+=1;"*s

Проверьте это на Ideone

Сначала мы видим, nотрицательно d +1ли это, и делаем, если оно есть, и -1если нет.
Затем мы выбираем две косые черты aи b, используя так d, чтобы a='\', b='/'когда было nположительно, а a='/', b='\'когда было nотрицательно.
Далее мы устанавливаем, s=abs(n)что может быть достигнуто s=n*d.
Затем мы рассчитываем число _вверху (внизу рисунка), которое также является числом в стороне от палатки как x=2*s-1.
Затем мы рассчитываем количество _у основания палатки (вверху рисунка) и сохраняем его так, y=4*sкак оно будет использоваться в цикле для создания остальной части палатки.
Теперь мы печатаем основание палатки, используя print'_'*y.
Затем мы печатаем оставшуюся часть палатки, выполняя sоператоры печати с iинициализируемой переменной цикла, значение 0которой увеличивается 1для каждого оператора печати.
У остальной части палатки есть y-3-x-i-iпробелы в дверях и xпробелы в корпусе до тех пор, пока не будет достигнут верх, когда s-i>1оценивается как False, выбирая _from '_ '.
Для положительной палатки с левой дверью вся палатка, исключая ведущие пространства, находится спереди назад, поэтому она переворачивается, тогда как положительной палатки с правой дверью нет [::d].

Джонатан Аллан
источник
@ Sp3000, к сожалению, cmp(0,0)возвращается0
Джонатан Аллан
5

Python 2, 121 байт

def f(n):i=k=abs(n);print'_'*k*4;exec"print' '*(k-i)+r'\\\%%s%\*%c%%*sc/'[n<0::2]%(' _'[i<2]*(2*k-1))%(2*i-1,47);i-=1;"*k

Просто много форматирования строк.

Sp3000
источник
5

C #, 215 214 байт

string t(int N){var n=N<0;N=n?-N:N;var t=new string('_',4*N);for(int i=0;i<N;){string f=new string(i<N-1?' ':'_',2*N-1),p=new string(' ',2*N-2*i-2);t+='\n'+new string(' ',i++)+'\\'+(n?p+'/'+f:f+'\\'+p)+'/';}return t;}

Есть возможность сэкономить несколько байтов при использовании using s=string;заранее.

s t(int N){var n=N<0;N=n?-N:N;var t=new s('_',4*N);for(int i=0;i<N;){s f=new s(i<N-1?' ':'_',2*N-1),p=new s(' ',2*N-2*i-2);t+='\n'+new s(' ',i++)+'\\'+(n?p+'/'+f:f+'\\'+p)+'/';}return t;}

что будет 15 (с использованием) + 184 (метод) = 199 байт.

BackFromExile
источник
5
Добро пожаловать в PPCG, BackFromExile!
Эрик Outgolfer
Действительно, добро пожаловать в PPCG! Очень хороший первый ответ +1. Я пытался найти что-нибудь для гольфа (довольно давно, так как я программировал на C #), и в итоге смог найти только одну вещь для -1 байта: если вы измените первое varв цикле for на string, вы можете удалить второй var (включая место для сохранения байта). Так var fстановится string fи ;var p=становится ,p=.
Кевин Круйссен,
4

TSQL, 195 байт

Golfed:

DECLARE @ INT=-2
DECLARE @b INT=ABS(@),@i INT=0PRINT REPLICATE('_',4*@b)z:SET @i+=1PRINT SPACE(@i-1)+'\'+STUFF(REPLICATE(IIF(@i<@b,' ','_'),4*@b-2*@i),@b*2-IIF(@<0,@i*2-1,0),1,IIF(@<0,'/','\'))+'/'IF @i<@b GOTO z

Ungolfed:

DECLARE @ INT=-2

DECLARE @b INT=ABS(@),@i INT=0

PRINT REPLICATE('_',4*@b)
z:
  SET @i+=1
  PRINT 
    SPACE(@i-1)+'\'
    +STUFF(REPLICATE(IIF(@i<@b,' ','_'),
      4*@b-2*@i),@b*2-IIF(@<0,@i*2-1,0),1,IIF(@<0,'/','\'))
    +'/'
IF @i<@b GOTO z

скрипка

t-clausen.dk
источник
4

V , 66 байт

é /ä
"aDoÀñá_>ñ^hr\A\/ò^hÄX$2é_Ó_/ òÄÒ_ñ/-
ddÍܨ[ _]*©Ü¨ *©/ܲ¯±

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

Это довольно наивный подход, поэтому я постараюсь развить его чуть позже сегодня. Это решение содержит непечатаемые символы, поэтому вот hexdump:

0000000: e920 2fe4 0a22 6144 6f1b c0f1 e15f 3ef1  . /.."aDo...._>.
0000010: 5e68 725c 415c 2f1b f25e 68c4 5824 32e9  ^hr\A\/..^h.X$2.
0000020: 5fd3 5f2f 20f2 c4d2 5ff1 2f2d 0a64 64cd  _._/ ..._./-.dd.
0000030: dca8 5b20 5f5d 2aa9 dca8 202a a92f dcb2  ..[ _]*... *./..
0000040: afb1                                     ..
DJMcMayhem
источник
4

05AB1E , 52 байта

Ä©'_4®*×,FNð×'\®·<N>®Qi'_ëð}×®N>-·ð×®¹Qi'\ës'/}s'/J,

объяснение

                                                     # implicit input, call this A
Ä©                                                   # store abs(A) in register for later use
  '_4®*×,                                            # print 4*A underscores (tent floor)
         F                                           # for each non-floor section in range(N)
          Nð×'\                                      # push N spaces at the beginning of the 
                                                     # row followed by a backslash
                  N>®Qi'_ëð}                         # if we're on the last row push an
                                                     # underscore, else a space
               ®·<          ×                        # repeat that char abs(A)*2-1 times
                             ®N>-·ð×                 # push 2*(abs(A)-(N+1)) spaces
                                    ®¹Qi'\ës'/}      # if input is positive push backslash
                                                     # else push a slash
                                               s'/   # move that char between the 2 sections
                                                     # of spaces
                                                  J, # join the row and print

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

Emigna
источник
4

PowerShell v2 +, 217 205 190 187 184 байта

param($b)"_"*(($a=[math]::Abs($b))*4);$z,$y='/\'[($b=$b-lt0),!$b]
((($x=1..$a|%{($w=" "*($_-1))+$z+" "*(2*($a-$_))+$y+(' ','_')[$_-eq$a]*($a*2-1)+$y+$w})|%{-join$_[($a*4)..0]}),$x)[$b]

Принимает ввод $bкак целое число. Обратите внимание, что если $bоно отрицательное, вам нужно явно заключить его в скобки для правильного приведения (см. Примеры), иначе PowerShell будет думать, что это строка.

Независимо от того, в каком направлении стоит палатка, первая строка одна и та же, несколько подчеркиваний; 4*abs(input)на самом деле их точно много. Этот номер также сохраняется $aдля последующего использования. Кроме того, теперь, когда у нас есть абсолютное значение, $bсохраненное в $a, мы превращаемся $bв логическое значение для его знака и выбираем наши слэши, сохраненные в $yи $z.

Следующая строка - это построение и формулировка вывода, и это глупо, поэтому давайте разберем его.

Мы по существу индексируем в массив из двух элементов, (big long calculations saved into $x)или $x, на основе $b.

Расчеты, где строение палатки. Мы возвращаемся из 1..$a|%{...}. На каждой итерации мы строим линию тела палатки. Мы начинаем с количества пробелов, равных строке #, в которой мы находимся -1, так что это соответственно выровнено по левому краю. Это сохраняется $wдля последующего использования и объединяется с соответствующей косой чертой ($ z, на основе $b), затем количеством пробелов в дверной раме, затем другой косой чертой $y, либо подчеркиванием или пробелами в зависимости от того, находимся ли мы в нижней строке или нет, затем еще одна косая черта $yи, наконец, соответствующее количество конечных пробелов ( $w) для построения прямоугольной строки. Этот результирующий массив строк сохраняется в $x.

Если выбрана левая половина массива (то есть, $bэто , Falseтак как входной сигнал был положительным), то мы должны петли через $xи обратный каждый элемент строки - это где конечные пробелы вступают в игру; это позволяет нам просто повернуть линии, а не пересчитывать расстояния.

Если $bесть True, то $xвместо этого выбирается правая половина массива .

В любом случае, конвейер теперь содержит массив строк. Неявный вывод через Write-Outputпроисходит при завершении программы, с новой строкой по умолчанию между элементами.

Примеры

PS C:\Tools\Scripts\golfing> .\print-upside-down-tent.ps1 (-5)
____________________
\        /         /
 \      /         / 
  \    /         /  
   \  /         /   
    \/_________/    

PS C:\Tools\Scripts\golfing> .\print-upside-down-tent.ps1 (4)
________________
\       \      /
 \       \    / 
  \       \  /  
   \_______\/   
AdmBorkBork
источник
3

Haskell, 187 184 183 байта

f x=unlines$[(n*4)%'_']++((' '#)<$>[0..n-2])++['_'#(n-1)]where m#i=i%' '++'\\':m!i++"/";m!i|x>0=(2*n-1)%m++'\\':(2*(n-i-1))%' '|q<-2*(n-i-1)=q%' '++'/':(2*n-1)%m;n=abs x;m%c=c<$[1..m]

Я чувствую, что это не лучший результат для Haskell, поэтому любые идеи по улучшению приветствуются.

  • 3 байта сохранены благодаря @Myridium
  • 1 байт сохранен благодаря @nimi

Ungolfed

tent :: Int -> String
tent x = unlines $ [replicate (n*4) '_'] ++ (row ' '<$>[0..n-2]) ++ [row '_' (n-1)]
    where row m i = replicate i ' ' ++ "\\" ++ dir m i ++ "/"
          -- direction selector
          dir m i | x > 0 = side m ++ "\\" ++ entrance i ' '
                  | 1 > 0 = entrance i ' ' ++ "/" ++ side m
          side = replicate (2*n-1)
          entrance i = replicate (2*(n-i-1))
          n = abs x
sudee
источник
Лучше, чем мои 290 байт, которые я собирался опубликовать ...
Myridium
Не следует ли добавить, mainчтобы он принимал в stdinкачестве входных данных?
Миридиум
Вы можете опубликовать одну функцию, если в вопросе не указано иное. Есть мета-поток для общих правил ответа, я постараюсь найти его для вас.
Sudee
1
Вы можете сохранить 2 байта, изменив место, где вы добавляете один символ для использования :символа. т.е. изменить "\\" ++ entrance...на '\\':entrance.
Миридиум
1
Не тратьте «иначе» охранника : вы можете изменить |1>0=(2*(n-i-1))%' 'на |q<-2*(n-i-1)=q%' '.
Ними,
2

C 240 207 193 байта

#define P putchar
a,j,l,m;g(x,y,z){for(m=y+z+1;m--;P(m^z?l?32:95:x));}f(n){g(32,(a=abs(n))*4,0);for(P(10),j=2*(l=a)-1;l--;){for(m=a;--m>l;P(32));P(92);m=n>0?g(92,j,l*2):g(47,l*2,j);puts("/");}}

На этот раз я оптимизировал функцию g (...), чтобы использовать один цикл for.

#define P putchar
a,j,l,m;g(x,y,z){for(;y--;P(l?32:95));for(P(x);z--;P(l?32:95));}f(n){g(32,(a=abs(n))*4,0);l=a;j=2*a-1;P(10);for(;l--;){for(m=a;--m>l;P(32));P(92);m=n>0?g(92,j,l*2):g(47,l*2,j);puts("/");}}

На этот раз макрос X лучше использовать как функцию g (...), и, поскольку y и z являются параметрами в новой области видимости, я могу просто уменьшить их в области видимости g.

#define P putchar
#define X(x,y,z){for(k=0;k++<y;P(l?32:95));P(x);for(k=0;k++<z;P(l?32:95));}
a,i,j,k,l,m;f(n){for(l=a=abs(n);i++<a*4;P(95));j=2*a-1;P(10);while(l--){for(m=a;--m>l;P(32));P(92);if(n>0)X(92,j,l*2)else X(47,l*2,j)puts("/");}}

Проверьте с этой основной функцией; Это должно упасть намного меньше.

main(c,v)char**v;
{
    f(atoi(v[1]));
}
cleblanc
источник
2

C # 241 231 байт

Сохранено 10 байтов благодаря @Kevin Cruijssen

using s=System.String;s f(int N){var f=N<0;N=N>0?N:-N;var o=new s('_',N*4);for(int j=0,z;j<N;){z=-2*j+2*N-2;var O=j>N-2?'_':' ';o+='\n'+new s(' ',j)+'\\'+new s(' ',z)+(f?'/':O)+new s(O,j++*2)+(f?O:'\\')+new s(' ',z)+'/';}return o;}

Старая версия:

string f(int N){var f=N<0;N=N>0?N:-N;var o=new string('_',N*4);for(int j=0;j<N;){int z=-2*j+2*N-2;var O=j>N-2?'_':' ';o+='\n'+new string(' ',j)+'\\'+new string(' ',z)+(f?'/':O)+new string(O,j++*2)+(f?O:'\\')+new string(' ',z)+'/';}return o;}

Первоначально имел new string(...)как Func<char,int,string>сохраненный один байт, используя конструктор. Я хочу int-> charбыл неявным

Уверен, моя математика тоже может быть исправлена, но я ее не вижу

pinkfloydx33
источник
1
Вы можете играть в гольф еще немного. Прежде всего , вы можете удалить int перед тем z=, добавив его в обмен на петлю: int j=0,z. И так как вы используете stringдовольно много, вы можете присвоить ему псевдоним. using s=System.String;Таким образом, итоговое значение становится: using s=System.String;s f(int N){var f=N<0;N=N>0?N:-N;var o=new s('_',N*4);for(int j=0,z;j<N;){z=-2*j+2*N-2;var O=j>N-2?'_':' ';o+='\n'+new s(' ',j)+'\\'+new s(' ',z)+(f?'/':O)+new s(O,j++*2)+(f?O:'\\')+new s(' ',z)+'/';}return o;}( 231 байт )
Кевин Круйссен
1

Swift 2.2 421 байт

Ну ... Это была попытка.

Golfed:

let t={(s:String,n:Int)->String in return String(count:n,repeatedValue:Character(s))};let e={(n:Int)in var w=[String]();w.append(t("_",abs(n)*4));let c = abs(n);let d = n>0 ? "/": "\\";let f = n>0 ? "\\": "/";for var i in 0...abs(n)-1 {w.append(t(" ",i)+d+t(" ",c*2-2-(2*i))+f+(i<c-1 ?t(" ",2*c-1)+f:t("_",2*c-1)+f)+(n>0 ?t(" ",i):""));};w=n<0 ?w:w.map(){String($0.characters.reverse())};print(w.joinWithSeparator("\n"))}

UnGolfed:

let t={(s:String,n:Int) -> String in
    return String(count:n,repeatedValue:Character(s))
};
let e={(n:Int) in
    var w=[String]();
    w.append(t("_",abs(n)*4));
    let c = abs(n);
    let d = n>0 ? "/": "\\";
    let f = n>0 ? "\\": "/";
    for var i in 0...abs(n)-1 {
        w.append(t(" ",i)+d+t(" ",c*2-2-(2*i))+f+(i<c-1 ?t(" ",2*c-1)+f:t("_",2*c-1)+f)+(n>0 ?t(" ",i):""));
    };
    w=n<0 ?w:w.map(){String($0.characters.reverse())};
    print(w.joinWithSeparator("\n"))
}
Danwakeem
источник
1

PHP, 143 байта

$t=str_repeat;echo$t(_,4*$s=$k=abs($n=$argv[1]));for(;$k--;$p.=" "){$f=$t("  ",$k);$r=$t($k?" ":_,2*$s-1);echo"
$p\\",$n<0?"$f/$r/":"$r\\$f/";}

бежать с php -r '<code>' <parameter>

сломать

$t=str_repeat;  // function name to variable saves 10-1 bytes
echo$t(_,4*$s=$k=abs($n=$argv[1])); // print bottom
for(
    ;
    $k--;   // $k from abs($n-1) to 0
    $p.=" "                 // create padding
)
{
    $f=$t("  ",$k);         // create front
    $r=$t($k?" ":_,2*$s-1); // create side/roof
    echo"\n$p\\",$n<0
        ?"$f/$r/"   // print, entrance left
        :"$r\\$f/"  // print, entrance right
    ;
}
Titus
источник
1

Пакетный, 289 байт

@echo off
set/pn=
set u=
for /l %%i in (2,1,%n:-=%)do call set u=_%%u%%_
echo _%u%__%u%_
set l=
set m=%u%/_%u%
if %n% gtr 0 set m=%u%_\%u%
set m=%m:_= %
for /l %%i in (2,1,%n:-=%)do call:l
set m=%m: =_%
:l
echo %l%\%m%/
set l= %l%
if %n% gtr 0 set m=  %m:~0,-2%
set m=%m:~2%

Принимает участие в STDIN. Начинается с создания строки 2*(abs(n)-1)подчеркивания. Затем это повторяется плюс еще 4 подчеркивания для основания палатки. Затем остальная часть палатки состоит из отступа (который увеличивается на 1 в каждой строке), а \, середины палатки и а /. Середина палатки начинается с 2*(abs(n)-1)пробелов, плюс либо \или /плюс пробел (который я не могу представить в Markdown), а также другие 2*(abs(n)-1)пробелы. Я повторно использую строку подчеркивания и заменяю их пробелами для удобства, но затем заменяю пробелы на подчеркивания для последней строки. Каждая строка удаляет два пробела с одной стороны от середины палатки, хотя немного сложнее, если нужно, сначала переместить два пробела к началу струны.

Нил
источник