34
\$\begingroup\$

Given any string, print it in the form of a triangle where the text runs up and down along each diagonal. For example, an input of "Hello World" should output:

                    d
                  l  
                r   d
              o   l  
            W   r   d
              o   l  
        o   W   r   d
      l       o   l  
    l   o   W   r   d
  e   l       o   l  
H   l   o   W   r   d
  e   l       o   l  
    l   o   W   r   d
      l       o   l  
        o   W   r   d
              o   l  
            W   r   d
              o   l  
                r   d
                  l  
                    d

The space between each character in a row must be at least 1, in order to maintain the proper format.

\$\endgroup\$
13
  • 1
    \$\begingroup\$ May we assume the string isn't empty? \$\endgroup\$
    – Mr. Xcoder
    Aug 14, 2017 at 13:09
  • \$\begingroup\$ @Mr.Xcoder Yes you may \$\endgroup\$ Aug 14, 2017 at 13:15
  • 1
    \$\begingroup\$ The space between each character in a row must be at least 1: Does this mean that H l o W r d is a valid center row? Asking because in your example each row has 3 spaces between each character. \$\endgroup\$
    – Emigna
    Aug 14, 2017 at 13:33
  • 1
    \$\begingroup\$ @Emigna I misunderstood you question, my apologies. Yes, your example would be valid. \$\endgroup\$ Aug 14, 2017 at 13:37
  • 1
    \$\begingroup\$ Leading or trailing spaces allowed? \$\endgroup\$
    – Luis Mendo
    Aug 14, 2017 at 13:45

22 Answers 22

19
\$\begingroup\$

Charcoal, 10 7 bytes

↗ELθ✂θιUE¹

Try it online! Try it online! Links are to verbose version of code. Explanation:

    ↗       Print up and to the right
     ELθ✂θι All suffixes of the input, as a list down and to the right
    UE¹     Insert blank columns

First time I got to use the UE command.

\$\endgroup\$
10
  • \$\begingroup\$ I knew Charcoal would be one of the first answers here.. Was almost tempting to start myself, but I'm way to inexperienced with it to finish a solution in time, and it would get out-golfed anyway.. ;) \$\endgroup\$ Aug 14, 2017 at 13:11
  • 6
    \$\begingroup\$ @Emigna ...but this was my big chance to use UE... \$\endgroup\$
    – Neil
    Aug 14, 2017 at 14:25
  • 6
    \$\begingroup\$ @EriktheOutgolfer ...but this was my big chance to use UE.. \$\endgroup\$
    – Neil
    Aug 14, 2017 at 14:50
  • 1
    \$\begingroup\$ @Neil It's -3 bytes! -3 for a nice sacrifice! Who doesn't want some nice -3? \$\endgroup\$ Aug 14, 2017 at 14:53
  • 4
    \$\begingroup\$ @EriktheOutgolfer What you're supposed to say is, "You can't let 05AB1E beat you, can you?" \$\endgroup\$
    – Neil
    Aug 14, 2017 at 15:21
12
\$\begingroup\$

05AB1E, 10 8 7 bytes

Thanks to Emigna for saving 2 bytes!

ðâƶ.cðζ

Uses the 05AB1E encoding. Try it online!

\$\endgroup\$
9
  • \$\begingroup\$ As per this line The space between each character in a row must be at least 1 you can remove ¶«. (also verified the validity with OP ) \$\endgroup\$
    – Emigna
    Aug 14, 2017 at 13:39
  • \$\begingroup\$ @Emigna Thanks! :) \$\endgroup\$
    – Adnan
    Aug 14, 2017 at 13:46
  • \$\begingroup\$ Might want to update the Tio link :) \$\endgroup\$
    – Mr. Xcoder
    Aug 14, 2017 at 13:47
  • \$\begingroup\$ @Mr.Xcoder ninja'd \$\endgroup\$
    – Adnan
    Aug 14, 2017 at 13:47
  • 1
    \$\begingroup\$ Clever use of â in ðâ instead of Sð«! \$\endgroup\$ Aug 14, 2017 at 14:45
9
\$\begingroup\$

Python 2, 75 bytes

s=input()
k=l=len(s)
while k>1-l:k-=1;m=abs(k);print' '*m+' '.join(s[m::2])

