Намовай мені змію!


34

З огляду на , вхід цілого числа n, намалювати змію числа, тобто, сітка вимірювання , n x nщо складаються з чисел 1через n^2які намотані навколо один одного в наступному вигляді:

Вхід n = 3:

7 8 9
6 1 2
5 4 3

Вхід n = 4:

 7  8  9 10
 6  1  2 11
 5  4  3 12
16 15 14 13

Вхід n = 5:

21 22 23 24 25
20  7  8  9 10
19  6  1  2 11
18  5  4  3 12
17 16 15 14 13

(Натхненна цією проблемою від Project Euler.)

Це , найкоротша відповідь у байтах виграє!


4
Приклад 4:? Або будь-яке парне число.
TheLethalCoder

1
Чи можемо ми вважати, що вхід непарний?
Містер Xcoder



1
Дивіться також perlmonks.com/?node_id=487200 з багатьма рішеннями та посиланнями у відповідях.
b_jonas

Відповіді:



18

C#, 203 202 196 193 178 bytes

n=>{var r=new int[n,n];for(int o=n-2+n%2>>1,i=r[o,o]=1,c=2,w=o,h=o,b=1-2*(i%2),j;n>i++;){r[h,w+=b]=c++;for(j=0;j<i-1;++j)r[h+=b,w]=c++;for(j=0;j<i-1;++j)r[h,w-=b]=c++;}return r;}

Saved a byte thanks to @StefanDelport.
Saved 22 bytes thanks to @FelipeNardiBatista.

This works by the following observation of how the squares are built up:

Image of square where n=5

As you can see each bit is added on to the previous square. For even numbers we go right of where we were, down till were one lower than where the square was and then left to the end. Odd numbers are essentially the opposite, we go left one, up till were one above the current height and then right to the end.

Full/Formatted version:

using System;
using System.Linq;

class P
{
    static void Main()
    {
        Func<int, int[,]> f = n =>
        {
            var r = new int[n, n];
            for (int o = n - 2 + n % 2 >> 1, i = r[o, o] = 1, c = 2, w = o, h = o, b = 1 - 2 * (i % 2), j; n > i++;)
            {
                r[h, w += b] = c++;

                for (j = 0; j < i - 1; ++j)
                    r[h += b, w] = c++;

                for (j = 0; j < i - 1; ++j)
                    r[h, w -= b] = c++;
            }

            return r;
        };

        Console.WriteLine(String.Join("\n", f(3).ToJagged().Select(line => String.Join(" ", line.Select(l => (l + "").PadLeft(2))))) + "\n");
        Console.WriteLine(String.Join("\n", f(4).ToJagged().Select(line => String.Join(" ", line.Select(l => (l + "").PadLeft(2))))) + "\n");
        Console.WriteLine(String.Join("\n", f(5).ToJagged().Select(line => String.Join(" ", line.Select(l => (l + "").PadLeft(2))))) + "\n");

        Console.ReadLine();
    }
}

public static class ArrayExtensions
{
    public static T[][] ToJagged<T>(this T[,] value)
    {
        T[][] result = new T[value.GetLength(0)][];

        for (int i = 0; i < value.GetLength(0); ++i)
            result[i] = new T[value.GetLength(1)];

        for (int i = 0; i < value.GetLength(0); ++i)
            for (int j = 0; j < value.GetLength(1); ++j)
                result[i][j] = value[i, j];

        return result;
    }
}

1
++i<=n; can become n>++i, nothing else I can see, +1.
LiefdeWen

1
n%2<1?2:1 to 2-x%2 ? I haven't tested it in C#, but in C and Python it worked.
Felipe Nardi Batista

