Asterisk spiral

29

1

Given the spiral of size S and the step N, output the "square" S*S spiral having N asterisks, built from the outer to inner radius clockwise.

Test cases (examples) below.

  1. Input: 4 3

    Output:

    ***
    
  2. Input: 4 6

    Output:

    ****
       *
       *
    
  3. Input: 4 11

    Output:

    ****
       *
    *  *
    ****
    
  4. Input: 6 18

    Output:

    ******
         *
         *
    *    *
    *    *
    ******
    
  5. Input: 6 22

    Output:

    ******
    ***  *
    *    *
    *    *
    *    *
    ******
    
  6. Input: 6 27

    Output:

    ******
    ******
    *   **
    *   **
    *   **
    ******
    
  7. Input: 1 1

    Output:

    *
    

It's not necessary to handle the cases when:

  • provided N asterisks can't "fit" in the spiral of given S*S dimensions.

  • either N or S is zero.

The challenge is code-golf, shortest bytes answer wins, any languages can be used.

Your output may have as many trailing (but not leading) spaces/newlines as you wish.

nicael

Posted 2018-04-01T15:24:57.523

Reputation: 4 585

Can we have trailing spaces/newlines? – user202729 – 2018-04-01T15:43:42.563

2I'd call S size (or at least diameter) rather than radius – Luis Mendo – 2018-04-01T15:58:53.410

@Luis fair point! – nicael – 2018-04-01T16:03:31.590

@LuisMendo Or side length. – Erik the Outgolfer – 2018-04-01T16:48:45.203

3Dear friends, please vote on answers also, not just question. It's easy to make this challenge. Providing an answer to it is (I think) definitely more difficult. – nicael – 2018-04-01T19:07:28.030

2Only you think so. Writing a well-received and clear challenge is very difficult. (just look at the comment thread right here, there are some suggestions after the challenge had been posted) – user202729 – 2018-04-02T02:18:44.493

related: https://codegolf.stackexchange.com/questions/89725/alphabet-spiral

– Titus – 2018-04-02T05:17:10.197

@Luis, lol, i havent noticed that instead of replacing the word radius with size, I replaced spiral with size xD funny that nobody else noticed – nicael – 2018-04-03T16:09:31.870

@nicael TBH I did, but I didn't want to be boring :-) – Luis Mendo – 2018-04-03T16:26:24.703

Answers

16

MATL, 17 16 bytes

UGlYLGoQ&P->42*c

Try it online!

Explanation (with example)

Consider inputs 4 and 11 as an example.

U       % Implicit input: S. Push S^2
        % STACK: 16
G       % Push S again
        % STACK: 16, 4
lYL     % Outward, clockwise, east-first spiral of that size
        % STACK: 16,
                 [ 7  8  9 10;
                   6  1  2 11;
                   5  4  3 12;
                  16 15 14 13]
GoQ     % Push S, compute parity, add 1. Gives 1 for even S, 2 for odd
        % STACK: 16,
                 [ 7  8  9 10;
                   6  1  2 11;
                   5  4  3 12;
                  16 15 14 13],
                 1
&P      % Flip along that dimension (1 is vertical, 2 is horizontal).
        % This corrects for the orientation of the spiral
        % STACK: 16,
                 [16 15 14 13;
                   5  4  3 12;
                   6  1  2 11;
                   7  8  9 10]
-       % Subtract, element-wise. The upper-left corner becomes 0
        % STACK: [ 0  1  2  3
                  11 12 13  4
                  10 15 14  5
                   9  8  7  6]
>       % Implicit input (below): N. Greater than?, element-wise.
        % This transforms the first N entries, starting from
        % upper-left, inward, east-first, into 1, and the rest
        % into 0
        % STACK: [1 1 1 1;
                  0 0 0 1;
                  1 0 0 1;
                  1 1 1 1]
42*     % Multiply each entry by 42
        % STACK: [42 42 42 42;
                   0  0  0 42;
                  42  0  0 42;
                  42 42 42 42]
c       % Convert to char. Char 0 will be displayed as space.
        % Implicit display
        % STACK: ['****';
                  '   *';
                  '*  *';
                  '****']

Luis Mendo

Posted 2018-04-01T15:24:57.523

Reputation: 87 464

1Wow, I was never good at golfing, but solve it with 17 bytes... That looks like magic :) (I know that possibly the shorter answers are coming, but you're first and here're my impressions :) – nicael – 2018-04-01T16:02:40.457

