A nicely-spaced ASCII spiral

13

1

Consider this spiral

###########
#
# #######
# #     #
# # ### #
# # # # #
# # # # #
# #   # #
# ##### #
#       #
#########

Starting in the centre:

  • The first line (upwards) has 3 characters.
  • The second line has the same number of characters (3)
  • Next, we add two chars (5) for the next two sides.
  • This pattern continues, two sides the same length then increase the length by 2.

I want to generate this spiral for N lines.

  • Write in any language.
  • The input/argument, etc. is the number of lines in your spiral.
  • Each line starts with the ending character of the previous line in the direction 90 degrees clockwise of the previous line.
  • I don't care how much whitespace is before or after each line, as long as the elements of the spiral line up.
  • Output text to draw the spiral with any non-whitespace character you choose.
  • Attempt to do this in the smallest number of bytes.

Test cases (using a hash as output):

N = 1

#
#
#

N = 2

###
#
#

N = 3

###
# #
# #
  #
  #

N = 10

###########
#
# #######
# #     #
# # ### #
# # # # #
# # # # #
# #   # #
# ##### #
#       #
#########

AJFaraday

Posted 7 years ago

Reputation: 10 466

@Shaggy "Output text to draw the spiral with any non-whitespace character you choose." Yep, whatever you like. – AJFaraday – 7 years ago

3Related 1; Related 2. – Kevin Cruijssen – 7 years ago

3The initial image has an * instead of #. Expected? – Wernisch – 7 years ago

@Wernisch It was intended to be a helpful starting point, but I suppose it's misleading. You can use any character you like. – AJFaraday – 7 years ago

Answers

11

05AB1E, 13 11 bytes

Code:

Thanks to Emigna for saving two bytes!

LDÈ-Ì'#3Ý·Λ

Uses the 05AB1E encoding. Try it online!

Explanation

The lengths of each individual edge on the spiral starts with length 3 and gradually increases every two steps by two:

3,3,5,5,7,7,9,

For a spiral with $n$ edges, we just need to trim this list to size $n$. This is done with the following piece of code:

L                # Create a list from [1 .. input]
 DÈ              # Duplicate and check for each number if even
   -             # Subtract that from the first list
    Ì            # Add 2

This basically gives us the desired list of lengths.

     '#          # Push the '#' character
       0246S     # Push the array [0, 2, 4, 6]
            Λ    # Write to canvas

The canvas works as a function that pops three parameters (where the rightmost parameter is popped first): <length(s)>, <char(s)>, <direction(s)>. The directions parameter is in this case a list of numbers. The numbers that correspond to the directions are:

[70162543]

In this case, [0, 2, 4, 6] corresponds to the directions list [↑, →, ↓, ←]. The canvas iterates over each length retrieved from the list of lengths, uses the '#' character and cyclically iterates over the directions list.

Adnan

Posted 7 years ago

Reputation: 41 965

0246S = 3Ý· – Emigna – 7 years ago

@Emigna Ah I did not think of that, thanks! – Adnan – 7 years ago

6

Python 2, 176 170 165 161 157 bytes

g=lambda a,r:r and g(map(''.join,zip(*a))[::-1],r-1)or a
R=['#']
n=1
exec"R=g(['  '+l for l in g(R,n)][:-1]+[(n+2)*'#'],3*n);n+=1;"*input()
print'\n'.join(R)

Try it online!

Repeatedly: Uses g to rotate the nth iteration of the spiral into a 'canonical' position (similar to N=3 or N=7), adds a new segment by adding 2 spaces at the left of each existing row, then replacing the last row with all '#'s (resulting in a position comparable to N=4 or N=8), and finally using g again to rotate it back to the correct position. Lather, rinse, repeat.

Chas Brown

Posted 7 years ago

Reputation: 8 959

4

Charcoal, 16 15 14 bytes

↶FN«¶×#⁺³⊗÷ι²↷

