13
\$\begingroup\$

Look at the following string. Notice a pattern?

ABEFNOPEFGH
DC G  Q   I
M  H  R   J
LKJI  S   K
D     T   L
C     U   M
BAZYXWV   N
E         O
D         P
C         Q
BAZYXWVUTSR

As some might have noticed, it's basically a spiral of the alphabet, where the distances between rows / columns are gradually increasing by 1 space / newline.

Rigorous definition

  • Let's have a counter c, which is initially 0.
  • We write out the first c + 1 letters of the alphabet from left to right: A.
  • Then, from top to bottom the next (c + 1)(c + 2)/2 letters (add B): AB.

  • From left to right, the next (c + 1)(c + 2)/2 (add C):

    AB
     C
    
  • And from bottom to top, the next c + 1 letters (add D):

    AB
    DC
    
  • Reached the end of the cycle. Hence, let's increment c (which becomes 1). Then, it starts back from the first step, the only difference being that instead of using the first c + 1 letters of the alphabet, we use the next c + 1 letters, starting from the last element of this cycle (D in this case, so we continue with EFG...). When Z is reached, it cycles back from A.

Task

Given an integer N (which is positive for 1-indexing or non-negative for 0-indexing), output the first N cycles of the spiral.

Rules

  • You can either use the lowercase or the uppercase alphabet, but your choice must be consistent (only use one of them, mixing is not allowed).

  • You can take input and provide output through any of the standard methods, in any programming language, while noting that these loopholes are forbidden by default.

  • Acceptable output formats: multiline string, a list of strings representing lines, a list containing multiple lists of characters, each representing one line, or anything else you find suitable. In case you don't choose the first format, it would be nice to include a pretty-print version of your code.

  • This is , so the shortest code in bytes (in each language) which fulfils the requirements wins!


Test cases

The input integer will be separated by its corresponding output through a newline, and the tests will be separated using dashes. Note that these are 1-indexed.

1

AB
DC

--------

2

ABEF
DC G
M  H
LKJI 

--------

3

ABEFNOP
DC G  Q
M  H  R
LKJI  S
D     T
C     U
BAZYXWV

-------

4

ABEFNOPEFGH
DC G  Q   I
M  H  R   J
LKJI  S   K
D     T   L
C     U   M
BAZYXWV   N
E         O
D         P
C         Q
BAZYXWVUTSR

-------
5

ABEFNOPEFGHFGHIJ
DC G  Q   I    K
M  H  R   J    L
LKJI  S   K    M
D     T   L    N
C     U   M    O
BAZYXWV   N    P
E         O    Q
D         P    R
C         Q    S
BAZYXWVUTSR    T
R              U
Q              V
P              W
O              X
NMLKJIHGFEDCBAZY

------

6

ABEFNOPEFGHFGHIJSTUVWX
DC G  Q   I    K     Y
M  H  R   J    L     Z
LKJI  S   K    M     A
D     T   L    N     B
C     U   M    O     C
BAZYXWV   N    P     D
E         O    Q     E
D         P    R     F
C         Q    S     G
BAZYXWVUTSR    T     H
R              U     I
Q              V     J
P              W     K
O              X     L
NMLKJIHGFEDCBAZY     M
S                    N
R                    O
Q                    P
P                    Q
O                    R 
NMLKJIHGFEDCBAZYXWVUTS
\$\endgroup\$
  • \$\begingroup\$ The testcases should be n=1,2,3,5,6, I think. \$\endgroup\$ – TFeld Dec 1 '17 at 10:22
9
\$\begingroup\$

Charcoal, 31 bytes

F⮌…⁰NB⁺²⊘×ι⁺³ι⭆α§α⁺λ÷×ι⊕×ι⁺⁹⊗ι⁶

Try it online! Link is to verbose version of code. Note: The deverbosifier outputs a trailing separator for some reason. Explanation:

F⮌…⁰NB

Draw boxes in reverse order of size (largest to smallest).

⁺²⊘×ι⁺³ι

Calculate the size of the box.

⭆α§α⁺λ

Draw the border of the box using a rotated alphabet.

÷×ι⊕×ι⁺⁹⊗ι⁶

Calculate the letter that would appear at the top left of the box (0-indexed).

\$\endgroup\$
6
\$\begingroup\$

Python 2, 176 bytes

n=input()
k=n*-~n/2+1
a=eval(`[[' ']*k]*k`)
x=y=z=0
for s in range(4*n+4):exec s/4*(s/4+1)/2*"if'!'>a[y][x]:a[y][x]=chr(z%26+65);z+=1\nx+=abs(2-s%4)-1;y+=s%2-s%4/3*2\n"
print a

Try it online!

Explanation

We construct an empty array of spaces of the right size, then move over it like this, starting in the top-left corner:

  • 1 step →, 1 step ↓, 1 step ←, 1 step ↑

  • 3 steps →, 3 steps ↓, 3 steps ←, 3 steps ↑

  • 6 steps →, 6 steps ↓, 6 steps ←, 6 steps ↑

  • 10 steps →, 10 steps ↓, 10 steps ←, 10 steps ↑

Every time we find a blank cell, we put a letter there and cycle to the next letter in the alphabet.

