Spiralize a Word, Triangularly!

Wolfram Language (Mathematica), 99 bytes

sPrint@@@Array[s[[4# #-2#+1-#2&@@If[Abs@#2<2#,!##,#-Abs@#2|-#2]]]/._@__->" "&,2{L=Tr[1^s],L},-L]

Try it online!

Directly computes the index of each position: in Cartesian coordinates, \$\operatorname{index}(x,y)=\textit{offset}+\begin{cases}2y(2y+1)-x,&|x|<-2y\\ 2\left(y+|x|\right)\left(2\left(y+|x|\right)+1\right)+x,&\text{else}\end{cases}\$

where \$\textit{offset}\$ is the index of the "first" character (1, in Mathematica).

Takes a list of characters as input.


Older approach, 123 122 109 107 bytes

Print@@@Normal@SparseArray[i=0;p=2Length@#;(p+=ReIm[I[2+I,1-I][[⌈2√i++⌉~Mod~4-1]]-1])->#&/@#,2p," "]&

Try it online!

The direction of the (1-indexed) ith character relative to the previous character can be computed with \$\Big\lceil2\sqrt i\Big\rceil\bmod 4\$:

  • 1: ↗
  • 2: ↘
  • 3,0: ←

Charcoal, 37 36 21 bytes

GH✳✳E⊖LθI§4174⌈⊗₂⊕ι²θ

Try it online! No verbose link because the deverbosifier outputs ✳σ instead of ✳✳, generating invalid succinct code that doesn't execute correctly, but if it did work then it would be PolygonHollow(Directions(Map(Decremented(Length(q)), Cast(AtIndex("4174", Ceiling(Doubled(SquareRoot(Incremented(i)))))))), 2, q);. Inspired by @KevinCruijssen's 05AB1E solution, but then using @att's formula to generate the directions. Explanation:

       θ                Input string
      L                 Length
     ⊖                  Decremented
    E                   Map over implicit range
                  ι     Current index (0-indexed)
                 ⊕      Incremented (i.e. 1-indexed)
                ₂       Square rooted
               ⊗        Doubled
              ⌈         Ceiling
         §4174          Cyclically index to find direction
        I               Cast to integer
  ✳✳                    Convert to directions
GH                 ²θ   Draw path using input string

The path drawing command draws one character for the start and then n-1 characters for each direction in the array. Unfortunately there aren't any single character strings that represent diagonal directions so I have to use integers instead; these start at 0 for right and increment for each 45° clockwise.

Previous 37 byte solution:

≔⮌⪪S¹θFLθF³F§⟦⊕⊗ι⁺³×⁴ι⊗⊕ι⟧κ¿θ✳⁻⁷׳κ⊟θ

Try it online! Link is to verbose version of code. Explanation:

≔⮌⪪S¹θ

Split the input into characters and reverse the list.

FLθ

Loop a large enough number of times.

F³

Loop for each side of the triangle.

F§⟦⊕⊗ι⁺³×⁴ι⊗⊕ι⟧κ

Loop for the size of the side.

¿θ

Check whether there is still anything left to print.

✳⁻⁷׳κ⊟θ

Print the next character in the appropriate direction.


05AB1E, 24 20 15 13 bytes

2Iā¨t·îŽOGsèΛ

-7 bytes by porting @Neil's Charcoal answer, using @att's formula, so make sure to upvote both of them as well!

Try it online. No test suite, because the builtin will keep its previous contents and there isn't any way to reset it (this is what it would look like.

Explanation:

2              # Push a 2
 I             # Push the input-string
  ā            # Push a list in the range [1,length] (without popping)
   ¨           # Remove the last value to change the range to [1,length)
    t          # Take the square-root of each value
     ·         # Double each
      î        # Ceil each
       ŽOG     # Push compressed integer 6136
          s    # Swap so the list is at the top of the stack again
           è   # Index each value (0-based and modulair) into the 6136
            Λ  # Pop all three and use the Canvas builtin,
               # after which the result is implicitly output immediately afterwards

See this 05AB1E tip of mine (section How to compress large integers?) to understand why ŽOG is 6136.

The Canvas builtin uses three arguments to draw a shape:

  • Character/string to draw: the input in this case
  • Length of the lines we'll draw: 2 in this case
  • The direction to draw in: [3,6,6,6,1,1,3,3,3,6,6,6,6,6,6,6,1,1,1,1,3,...].

See the original answer below for an explanation of the Canvas builtin. Unlike the program below where the list of lengths are leading, here the list of directions are leading because we use a single length of 2.


Original 24 20 bytes answer:

ā·Ð·s>ø.ι˜DŠOð׫₆1ªΛ

Contains leading/trailing spaces and newlines (the longer the input, the more spaces/newlines)

Try it online. No test suite, because the builtin will keep its previous contents and there isn't any way to reset it (this is what it would look like, where the test cases are drawn on top of one another).

Explanation:

ā           # Push a list in the range [1, length] of the (implicit) input (without popping)
            #  i.e. "Hello World!" → "Hello World!" and [1,2,3,4,5,6,7,8,9,10,11,12]
 ·          # Double each value in this list
            #  → [2,4,6,8,10,12,14,16,18,20,22,24]
  Ð         # Triplicate it
   ·        # Double each value of the top copy
            #  → [4,8,12,16,20,24,28,32,36,40,44,48]
    s       # Swap to get the other copy
     >      # Increase each by 1
            #  → [3,5,6,9,11,13,15,17,19,21,23,25]
      ø     # Create pairs of the top two lists
            #  → [[4,3],[8,5],[12,7],[16,9],[20,11],[24,13],[28,15],[32,17],[36,19],[40,21],[44,23],[48,25]]
       .ι   # Interleave it with the third list
            #  → [2,[4,3],4,[8,5],6,[12,7],8,[16,9],10,[20,11],12,[24,13],14,[28,15],16,[32,17],18,[36,19],20,[40,21],22,[44,23],24,[48,25]]
         ˜  # Flatten
            #  → [2,4,3,4,8,5,6,12,7,8,16,9,10,20,11,12,24,13,14,28,15,16,32,17,18,36,19,20,40,21,22,44,23,24,48,25]
D           # Duplicate this list of integers
 Š          # Triple-swap, so the stack order is list,input,list
  O         # Pop and sum the top list
            #  → 636
   ð×       # Create a string of that many spaces
     «      # And append it to the string
₆           # Push builtin 36
 1ª         # Convert it to a list of digits, and append 1: [3,6,1]
Λ           # Use the Canvas builtin with these three arguments,
            # after which the result is implicitly output immediately afterwards

The Canvas builtin uses three arguments to draw a shape:

  • Character/string to draw: the input in this case, appended with trailing spaces
  • Length of the lines we'll draw: the list [2,4,3,4,8,5,6,12,7,8,16,9,10,20,11,...]
  • The direction to draw in: [3,6,1]. The digits in the range \$[0,7]\$ each represent a certain direction:
7   0   1
  ↖ ↑ ↗
6 ← X → 2
  ↙ ↓ ↘
5   4   3

So the [3,6,1] in this case translate to the directions \$[↘,←,↗]\$.

Here a step-by-step explanation of the output (we'll use input "Hello_World!" as example here):

Step 1: Draw 2 characters ("He") in direction 3↘:

H
 e

Step 2: Draw 4-1 characters ("llo") in direction 6←:

  H
olle

Step 3: Draw 3-1 characters ("_W") in direction 1↗:

  W
 _H
olle

Step 4: Draw 4-1 characters ("orl") in direction 3↘:

  W
 _Ho
oller
     l

Step 5: Draw 8-1 characters ("d! ") in direction 6←:

   W
  _Ho
 oller
    !dl

Et cetera for all other trailing spaces.

See this 05AB1E tip of mine for an in-depth explanation of the Canvas builtin.