Try it online!

Ruud saved 3 bytes.

\$\endgroup\$
2
  • 3
    \$\begingroup\$ This has been allowed by the OP: 78 bytes. The space on each row must be at least 1. \$\endgroup\$
    – Mr. Xcoder
    Aug 14, 2017 at 13:49
  • 1
    \$\begingroup\$ 75 bytes \$\endgroup\$
    – Arfie
    Aug 16, 2017 at 12:15
8
\$\begingroup\$

C, 86 78 73 70 chars

for(int i=1,j=1-n;i=putchar(j*j<i*i&i-j?s[i-1]?:13:32)^13?i+1:++j<n;);

Try it online!

Explanation

Naive implementation: two cycles, fill from top to bottom, left to right (99 bytes):

for(int j=1;j<n*2;j++){for(int i=0;i<n;i++)printf("%c ",(i+j)%2&&i+1>=abs(j-n)?s[i]:' ');puts("");}

Here, puts() just prints \n to the output. Let’s combine variable declarations and combine j++ with something (94 bytes):

for(int i,j=0;++j<n*2;){for(i=0;i<n;i++)printf("%c ",(i+j)%2&&i>=abs(j-n)?s[i]:' ');puts("");}

Good. Variable j has a range 0...2n; let it be within -n...n, this makes the math simpler. Notice that boolean expression at the right of && always has the value 0 or 1. This means we can replace && with &. 91 byte:

for(int i,j=-n;++j<n;){for(i=0;i<n;i++)printf("%c ",~(i+j)%2&i>=abs(j)?s[i]:' ');puts("");}

And now we realized we printing an extra space. And yeah, we don’t need printf() to print just a single symbol. 86 bytes:

for(int i,j=-n;++j<n;){for(i=0;i<n;i++)putchar(~(i+j)%2&i>=abs(j)?s[i]:' ');puts("");}

Even better. Notice that condition i * i>=j * j is same as i>=abs(j), but shorter. Let’s move puts() into for loop increment expression. And guess what? Actually, we don’t need the braces around i+j. 78 bytes:

for(int i,j=-n;++j<n;puts(""))for(i=0;i<n;i++)putchar(i*i>=j*j&~i+j?s[i]:' '); 

Did you know that putchar() returns the character it has printed? Let’s use XOR to test numbers for equivalence. Let’s replace space with its ASCII code, 32. Remember that end-of-line character code is 13. And finally: did you know that GCC/Clang do support https://en.wikipedia.org/wiki/Elvis_operator ? 73 bytes:

for(int i,j=-n;++j<n;)for(i=0;putchar(i*i>=j*j&~i+j?s[i]?:13:32)^13;i++);

Finally, guess what? We don’t need two for loops. We can replace ugly ~i+j with just i-j. 70 bytes:

for(int i=1,j=1-n;i=putchar(j*j<i*i&i-j?s[i-1]?:13:32)^13?i+1:++j<n;);

Future work: change loop direction? This might save some bytes, if done properly.

\$\endgroup\$
5
\$\begingroup\$

SOGL V0.12, 13 10 9 bytes

ēI*@∑}¹╚H

This uses a feature that I just added, but was documented a while ago.

Try it here!
In that link , is added because this expects the input on the stack and { added because otherwise , would get executed every time in the loop

implicitly start loop over POP
ē            increase the variable E, on first push which will be 0
 I           increase by 1
  *          multiply the current character that many times
   @∑        join with spaces
     }     end loop
      ¹    wrap everything on stack in an array
       ╚   center vertically
        H  rotate counter-clockwise
\$\endgroup\$
0
4
\$\begingroup\$

Haskell, 73 bytes

f s|l<-length s-1=[zipWith min s$(' '<$[1..abs x])++cycle"~ "|x<-[-l..l]]

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Gaia, 16 bytes

$:ċ⟪×$§×⟫†€|$¦tụ

Try it online!

Explanation

$                 Split into list of chars
 :ċ               Push [1 .. len(input)]
   ⟪×$§×⟫†        Apply this block to corresponding elements of the two lists:
    ×              Repetition
     $             Split into chars
      §×           Join with spaces
          €|      Centre align the rows
            $¦    Split each line into chars
              t   Transpose
               ụ  Join each row with spaces, then join the rows together with newlines