In the code, s%4 is the direction (→↓←↑), and we step this many times:

TriangularNumber(s/4) = s/4*(s/4+1)/2.

Golf opportunities

  • Is there a shorter way to map s%4 to 1,0,-1,0 than abs(2-s%4)-1?

  • Is there a shorter way to map s%4 to 0,1,0,-1 than s%2-s%4/3*2?

Credits

  • Mr. Xcoder saved a byte.
\$\endgroup\$
  • 2
    \$\begingroup\$ +1 Wow, this is just brilliant. Took me a while to figure out how it works. I found a shorthand for 21/(s%4+3)%3-1: s%2-2*(s%4>2) (179 bytes). It might still be golfable though \$\endgroup\$ – Mr. Xcoder Dec 1 '17 at 15:39
4
\$\begingroup\$

C,  305  281 bytes

Thanks to @Mr. Xcoder for saving four bytes!

#define L(x,y)l[x][y]=a++%26+65;
#define F for(
c,i,j,a,p;f(n){char**l=calloc(8,i=a=n*n*4);F;i--;memset(l[i],32,a))l[i]=malloc(a);F c=a=p=i=0;c<n;++c){F i=p;i<c+p+!c;)L(j=0,c+i++)F p=i;j<=-~c*(c+2)/2;)L(j++,c+i)F;c+i-1;)L(j-1,c+--i)F i=0;i<=c;)L(j+~i++,0)}F i=0;i<j;)puts(l[i++]);}

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ First time I see a #define for for( (that actually saves bytes). +1 from me. :) \$\endgroup\$ – Kevin Cruijssen Dec 1 '17 at 15:01
2
\$\begingroup\$

Python 2, 262 260 254 245 bytes

lambda n:[[[' ',chr(65+(4*(i<j)+sum((i<j)*8+2+I*[5,9][i<j]+sum(2*R(I))for I in R(S(i,j)-1))+[i+j,-i-j][i<j])%26)][max(i,j)==S(i,j)*-~S(i,j)/2or i*j<1]for i in R(1+n*-~n/2)]for j in R(1+n*-~n/2)]
R=range
S=lambda x,y:int((8*max(x,y)+1)**.5+.99)/2

Try it online!

New method with more maths!

Returns a list of char-lists.


Old version:

Python 2, 322 321 308 298 bytes

R=range
n=input()
w=1+n*-~n/2;r=[w*[' ']for _ in R(w)];r[0][0]='A';l=R(1,w*w*9);c=lambda:chr(65+l.pop(0)%26)
for i in R(n+1):
 w=1+i*-~i/2;W=w-i
 for x in R(W,w):r[0][x]=c()
 for y in R(1,w):r[y][w-1]=c()
 for x in R(1,w):r[w-1][w+~x]=c()
 for x in R(1,w-W):r[w+~x][0]=c()
for l in r:print`l`[2::5]

Try it online!

\$\endgroup\$
  • \$\begingroup\$ @Mr.Xcoder Isn't just .49 sufficient enough in that case, or does it fail for very big inputs? \$\endgroup\$ – Kevin Cruijssen Dec 1 '17 at 14:40
  • 1
    \$\begingroup\$ @KevinCruijssen Not sure, but this works for sure, 260 bytes. \$\endgroup\$ – Mr. Xcoder Dec 1 '17 at 14:42
  • \$\begingroup\$ I don't know Python that well, but is it possible to make an inline-variable for i<j, since you are using it four times? \$\endgroup\$ – Kevin Cruijssen Dec 1 '17 at 14:48
  • 1
    \$\begingroup\$ 245 bytes by golfing +1==1+ from my previous method \$\endgroup\$ – Mr. Xcoder Dec 1 '17 at 14:56
1
\$\begingroup\$

Perl 5, 177 +2 (-nl) = 179 bytes

2 bytes saved thanks to Xcali

sub n{chr 65+$c++%26}@O=(n);while($,++<$_){$_.=$"x$,for@O;push@O,($"x length$O[0])x$,;$O[0]=~s/ /n/eg;s/ $/n/e for@O;1while$O[-1]=~s/.*\K /n/e;s/^ /n/e for reverse@O}print for@O

Try it online

\$\endgroup\$
  • \$\begingroup\$ You can save a byte by using -1 instead of $#O. Also using $, instead of $n will let you remove the space before for in $_.=$"x$n for@O \$\endgroup\$ – Xcali Dec 1 '17 at 16:34
  • \$\begingroup\$ thank you, i was looking for other improvements but could not find for the moment \$\endgroup\$ – Nahuel Fouilleul Dec 1 '17 at 16:45
  • \$\begingroup\$ saved 2 more bytes changing regex s/ (?=\S)/n/e to s/.*\K /n/e \$\endgroup\$ – Nahuel Fouilleul Dec 1 '17 at 16:49
0
\$\begingroup\$

APL (Dyalog Classic), 47 bytes

(⎕a⍴⍨≢i)@i⍴∘''⊃⌈/i←∪+\↓1⍪⊃⍪⌿(+\⍳⎕)⌿¨⊂⍪∘-⍨∘.≠⍨⍳2

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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