1Part of the job is done by a built-in spiral function. I just added an explanation – Luis Mendo – 2018-04-01T16:05:41.843

@nicael Welcome to the world of golfing languages aimed for specific purposes. :) – Erik the Outgolfer – 2018-04-01T17:59:38.677

3+1 for full example alongside the explanation – IanF1 – 2018-04-01T21:43:53.747

Why built-in... – user202729 – 2018-04-02T02:19:21.250

6

Stax, 19 bytes

±♪☺ÿzMæ¡♠à╣♂7☼V♀§9↓

Run and debug it

It starts by building a string that has all the characters in the result with all the asterisks left-aligned. Then it it takes increasingly large slices off the end of the string, and "wraps" them around a grid as it rotates the grid.

Here's the same program, unpacked, ungolfed, and commented.

'**     repeat "*" specified number of times
,J(     square the top of the input stack, and right-pad string to that length
z       push an empty array - this is the result grid built up in the loop
{       begin a block to loop
  ~     push grid to the input stack
  ihNv  push -(i / 2) - 1 where i is the 0-based iteration index using integer division
  :/]   split the string at that index and wrap the second half in a singleton array
  ,     pop the grid from the input stack
  rM+   rotate the grid clockwise, then prepend the split string as the new first row
  n     copy what's left of the original string to top of stack for the loop condition
w       while; execute block until condition is truthy
m       display resulting grid

Run and debug it

recursive

Posted 2018-04-01T15:24:57.523

Reputation: 8 616

2It inordinatly amuses me that on android this answer contains an orange blob smiley. – StarWeaver – 2018-04-01T21:19:00.330

@StarWeaver There are many answers in Stax that do so. – Weijun Zhou – 2018-04-02T09:27:24.637

I was really confused when I read the explanation and didn't see one. I just thought that Stax had a really weird code page! – ndm13 – 2018-04-02T17:03:56.030

@ndm13: I suppose it does have a weird code page. It's derived from CP437 which is a "real" encoding that has the same character in it. You should see the same smiling face if you follow that link on your phone.

– recursive – 2018-04-03T20:34:58.143

5

Python 2, 117 bytes

n,k=input()
i=0;d=1
l=(' '*n+'\n')*n
exec"l=l[:i]+'*'+l[i+1:];d=[~n/d*cmp(d*d,2),d][' '<l[i+d:]<'*'];i+=d;"*k
print l

Try it online!

xnor

Posted 2018-04-01T15:24:57.523

Reputation: 115 687

4

APL (Dyalog), 65 bytes

' *'[1+⎕>⊖∘⌽⍣o(⊖×⍨-,⍨⍴∘(⍋+\)×⍨↑(⌈2÷⍨×⍨),(+⍨⍴1,⊢,¯1,-)(/⍨)2/⍳)o←⎕]

Try it online!

The code for the spiral matrix is taken from another answer of mine.

Uriel

Posted 2018-04-01T15:24:57.523

Reputation: 11 708

Your code draws the spiral in the wrong direction if the N is odd :) – nicael – 2018-04-01T19:25:41.533

@nicael fixed (more like patched). thanks – Uriel – 2018-04-01T19:27:49.213

But... https://i.stack.imgur.com/gGJsS.png

– nicael – 2018-04-01T19:30:44.050

Maybe I'm using the input in the wrong way? – nicael – 2018-04-01T19:31:23.663

@nicael arghh. OK, I think its fine now. – Uriel – 2018-04-01T19:32:23.700

It is fine, indeed! – nicael – 2018-04-01T19:33:15.880

4

Python 2, 150 bytes

S,N=input()
X=y=n=0
Y=x=c=-1
s=eval(`[[' ']*S]*S`)
exec"if n%S<1:S-=c%2<1;X,Y=-Y,X;c+=1;n=0\nx+=X;y+=Y;s[y][x]='*';n+=1\n"*N
for i in s:print`i`[2::5]

Try it online!

Erik the Outgolfer

Posted 2018-04-01T15:24:57.523

Reputation: 38 134

4

PHP, 118 bytes

adjusted and golfed my solution for the Alphabet Spiral.

for($w=$n=$argv[$s=1],$r="*";--$argv[2];$r[$p+=$s*$d+$s]="*")if(!$c=++$c%$n)($d^=$w)?$n--:$s=-$s;echo wordwrap($r,$w);

Run with php -nr '<code>' <S> <N> or try it online.

Titus

Posted 2018-04-01T15:24:57.523

Reputation: 13 814

3

J, 60 56 Bytes