\$\endgroup\$
3
\$\begingroup\$

Python 2, 86 83 bytes

-3 thanks to officialaimm

lambda s,j=' '.join:map(j,zip(*(j(c*-~i).center(len(s)*2)for i,c in enumerate(s))))

Try it online!

\$\endgroup\$
1
3
\$\begingroup\$

Jelly, 15 bytes

;€⁶ṁ"JUz⁶ZUŒBZG

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Octave, 59 63 58 57 bytes

@(s,a=@strjust)a([kron(+a(hankel(s)),[1 0;0 0]) '']',99)'

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ 99: good idea :-) \$\endgroup\$
    – Luis Mendo
    Aug 14, 2017 at 16:01
3
\$\begingroup\$

Java, 292 bytes (sorry)

public class D{
public static void main(String[]r){
String s=r[0];int L=s.length(),n=L*2-1,x=L-1,d=-1,i,j;boolean a=false,o=L%2==1;
for(i=0;i<n;i++){
for(j=0;j<L;j++)System.out.print(j<x||a&&j%2==(o?0:1)||!a&&j%2==(o?1:0)?' ':s.charAt(j));
System.out.println();
x+=d;if(x<0){x=0;d=1;}a=!a;}}}
\$\endgroup\$
2
  • 1
    \$\begingroup\$ You can remove the newlines, otherwise, this looks pretty golfed! \$\endgroup\$
    – Adalynn
    Aug 14, 2017 at 22:31
  • 1
    \$\begingroup\$ You can golf more: 1. boolean a=1<0,o=L%2>0;. 2. If you don't need i, use this loop: for(i=0;i++<n;). 3. You can get rid of o: j%2<L%2 then j%2>L%2. 4. Using d as flip takes so many characters: just do j<(x<0?-x:x). 5. You have way more variables than needed. 6. You don't need a full program: a lambda or method is enough. -- If you want a golfed Java example, check my answer. \$\endgroup\$ Aug 14, 2017 at 22:51
3
\$\begingroup\$

Haskell, 81 bytes

f s|l<-length s=[[last$' ':[s!!i|i>=n,mod(n+i)2<1]|i<-[0..l-1]]|n<-abs<$>[-l..l]]

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Java (OpenJDK 8), 116 bytes

s->{for(int l=s.length(),i=-l;++i<l;)System.out.printf("%"+l+"s%n",s.substring(i<0?-i:i).replaceAll("(.).","$1 "));}

Try it online!

Explanation

s->{                                // Consumer<String> lambda
 for(int l=s.length(),i=-l;++i<l;)  // For each length between l and 1 and back to l, 
  System.out.printf("%"+l+"s%n",    // Print with align to right
    s.substring(i<0?-i:i)           // skip the first |i| characters
     .replaceAll("(.).","$1 ")      // replace every even-positioned character with a space.
   );
}
\$\endgroup\$
3
\$\begingroup\$

C++, 135 bytes

Okay, here's my shot with C++:

auto f=[&](auto f,int y)->void{
  for(int i{};i<n;i++) putchar(y<0?f(f,y+1?i+1:n-1-i),'\n':i<y||i+y&1?' ':s[i]);
}; f(f,-1); f(f,-2);

Try It Online (ideone)!

\$\endgroup\$
3
\$\begingroup\$

Haskell, 140 137 bytes