-2 bytes thanks to @Neil.

Try it online (verbose) or Try it online (pure).

Explanation:

Printing direction is to the right by default, and we want to start upwards, so we start by rotating 45 degrees counterclockwise:

PivotLeft();
↶

Then loop i in the range [0, input):

For(InputNumber()){ ... }
FN« ...

Print a new-line to mimic the effect of moving back one position:

Print("\n");
¶

Print "#" x amount of times in the current direction:

Print(Times("#", ... ));
×# ...

Where x is: 3 + i // 2 * 2:

Add(3,Doubled(IntegerDivide(i,2))
⁺³⊗÷ι²

And then rotate 45 degrees clockwise for the next iteration of the loop:

PivotRight();
↷

Kevin Cruijssen

Posted 7 years ago

Reputation: 67 575

I assume there's no command in Charcoal for moving backwards? – Emigna – 7 years ago

@Emigna Not sure, but I couldn't find it either. Was indeed looking for one myself when I was writing this answer. There is a Move with a given direction, as well as a Jump with given coordinates, but not a MoveBack unfortunately. – Kevin Cruijssen – 7 years ago

1⊗÷ι² is a byte shorter than ⁻ι﹪ι². Also, you can get the effect of moving back by printing a \n before the #s, which will allow you to remove the »# for an additional overall byte saving. – Neil – 7 years ago

@Neil Thanks for the ⊗÷ι², but what would the changes be for printing a \n before the #s? The spiral is incorrect if I add the Print("\n").

– Kevin Cruijssen – 7 years ago

Because the arms now overlap you need to make them an extra # longer. – Neil – 7 years ago

3

Python 2, 179 178 bytes

thanks to Kevin Cruijssen for -1 byte.

n=input()
S,H=' #'
m=[S*n]*(n%2-~n)
x=n/4*2
y=0--n/4*2
k=2
m[y]=S*x+H+S*n
M=[1,0,-1,0]*n
exec'exec k/2*2*"x+=M[~k];y+=M[k];m[y]=m[y][:x]+H+m[y][x+1:];";k+=1;'*n
print'\n'.join(m)

Try it online!


Python 2, 179 bytes

In this approach formulas are used for x and y deltas instead of a lookup list.

n=input()
S,H=' #'
m=[S*n]*(n%2-~n)
x=n/4*2
y=0--n/4*2
k=2
m[y]=S*x+H+S*n
exec'exec k/2*2*"x+=k%-2+k%4/3*2;y-=(k%2or k%4)-1;m[y]=m[y][:x]+H+m[y][x+1:];";k+=1;'*n
print'\n'.join(m)

Try it online!

ovs

Posted 7 years ago

Reputation: 21 408

n+1+n%2 to n%2-~n for -1 byte. And I need to remember 0--n/4*2 being 1 shorter than -(-n/4*2). Nice answer, +1 from me. – Kevin Cruijssen – 7 years ago

1

JavaScript (ES6), 185 bytes

Sure this can be golfed more, maybe with currying, but here's my very humble attempt. Line breaks added for readability except penultimate character

r=(a,n=1)=>n?r(a.reduce((_,c)=>c).map((_,i)=>a.map(e=>e[i])).reverse(),n-1):a,
s=n=>n?r(s(n-1)).map((r,i)=>[...r,w,w].map(x=>i?x:'#')):[[w=' ']],
d=n=>r(s(n),1-i).map(r=>r.join``).join`
`

Usage: d(10) returns a string as per the N=10 challenge example.

Defines a function r(a,n) to rotate an array a by n turns; a function s(n) to generate a 2-dimensional array representing a spiral of size n by recursively rotating and adding spacing and lines (not rotated back to starting position); and a function d(n) to draw a spiral of size n, rotated consistently as per the challenge, and rendered as a returned string.

This was a really fun challenge :¬)

Chris M

Posted 7 years ago

Reputation: 191