1
for(int o=n-2+n%2>>1,i=r[o,o]=1,c=2,w=o,h=o,j;n>i++;){var b=i%2<1; .... golfed a bit
Felipe Nardi Batista

@FelipeNardiBatista Awesome would never have thought of those two! Thanks.
TheLethalCoder

1
var b=1-2*(i%2);r[h,w+=b]=c++;for(j=0;j<i-1;++j)r[h+=b,w]=c++;for(j=0;j<i-1;++j)r[h,w-=b]=c++;
Felipe Nardi Batista

15

Dyalog APL, 70 56 45 41 bytes

,⍨⍴∘(⍋+\)×⍨↑(⌈2÷⍨×⍨),(+⍨⍴1,⊢,¯1,-)(/⍨)2/⍳

Try it online!

How?

(+⍨⍴1,⊢,¯1,-)(/⍨)2/⍳

calculates the differences between the indices; 1 and ¯1 for right and left, ¯⍵ and for up and down.

1,⊢,¯1,- comes as 1 ⍵ ¯1 ¯⍵, +⍨⍴ stretches this array to the length of ⍵×2, so the final 2/⍳ can repeat each of them, with a repetition count increasing every second element:

      (1,⊢,¯1,-) 4
1 4 ¯1 ¯4
      (+⍨⍴1,⊢,¯1,-) 4
1 4 ¯1 ¯4 1 4 ¯1 ¯4
      (2/⍳) 4
1 1 2 2 3 3 4 4
      ((+⍨⍴1,⊢,¯1,-)(/⍨)2/⍳) 4
1 4 ¯1 ¯1 ¯4 ¯4 1 1 1 4 4 4 ¯1 ¯1 ¯1 ¯1 ¯4 ¯4 ¯4 ¯4

then,

(⌈2÷⍨×⍨),

prepends the top-left element of the spiral,

×⍨↑

limit the first ⍵2 elements of this distances list,

+\

performs cumulative sum,

grades up the indices (⍵[i] = ⍵[⍵[i]]), to translate the original matrix with the indices of every element, and finally

,⍨⍴

shapes as a ⍵×⍵ matrix.


For those interested, this technique is discussed at length in this excellent article.
Jonah

9

C, 321 307 295 284 283 282 bytes

Thanks to both @Zachary T and @Jonathan Frech for golfing a byte!

#define F for(b=a;b--;)l
i,j,k,a,b,m;**l;f(n){n*=n;l=calloc(a=m=3*n,4);F[b]=calloc(m,4);for(l[i=j=n][j]=a=k=1;n>k;++a){F[i][++j]=++k;F[++i][j]=++k;++a;F[i][--j]=++k;F[--i][j]=++k;}for(i=0;i<m;++i,k&&puts(""))for(j=k=0;j<m;)(a=l[i][j++])>0&&a<=n&&printf("%*d ",(int)log10(n)+1,k=a);}

Allocates a two-dimensional array of zeroes, then starts filling it from somewhere in the middle. Lastly the values that are larger than zero but smaller than or equal to the square of the input are printed.

Try it online!

Formatted:

#define F for(b=a; b--;)l
i, j, k, a, b, m; **l;
f(n)
{
    n *= n;
    l = calloc(a=m=3*n, 4);

    F[b] = calloc(m, 4);

    for(l[i=j=n][j]=a=k=1; n>k; ++a)
    {
        F[i][++j] = ++k;
        F[++i][j] = ++k;
        ++a;

        F[i][--j] = ++k;
        F[--i][j] = ++k;
    }

    for(i=0; i<m; ++i, k&&puts(""))
        for(j=k=0; j<m;)
            (a=l[i][j++])>0 && a<=n && printf("%*d ", (int)log10(n)+1, k=a);
}

1
Is it possible to replace i,j,k,a,b,m;f(n){n*=n;int**l=calloc(a=m=3*n,4); with i,j,k,a,b,m,**l;f(n){n*=n;l=calloc(a=m=3*n,4); to save a byte?
Zacharý

1
You may be able to replace k<=n; with n>k; to save a byte.
Jonathan Frech

6

PHP, 192 bytes

for($l=strlen($q=($a=$argn)**2)+$d=1,$x=$y=$a/2^$w=0;$i++<$q;${yx[$w%2]}+=$d&1?:-1,$i%$d?:$d+=$w++&1)$e[$x-!($a&1)][$y]=sprintf("%$l".d,$i);for(;$k<$a;print join($o)."\n")ksort($o=&$e[+$k++]);

Try it online!

Same way build a string instead of an array

PHP, 217 bytes

for($l=strlen($q=($a=$argn)**2)+$d=1,$x=$y=($a/2^$w=0)-!($a&1),$s=str_pad(_,$q*$l);$i++<$q;${yx[$w%2]}+=$d&1?:-1,$i%$d?:$d+=$w++&1)$s=substr_replace($s,sprintf("%$l".d,$i),($x*$a+$y)*$l,$l);echo chunk_split($s,$a*$l);

Try it online!


1
[-1,1][$d&1] --> $d&1?:-1
Titus

@Titus Thank You I have not see it
Jörg Hülsermann

1
Here is one more byte: for(;$k<$a;print join($o)."\n")ksort($o=&$e[+$k++]);. And another one: "%$l".d. And one more: $x*$l*$a+$y*$l --> ($x*$a+$y)*$l.
Titus

1
And I think that in the second version You can initialize $s to a padded underscore (or letter or digit); that character will be overwritten.
Titus

@Titus Thank You and you can use the .d in your own approach to save 2 bytes
Jörg Hülsermann

6

PHP, 185 176 174 bytes

for(;$n++<$argn**2;${xy[$m&1]}+=$m&2?-1:1,$k++<$p?:$p+=$m++%2+$k=0)$r[+$y][+$x]=$n;ksort($r);foreach($r as$o){ksort($o);foreach($o as$i)printf(" %".strlen($n).d,$i);echo"
";}

Run as pipe with -nR or test it online.

breakdown

for(;$n++<$argn**2;     # loop $n from 1 to N squared
    ${xy[$m&1]}+=$m&2?-1:1, # 2. move cursor
    $k++<$p?:               # 3. if $p+1 numbers have been printed in that direction:
        $p+=$m++%2+             # increment direction $m, every two directions increment $p
        $k=0                    # reset $k
)$r[+$y][+$x]=$n;           # 1. paint current number at current coordinates

ksort($r);              # sort grid by indexes
foreach($r as$o){       # and loop through it
    ksort($o);              # sort row by indexes
    foreach($o as$i)        # and loop through it
        printf(" %".strlen($n).d,$i);   # print formatted number
    echo"\n";               # print newline
}

6

APL (Dyalog Classic), 32 29 bytes

1+×⍨-{⊖∘⌽⍣⍵⌽{⌽⍉,⌸⍵+≢⍵}⍣2⍣⍵⍪⍬}

Try it online!

Uses ⎕io←1. Starts with a 0-by-1 matrix (⍪⍬). 2N times (⍣2⍣⍵) adds the height of the matrix (≢⍵) to each of its elements, puts 1 2...height on its right (,⌸), and rotates (⌽⍉). When that's finished, corrects the orientation of the result (⊖∘⌽⍣⍵⌽) and reverses the numbers by subtracting them from N2+1 (1+×⍨-).


5

Mathematica, 177 bytes

(n=#;i=j=Floor[(n+1)/2];c=1;d=0;v={{1,0},{0,-1},{-1,0},{0,1}};a=Table[j+n(i-1),{i,n},{j,n}];Do[Do[Do[a[[j,i]]=c++;{i,j}+=v[[d+1]], {k,l}];d=Mod[d+1,4],{p,0,1}],{l,n-1}];Grid@a)&

8
Waaait, no built-in for this in Mathematica?
Mr. Xcoder

5

C++, 245 228 bytes

void f(){for(int i=0,j=-1,v,x,y,a,b;i<n;i++,j=-1,cout<<endl)while(++j<n){x=(a=n%2)?j:n-j-1;y=a?i:n-i-1;v=(b=y<n-x)?n-1-2*(x<y?x:y):2*(x>y?x:y)-n;v=v*v+(b?n-y-(y>x?x:y*2-x):y+1-n+(x>y?x:2*y-x));cout<<setw(log10(n*n)+1)<<v<<' ';}}

Try it online!

The function calculates and prints the value of each number of the matrix depending on its x, y position by applying this logic:

Snake values calculation depending on position

Formatted version:

#include <iostream>
#include <iomanip>
#include <math.h>

using namespace std;

void f(int n)
{
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            int value = 0;

            // Invert x and y when n is even
            int x = n % 2 == 0 ? n - j - 1 : j;
            int y = n % 2 == 0 ? n - i - 1 : i;
            if (y < (n - x))
            {
                // Left-top part of the matrix
                int padding = x < y ? x : y;
                value = n - 1 - padding * 2;
                value *= value;
                value += y >= x ? n - x - y : n + x - y - (y * 2);
            }
            else
            {
                // Right-bottom part of the matrix
                int padding = x > y ? n - x : n - y;
                value = n - padding * 2;
                value *= value;
                value += x > y ? y - padding + 1 : n + y - x - (padding * 2) + 1;
            }

            cout << setw(log10(n * n) + 1);
            cout << value << ' ';
        }

        cout << endl;
    }
}

int main()
{
    int n;
    while (cin >> n && n > 0)
    {
        f(n);
        cout << endl;
    }
}

5

Python 3, 249 247 bytes

I initialize an 2D array and find the starting point, which is the center for odd n or offset (-1,-1) for even n, then scale the fill/cursor pattern with the current 'ring' number. I feel like I'm missing a trick for interpreting the directions but I haven't come up with anything cheaper.

def f(n):
 M=[n*[0]for a in range(n)]
 x=y=n//2-1+n%2
 M[x][y]=i=s=1
 while 1:
  t=s*2
  for d in'R'+'D'*(t-1)+'L'*t+'U'*t+'R'*t:
   if i==n*n:print(*M,sep='\n');return
   v=[1,-1][d in'LU']
   if d in'UD':x+=v
   else:y+=v
   M[x][y]=i=i+1
  s+=1

Try it online!

-2 thanks to Zachary T!


how did you count your bytes? tabs, spaces and newlines counts as well
Felipe Nardi Batista

I replaced every \n and \t with " " and took a len(). I just copied the above and redid it to make sure I didn't change anything and forget to recount but I got the same number. Did I miss something?
nocturama

i'm counting \t and \n as 1 byte and still getting 249 bytes
Felipe Nardi Batista

e:^^^is there a better/easier method I should use? they always appeared to be used interchangeably to me.^^^ Strange, this is what I get in IDLE: len("def f(n): M=[n*[0]for a in range(n)] x=y=n//2-(n%2<1) M[x][y]=i=s=1 while 1: t=s*2 for d in'R'+'D'*(t-1)+'L'*t+'U'*t+'R'*t: if i==n*n:print(*M,sep='\n');return v=[1,-1][d in'LU'] if d in'UD':x+=v else:y+=v M[x][y]=i=i+1 s+=1") 223
nocturama

usually text editors tell you how many characters are selected, so CTRL+A and read what it says
Felipe Nardi Batista

5

Wolfram Language (Mathematica), (...) 83 bytes

Byte measured in UTF8, \[LeftFloor] () and \[RightFloor] () cost 3 bytes each. Mathematica doesn't have any special byte character set.

Table[Max[4x^2-Max[x+y,3x-y],4y
y-{x+y,3y-x}]+1,{y,b+1-#,b=⌊#/2⌋},{x,b+1-#,b}]&

Try it online!


Uses the closed form for each of the 4 cases, then takes the maximum carefully to get the desired result.

Returns a 2D array of integers. I'm not sure if this is allowed, and although it has been asked in the comments, the OP didn't reply.


4

Clojure, 206 bytes

(defmacro F[s]`(if(~'r(+ ~'p ~'v ~s))~'v ~s))
#(loop[i 1 p(*(quot(dec %)2)(inc %))v 1 r{}](if(<(* % %)i)(partition %(map r(range i)))(recur(inc i)(+ p v)({1(F %)-1(F(- %))%(F -1)(- %)(F 1)}v)(assoc r p i))))

I guess this is a decent start, builds the board in sequence to a hash-map and then partitions it into n x n lists. That defmacro ended up being quite long, but the code is still shorter with it than without. Is there a more succint syntax to describe it?

Bulk of bytes calculate the starting point, and build the look-up logic of the next velocity v. Perhaps a nested vec would be better, but then you've got two indexes and velocities to keep track of.



1

Python 165 (or 144)

from pylab import *
def S(n):
 a=r_[[[1]]];r=rot90;i=2
 while any(array(a.shape)<n):
  q=a.shape[0];a=vstack([range(i,i+q),r(a)]);i+=q
 if n%2==0:a=r(r(a))
 print(a)

This creates a numpy array, then rotates it and adds a side until the correct size is reached. The question didn't specify if the same start point needs to be used for even and odd numbers, if that's not the case the line if n%2==0:a=r(r(a)) can be removed, saving 21 bytes.


1
this isn't Python, it's Python + numpy
ASCII-only

@ASCII-only Is there a master list of acceptable language names somewhere? This is perfectly valid python.
user2699

It uses a library, so you need to include the library's name as well... as for allowed languages, any language with a publicly available implementation you can get to run is allowed
ASCII-only

@ASCII-only where's that written out? I haven't seen it done with most python answers.
user2699

Yes, because most of them don't use numpy... and the stdlib doesn't count as an external library
ASCII-only

0

J, 41 bytes

,~$[:/:[:+/\_1|.1&,(]##@]$[,-@[)2}:@#1+i.

standard formatting

,~ $ [: /: [: +/\ _1 |. 1&, (] # #@] $ [ , -@[) 2 }:@# 1 + i.

This approach is based off At Play With J Volutes (Uriel's APL uses a similar technique).

It's unexpected and elegant enough to justify a 2nd J answer, I thought.

Essentially, we don't do anything procedural or even geometric. Instead, we arithmetically create a simple sequence that, when scan summed and graded up, gives the correct order of the spiraled number from left to right, top to bottom. We then shape that into a matrix and are done.

I'll add a more detailed explanation when time permits, but the linked article explains it in depth.

Try it online!


0

Python 3 (Stackless), 192 188 179 150 bytes

lambda n:[list(map(v,list(range(t-n,t)),[y]*n))for t in[1+n//2]for y in range(n-t,-t,-1)]
v=lambda x,y,r=0:y>=abs(x)and(3-2*r+4*y)*y+x+1or v(y,-x,r+1)

Try it online!

The algorithm here is to form a phasor for each coordinate in the grid, and then rotate it 90-degrees clockwise until the phasor lies between the upper diagonals. A simple formula can be used to calculate the value based on the coordinates and the number of clockwise rotations:

(2y+1)2(yx)2yr

Saved 4-bytes since 90-degree phasor rotation is easily done without complex numbers


0

R, 183 bytes

x=scan()
b=t(d<-1)
while(2*x-1-d){m=max(b)
y=(m+1):(m+sum(1:dim(b)[2]|1))
z=d%%4
if(z==1)b=cbind(b,y)
if(z==2)b=rbind(b,rev(y))
if(z==3)b=cbind(rev(y),b)
if(z==0)b=rbind(y,b)
d=d+1}
b

Try it online!

Output is a matrix snake (or snake matrix, whatever). It's probably not the most efficient method, and it could likely be golfed, but I thought it was worth showing. I'm rather proud of this actually!

The method builds the matrix from the inside out, always appending an additional number of integers equal to the number of columns in the matrix before appending. The pattern that follows is either binding by columns or by rows, while also reversing some values so they are appended in the correct order.

193 bytes

Exact same as above, but final b is

matrix(b,x)

Try it online!

which gives slightly cleaner output, but I didn't see any special criteria for output, so the first answer should work if I'm not mistaken.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.