(m#n)s=(\(i,x)->' ':(last$"  ":[x:" "|rem i 2==m&&i>n]))=<<zip[0..]s
g s=((++)=<<reverse.tail)$id=<<[[(0#n)s,(1#n)s]|n<-[-1,1..length s]]

Try it online!

Saved 3 bytes thanls to Challenger5

I don't think that's optimal...

f produces one of the lines (m = 0 or 1 is the modulo of the line number, n is the number of the line)

g intercalates "odd" and "even" lines, and add to the result a mirror of itself.

\$\endgroup\$
1
  • \$\begingroup\$ You can save bytes by defining f as an infix function (as in (m#n)s=...) rather than a prefix function. \$\endgroup\$ Aug 16, 2017 at 7:01
2
\$\begingroup\$

Pyth, 25 bytes

j+_Km++*d;@Qdtj;%2>QdUQtK

Try it here.

\$\endgroup\$
2
\$\begingroup\$

Jelly, 18 bytes

JrLm€2Ṭ;€0a⁸o⁶ṚŒḄG

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Mathematica 105 Bytes

(c=Characters@#;l=Length@c;StringRiffle@Table[If[Abs[j-l]<i&&EvenQ[j+i],c[[i]]," "],{j,1,2l+1},{i,1,l}])&

Maybe I could shave off another byte or two, but the character count overhead of dealing with strings in Mathematica makes simple challenges like this uncompetitive.

\$\endgroup\$
2
\$\begingroup\$

J, 54 bytes

[:|:|.@i.@#(>@],~' '#~[)"_1[:(,' '&,)/&.>>:@i.@#<@#"0]

Try it online! (note that the output on TIO has a newline and three spaces, but that isn't from the function call -- it's probably just what the J interpreter does automatically).

I think the general idea for solving this is right, but there are small things that I'm probably doing sub-optimally that are adding to the bytecount.

Previous variants

55 bytes

<:@+:@#{.[:|:|.@i.@#(],~' '#~[)"_1>:@i.@#(,' '&,)/@#"0]

56 bytes

<:@+:@#{.[:|:|.@i.@#(],~' '#~[)"_1#{.[:(,' '&,)//.[:]\.]

Explanation

This will be split into a few functions. Also, I wasn't as thorough with latter parts of the explanation, so let me know if you want a better explanation for a certain part and I can edit that in.

dup   =. >:@i.@# <@#"0 ]
space =. (,' '&,)/&.>
pad   =. |.@i.@# (>@],~' '#~[)"_1 ]
trans =. |:
  • dup duplicates each character as many times as its index (plus one) in the string
  • space inserts spaces between each character
  • pad pads the characters with the right amount of spaces
  • trans transposes the resulting matrix

Sample call:

   trans pad space dup 'abc'
  c
 b 
a c
 b 
  c

Dup

>:@i.@# <@#"0 ]
>:@i.@#         Indices of each character plus one
      #          Length of the string
   i.            Range [0,length)
>:               Add one
        <@#"0 ] Duplicate each character as many times as it index (plus one)
           "0   For each
          #   ]  Copy the character
>:@i.@#           as many times as it index
        <        Box the result

The results are boxed to prevent J from padding the ends with spaces (since they're of uneven length).

Sample call:

   dup 'abc'
┌─┬──┬───┐
│a│bb│ccc│
└─┴──┴───┘

Space

(,' '&,)/&.>
         &.>  For each boxed element
(,' '&,)/      Insert spaces between each

Sample call:

   space dup 'abc'
┌─┬───┬─────┐
│a│b b│c c c│
└─┴───┴─────┘

Pad

|.@i.@# (>@],~' '#~[)"_1 ]
        (>@],~' '#~[)      Pad the right arg with spaces given by the left arg
|.@i.@#                    Indices in reverse order
   i. #                     Range [0,length)
|.                          Reverse

Basically, pad the first element with length - 1 spaces, the second with length - 2, etc. It also removes the boxing.

Sample call:

   pad space dup 'abc'
  a  
 b b 
c c c

Transpose

This is just the built-in function |: which takes the transpose of a matrix.

\$\endgroup\$
9
  • 1
    \$\begingroup\$ I used a similar approach, but avoided boxing. 45 bytes: |:@(-@i.@-@#|."0 1((,@,.~' '#~#)@$"0~1+i.@#)). it could surely be golfed further. this part -@i.@-@# is some low hanging fruit, most likely \$\endgroup\$
    – Jonah
    Aug 15, 2017 at 2:34
  • \$\begingroup\$ @Jonah I can't quickly decipher how your answer works, so I'll leave it to you to post it if you would like to, as I like to include an explanation of my answer. I guess J for me right now is a write-only language. \$\endgroup\$
    – cole
    Aug 15, 2017 at 3:01
  • \$\begingroup\$ helpful for quickly deciphering: f=. <some tacit expression>, then 5!:2 <'f'gives a boxed visualization and 5!:4 <'f' gives a tree visualization. in my case, try running $"0~1+i.@# with some string first, then run everything to the right of |."0 1, then understand that |."0 1 and everything to the left, save the final transpose, is just doing the necessary rotations. \$\endgroup\$
    – Jonah
    Aug 15, 2017 at 3:13
  • 1
    \$\begingroup\$ oh i wasn't expecting you to update your answer. it was more of a "hey, you might find this interesting." i could have posted it, but felt the high-level approaches were similar enough it wasn't worth it. \$\endgroup\$
    – Jonah
    Aug 15, 2017 at 3:21
  • 2
    \$\begingroup\$ Just remembered the complex arguments of # helps here, 26 bytes with |:@((-#)|."_1(1j1##)"0)~#\ \$\endgroup\$
    – miles
    Aug 15, 2017 at 10:59
1
\$\begingroup\$

JavaScript (ECMAScript 6), 161 bytes

(s,n=console.log)=>s.split("").map((q,i,a,p)=>n(p=" ".repeat(q=a.length-++i)+a.map((v,j)=>j>=q&&j%2==q%2?a[j]+' ':'').join(''))||p).reverse().map((v,i)=>i&&n(v))

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Perl 5, 86 + 2 (-F) = 88 bytes

Used @Dom's suggestions and a few of my own tweaks to lower the byte count.

for$k(0..$#F){$i=1;$a[$#F+$k]=$a[$#F-$k]=[map$i++<$k|($i+$k)%2?$":$_,@F]}say"@$_"for@a

Try it online!

\$\endgroup\$
4
  • \$\begingroup\$ Sorry about that, glad you got your answer out there though! Had a little bit of a play when I was trying to fix mine and coudnl't get a solution down, yours was a better approach! It is possible to drop a couple of bytes using -aF to put all the letters in @F and a couple of little tweaks (-F counts as 3 since it needs a space after): Try it online! \$\endgroup\$ Aug 18, 2017 at 4:46
  • 1
    \$\begingroup\$ Why does -F count as 3? Shouldn't it be 2 at the most? Isn't it the difference between perl -e'code...' and perl -eF 'code...'. Also -a is unnecessary when using -F, so that byte can be cut. \$\endgroup\$
    – Xcali
    Aug 18, 2017 at 5:06
  • \$\begingroup\$ That's it exactly. So -F accepts an argument, but we don't wanna pass one in (-F allows us to control what -a splits on, no argument, split each char on its own) so it's the difference between perl -ae '...' and perl -aF -e '...'. By default -a splits on /\s+/. Hope that helps clarify! \$\endgroup\$ Aug 18, 2017 at 5:42
  • \$\begingroup\$ Also, nice use of $#F! Always forget about that! \$\endgroup\$ Aug 18, 2017 at 5:43
0
\$\begingroup\$

q/kdb+, 55 bytes

Solution:

-1(+){{1_a,((2*y)#" ",z),a:x#" "}'[(|)c;1+c:(!)(#)x]x};

Example:

q)-1(+){{1_a,((2*y)#" ",z),a:x#" "}'[(|)c;1+c:(!)(#)x]x}"Hello World";
          d
         l
        r d
       o l
      W r d
       o l
    o W r d
   l   o l
  l o W r d
 e l   o l
H l o W r d
 e l   o l
  l o W r d
   l   o l
    o W r d
       o l
      W r d
       o l
        r d
         l
          d

Explanation:

TODO. ungolfed version is 66 bytes:

-1 flip{{1_a,((2*y)#" ",z),a:x#" "}'[reverse c;1+c:til count x]x};

Bonus:

To get the same output as the example (74 bytes):

q)-1(+){1_'raze{(a,((2*y)#" ",z),a:x#" ";(2*y+x)#" ")}'[(|)c;1+c:(!)(#)x]x}"Hello World";
                    d
                  l
                r   d
              o   l
            W   r   d
              o   l
        o   W   r   d
      l       o   l
    l   o   W   r   d
  e   l       o   l
H   l   o   W   r   d
  e   l       o   l
    l   o   W   r   d
      l       o   l
        o   W   r   d
              o   l
            W   r   d
              o   l
                r   d
                  l
                    d
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.