-4 Bytes by modifying the build proccess for the spiral so that subtracting it from y^2 was unnecessary

4 :'''* ''{~x<|."1|.(|:@|.,<:@{:@{:-i.@#)^:(+:<:y),.*:y'

Try it online!

Explanation coming soon now.

Explanation:

4 :'''* ''{~x<|."1|.(|:@|.,<:@{:@{:-i.@#)^:(+:<:y),.*:y'  | Explicit dyad definition
                    (|:@|.,<:@{:@{:-i.@#)^:(+:<:y),.*:y   | Generate a y by y inward spiral
                                                  ,.*:y   | The matrix [[y^2]]
                    (                   )^:(+:<:y)        | 2*(y-1) times...
                     |:@|.                                | Rotate
                          ,                               | Append
                                    i.@#                  | [0..len(n)-1]
                           <:@{:@{:-                      | Subtracted from the previous value and decremented
              |."1|.                                      | Flip around antidiagonal
            x>                                            | Test if each entry is less than x
    '' *''{~                                              | ' ' for 0, '*' for 1

Examples:

   3 :'(|:@|.,<:@{:@{:-i.@#)^:(+:<:y),.*:y' 4
7  8  9 10
6 15 16 11
5 14 13 12
4  3  2  1
   3 :'|."1|.(|:@|.,<:@{:@{:-i.@#)^:(+:<:y),.*:y' 4
1  2  3 4
12 13 14 5
11 16 15 6
10  9  8 7
   11(4 :'x<|."1|.(|:@|.,<:@{:@{:-i.@#)^:(+:<:y),.*:y') 4
0 0 0 0
1 1 1 0
0 1 1 0
0 0 0 0
   11(4 :'''* ''{~x<|."1|.(|:@|.,<:@{:@{:-i.@#)^:(+:<:y),.*:y') 4
****
   *
*  *
****

Bolce Bussiere

Posted 2018-04-01T15:24:57.523

Reputation: 970

May you also add a link to the executable example? – nicael – 2018-04-01T16:44:14.323

@nicael Added :) – Bolce Bussiere – 2018-04-01T17:05:26.893

3

Charcoal, 34 bytes

NθFE⮌E⊗N∨ι¹÷⁺鬬겫F‹θι≔θι×ι*≧⁻ιθ↷

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

Nθ

Input N.

FE⮌E⊗N∨ι¹÷⁺鬬겫

The lengths of the spiral arms (excluding corners) are S-1, S-1, S-1, S-2, S-2, S-3, ..., 3, 2, 2, 1, 1, 1. This is formed by starting with the range from 0 up to but excluding 2S, changing the 0 to 1, reversing it, adding 1 to each element after the first, and finally integer dividing all the elements by 2. This list is then looped over.

F‹θι≔θι

If there are fewer stars left to draw than the length of the next arm, reduce the arm to that length.

×ι*

Draw the appropriate number of stars.

≧⁻ιθ

Subtract from the number of stars remaining.

Rotate the drawing direction by 90° clockwise.

Neil

Posted 2018-04-01T15:24:57.523

Reputation: 95 035

2

Java 10, 284 282 281 263 bytes

s->n->{var c=new char[s][s];for(var d:c)java.util.Arrays.fill(d,' ');for(int i=0,j=0,y=0,x=1,u=s-1,l=0;n-->0;c[j][i]=42,i+=x,j+=y,l+=i==l&x==0?1:0,u-=i==l&j==l&y<1?1:0)if(x!=0){var b=x>0?i<u:i>l;y=b?0:x;x=b?x:0;}else{var b=y>0?j<u:j>l;x=b?0:-y;y=b?y:0;}return c;}

A fun challenge!

Try it online here.

Thanks to Kevin Cruijssen for golfing 18 bytes.

Ungolfed version:

s -> n -> { // lambda taking two integer arguments in currying syntax
    var c = new char[s][s]; // the matrix containing the spiral
    for(var d : c) // for every row
        java.util.Arrays.fill(d, ' '); // fill it with spaces
    for(int i = 0, j = 0, // the coordinates of the next '*'
            y = 0, x = 1, // the direction to move in
            u = s-1, l = 0; // the upper and lower bounds
        n-- > 0; // decrecement the length of the spiral and repeat as many times
        c[j][i] = 42, // draw the '*', 42 is ASCII code
        i += x, j += y, // move to the next cell
        l += i == l & x == 0 ? 1 : 0, // adjust lower bound if necessary
        u -= i == l & j == l & y < 1 ? 1 : 0) // adjust upper bound if necessary
        if(x != 0) { // if moving in x direction
            var b = x > 0 ? i < u : i > l; // if we hit the bounds
            y = b ? 0 : x; // flip directions,
            x = b ? x : 0; // turning around
        } else { // if moving in y direction
            var b = y > 0 ? j < u : j > l; // if we hit the bounds
            x = b ? 0 : -y; // flip directions,
            y = b ? y : 0;  // turning around
        }
    return c; // return the matrix
}

O.O.Balance

Posted 2018-04-01T15:24:57.523

Reputation: 1 499

263 bytes Last two loops are mainly changed, and a var b is added so you only have to do the x>0?i<u:i>l and y>0?j<u:j>l once each, instead of twice each. – Kevin Cruijssen – 2018-04-03T07:40:59.627

@KevinCruijssen great golf, thanks! – O.O.Balance – 2018-04-03T08:41:12.177

Suggest if(x>0?i<u:i>l)y=0;else{y=x;x=0;}else if(y>0?j<u:j>l)x=0;else{x=-y;y=0;} instead of {var b=x>0?i<u:i>l;y=b?0:x;x=b?x:0;}else{var b=y>0?j<u:j>l;x=b?0:-y;y=b?y:0;} – ceilingcat – 2019-12-07T01:29:00.330

2

Kotlin, 361 355 353 334 bytes

6 bytes saved thanks to Jonathan
2 bytes saved changing to when
19 bytes saved switching to lambda & tracking outer edges

{s:Int,n:Int->var a=Array(s,{_->Array(s,{_->' '})})
var r=0
var c=0
var d=0
var e=0
var f=1
var g=s-1
var h=g
for(i in 1..n){a[r][c]='*'
when(d){0->if(c<g)c++
else{d=1
r++
g--}
1->if(r<h)r++
else{d=2
c--
h--}
2->if(c>e)c--
else{d=3
r--
e++}
3->if(r>f)r--
else{d=0
c++
f++}}}
for(i in 0..s-1){for(j in 0..s-1)print(a[i][j])
println()}}

Try it online!

JohnWells

Posted 2018-04-01T15:24:57.523

Reputation: 611

1I'm not really sure how to try it since the input field is empty. – nicael – 2018-04-01T20:19:18.310

1

@nicael It's a function. this may be easier to use - the call is made in the footer.

– Jonathan Allan – 2018-04-01T20:32:18.750

1I don't know Kotlin much at all but believe ==' ' may be replaced by <'*'. Also d==0 with d<1 and d==3 with d>2. These seem like pretty fundamental golfs so there are probably others too! – Jonathan Allan – 2018-04-01T20:42:35.190

@nicael you can put two integers in input field, size on first line, number on second. – JohnWells – 2018-04-01T21:18:20.647

@jonathan thank you. Just starting out with Kotlin and golf so haven't figured out simple things like that as yet. – JohnWells – 2018-04-01T21:21:11.087

1@JohnWells indeed, it works. Somehow it's too slow, but it doesn't matter. – nicael – 2018-04-01T21:22:39.440

2

JavaScript (Node.js), 167 164 163 bytes

  • thanks to @Erik the Outgolfer and @nicael for spaces (3 bytes)
  • thanks to @micha for join``split, instead of map (1 byte)
(l,s)=>{a=(b=[...Array(l)]).map(x=>b.map(_=>" "))
for(d=1,x=y=D=0;s--;x+=d,y+=D)a[y][x]="*",(a[y+D]||[])[x+d]!=" "?[d,D]=[-D,d]:0
return a.join`
`.split`,`.join``}

Try it online!

DanielIndie

Posted 2018-04-01T15:24:57.523

Reputation: 1 220

1Nice, it works! Can you remove spaces/newlines to make it even shorter? – nicael – 2018-04-01T20:19:58.317

1

@nicael Looks like yes.

– Erik the Outgolfer – 2018-04-01T20:34:22.557

1Beautiful! If Kotlin and Java version would use the same method they would be a lot shorter! Such an elegant way of detecting when you hit the spiral or border and then turn the "turtle". Very clever! One byte less: change the return into return a.join\ `.split`,`.join```. – micha – 2018-04-04T10:38:14.390

@micha first of all thank you :). second a.join.split,.join`` doesnt output the spiral "nicely"(with new lines) so i think its a problem – DanielIndie – 2018-04-04T10:42:40.760

@DanielIndie, the newline got formatted away, first join should have a newline. See it

– micha – 2018-04-04T10:46:45.307