Bana bir numara yılanı sar!


34

Bir giriş tamsayı verilen n, bir ızgara, ölçüm bir sayı yılan çizmek n x nnumaralarını içerir 1yoluylan^2 aşağıdaki şekilde birbiri etrafında sarılması:

Giriş n = 3:

7 8 9
6 1 2
5 4 3

Giriş n = 4:

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

Giriş 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

( Bu sorundan ilham alındı Euler Projesi'nden .)

Bu , bayt cinsinden en kısa cevap kazanır!


4
Örnek: 4? Veya herhangi bir çift sayı.
TheLethalCoder

1
Girişin tuhaf olduğunu kabul edebilir miyiz?
Bay Xcoder



1
Ayrıca , cevaplarda birçok çözüm ve bağlantı bulunan perlmonks.com/?node_id=487200 adresine bakın .
b_jonas

Yanıtlar:



18

C #, 203 202 196 193 178 bayt

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;}

@StefanDelport sayesinde bir bayt kaydedildi.
@FelipeNardiBatista sayesinde 22 bayt kaydedildi.

Bu, karelerin nasıl oluşturulduğuna dair aşağıdaki gözlemlerle çalışır:

Image of square where n=5

Gördüğünüz gibi her bit önceki kareye eklenir. Rakamlar için, bulunduğumuz yerin tamına gidiyoruz, aşağıya, karenin olduğu yerden bir alttaydı ve daha sonra sona erdi. Tek sayılar esasında tam tersidir, bir sola gideriz, o zamana kadar mevcut yüksekliğin bir üzerine çıktıktan sonra sağdan sona doğru.

Tam / Biçimli sürüm:

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;olabilir n>++i, görebileceğim başka bir şey yok, +1.
LiefdeWen

1
n%2<1?2:1için 2-x%2? C # ile test etmedim, fakat C ve Python'da işe yaradı.
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; ....biraz golf oynadı
Felipe Nardi Batista

@FelipeNardiBatista Awesome, bu ikisini asla düşünemezdi! Teşekkürler.
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 bayt

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

Çevrimiçi deneyin!

Nasıl?

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

Endeksler arasındaki farkları hesaplar; 1ve ¯1sağ ve sol ¯⍵ve yukarı ve aşağı için.

1,⊢,¯1,-geldiğinde 1 ⍵ ¯1 ¯⍵, +⍨⍴bu diziyi uzunluğa kadar uzatır ⍵×2, böylece final 2/⍳, her ikinci öğeyi artıran bir tekrar sayımı ile her birini tekrar edebilir:

      (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

sonra,

(⌈2÷⍨×⍨),

Spiralin sol üst elemanını hazırlar,

×⍨↑

bu mesafeler listesinin ilk ⍵ 2 elemanını sınırlandırın ,

+\

Birikimli toplamı yapar,

⍵[i] = ⍵[⍵[i]]orijinal matrisi her elemanın indeksleriyle çevirmek için endeksleri ( ) yükseltir ve son olarak

,⍨⍴

⍵×⍵matris olarak biçimlendirir.


İlgilenenler için, bu teknik bu mükemmel makalede uzunca ele alınmıştır .
Jonah

9

C, 321 307 295 284 283 282 bayt

Bir bayt golf oynamak için hem @ Zachary T hem de @Jonathan Frech'e teşekkürler!

#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);}

İki boyutlu sıfır dizisini tahsis eder, ardından ortadaki bir yerden doldurmaya başlar. Son olarak, sıfırdan büyük ancak girişin karesine eşit veya daha küçük olan değerler yazdırılır.

Çevrimiçi deneyin!

biçimlendirilmiş:

#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
Değiştirmek mümkündür mı i,j,k,a,b,m;f(n){n*=n;int**l=calloc(a=m=3*n,4);ile i,j,k,a,b,m,**l;f(n){n*=n;l=calloc(a=m=3*n,4);bir byte kaydetmek için?
Zacharı,

1
Sen yerine mümkün olabilir k<=n;ile n>k;bir byte tasarrufu için.
Jonathan Frech

6

PHP , 192 bayt

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++]);

Çevrimiçi deneyin!

Aynı şekilde bir dizi yerine bir dizge oluştur

PHP , 217 bayt

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);

Çevrimiçi deneyin!


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

@Titus Teşekkür ederim Görmedim
Jörg Hülsermann

1
İşte bir tane daha bayt geçerli: for(;$k<$a;print join($o)."\n")ksort($o=&$e[+$k++]);. Ve başka bir: "%$l".d. Ve bir tane daha: $x*$l*$a+$y*$l-> ($x*$a+$y)*$l.
Titus

1
Ve sanırım ikinci versiyonda $syastıklı bir alt çizgiye (veya harf ya da rakam) başlatabilirsiniz ; bu karakterin üzerine yazılacak.
Titus

@Titus Teşekkürler ve .d2 bayttan tasarruf etmek için kendi yaklaşımınızı kullanabilirsiniz
Jörg Hülsermann

6

PHP, 185 176 174 bayt

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"
";}

Pipo olarak çalıştır -nRveya çevrimiçi olarak test et .

Yıkmak

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 bayt

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

Çevrimiçi deneyin!

Kullanır ⎕io←1. 0x1 matris ( ⍪⍬) ile başlar. 2N times ( ⍣2⍣⍵), matrisin ( ≢⍵) yüksekliğini öğelerin her birine ekler 1 2...height, sağına koyar ( ,⌸) ve döndürür ( ⌽⍉). Tamamlandığında, sonucun ( ⊖∘⌽⍣⍵⌽) yönünü düzeltir ve sayıları N 2 + 1'den ( 1+×⍨-) çıkararak tersine çevirir .


5

Mathematica, 177 bayt

(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, Mathematica'da bunun için yerleşik değil mi?
Bay Xcoder

5

C ++, 245 228 bayt

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<<' ';}}

Çevrimiçi deneyin!

İşlev , bu mantığı uygulayarak x, y konumuna bağlı olarak her bir matris sayısının değerini hesaplar ve yazdırır :

Snake values calculation depending on position

Biçimlendirilmiş versiyon :

#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 bayt

Bir 2B dizi başlatıyorum ve tek n için tek n veya ofsetin (-1, -1) merkezi olan başlangıç ​​noktasını buluyorum, ardından dolgu / imleç desenini geçerli 'halka' numarasıyla ölçeklendiriyorum. Yönergeleri yorumlamak için bir numara kaçırdığımı hissediyorum ama daha ucuz bir şey bulamadım.

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

Çevrimiçi deneyin!

-2, Zachary T'ye teşekkürler!


Baytınızı nasıl saydınız? sekmeleri, boşlukları ve yeni satırları da sayılır
Felipe Nardi Batista

Her bir \ n ve t'yi "" ile değiştirdim ve bir len () aldım. Yukarıdakileri kopyaladım ve hiçbir şeyi değiştirmediğimden ve tekrar saymayı unuttuğumdan emin olmak için yeniden yazdım ama aynı sayıyı aldım. Bir şey mi kaçırdım?
nocturama

Ben sayıyorum \tve \n1 bayt ve hala 249 bayt alıyorum
Felipe Nardi Batista

e: ^^^ kullanmam gereken daha iyi / daha kolay bir yöntem var mı? her zaman bana birbirlerinin yerine kullanıldıkları ortaya çıktı.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
IDLE'de

genellikle metin editörleri size kaç karakterin seçildiğini söyler, bu nedenle CTRL + A
Felipe Nardi Batista

5

Wolfram Dili (Mathematica) , (...) 83 bayt

UTF8, \[LeftFloor]( ) ve \[RightFloor]( ) cinsinden ölçülen bayt, her birinin maliyeti 3 bayttır. Mathematica'da herhangi bir özel bayt karakter seti yok.

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}]&

Çevrimiçi deneyin!


4 durumun her biri için kapalı formu kullanır, ardından istenen sonucu elde etmek için azami özenle alır.

2B bir tamsayı dizisi döndürür. Buna izin verilip verilmediğinden emin değilim ve yorumlarda sorulmasına rağmen OP yanıt vermedi.


4

Clojure, 206 bayt

(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))))

Sanırım bu iyi bir başlangıç, tahtayı bir karma haritaya göre sırayla oluşturuyor ve ardından n x nlisteleri listeliyor. odefmacro oldukça uzun sürdü, ancak kod hala onunla olmadan daha kısa. Açıklamak için daha sulu bir sözdizimi var mı?

Toplu bayt, başlangıç ​​noktasını hesaplar ve bir sonraki hızın arama mantığını oluşturur v. Belki bir yuvalanmış vecdaha iyi olurdu, ama sonra takip etmek için iki dizin ve hızları var.



1

Python 165 (veya 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)

Bu bir numpy dizi oluşturur, sonra onu döndürür ve doğru boyuta ulaşılana kadar bir taraf ekler. Soru, aynı başlangıç ​​noktasının çift ve tek sayılar için kullanılması gerekip gerekmediğini, hattın if n%2==0:a=r(r(a))kaldırılması mümkün değilse, 21 bayttan tasarruf etmeyi belirlemedi .


1
Bu Python değil, Python + numpy
ASCII-sadece

@ ASCII-only Bir yerde kabul edilebilir dil adlarının ana listesi var mı? Bu mükemmel geçerli python.
user2699

Bir kütüphane kullanır, bu yüzden kütüphanenin adını da eklemeniz gerekir ... izin verilen diller için, herkesin kullanabileceği bir uygulamaya sahip herhangi bir dilin yayınlanmasına izin verilir
ASCII - sadece

@ ASCII-sadece bu yazılan nerede? Piton cevaplarının çoğunda bunu görmedim.
user2699

Evet, çünkü çoğu uyuşuk kullanmıyor ... ve stdlib harici bir kütüphane saymıyor
ASCII-sadece

0

J , 41 bayt

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

standart biçimlendirme

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

Bu yaklaşım J Volutes ile Oynamak üzerine kuruludur (Uriel'in APL'si benzer bir teknik kullanır).

İkinci bir J cevabını haklı çıkaracak kadar beklenmedik ve zarif, diye düşündüm.

Esasen, prosedürel ve hatta geometrik bir şey yapmıyoruz. Bunun yerine, aritmetik olarak, tarama toplanıp derecelendirildiğinde, spiral sayının soldan sağa, yukarıdan aşağıya doğru sırasını veren basit bir dizi oluştururuz. Daha sonra bunu bir matris haline getiririz ve yapılır.

Zaman izin verdiği zaman daha ayrıntılı bir açıklama ekleyeceğim, ancak bağlantılı makale onu derinlemesine açıklıyor.

Çevrimiçi deneyin!


0

Python 3 (İstifsiz) , 192 188 179 150 bayt

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)

Çevrimiçi deneyin!

Buradaki algoritma, ızgaradaki her koordinat için bir fazör oluşturmak ve daha sonra fazör üst köşegenler arasında uzanana kadar saat yönünde 90 derece döndürmektir. Koordinatlara ve saat yönünde dönüşlerin sayısına göre değeri hesaplamak için basit bir formül kullanılabilir:

(2y+1)2-(y-x)-2yr

90 derecelik fazör rotasyonu, 4 sayılardan beri karmaşık sayılar olmadan kolayca yapılabilir.


0

R , 183 bayt

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

Çevrimiçi deneyin!

Çıktı bir matris yılanıdır (veya yılan matrisi, ne olursa olsun). Muhtemelen en etkili yöntem değildir ve muhtemelen golf olabilir, ancak göstermeye değer olduğunu düşündüm. Aslında bununla gurur duyuyorum!

Yöntem, matrisi içten dışa doğru oluşturur, her zaman eklemeden önce matristeki sütun sayısına eşit sayıda tam sayı ekler. Takip eden desen ya sütunlarla ya da satırlarla bağlanırken aynı zamanda bazı değerleri de doğru sırayla eklemek için tersine çevirir.

193 bayt

Tam yukarıdaki ile aynıdır, ancak son bis

matrix(b,x)

Çevrimiçi deneyin!

biraz daha temiz çıktılar veriyor, ancak çıktı için herhangi bir özel kriter görmedim, bu yüzden yanılmıyorsam ilk cevap işe yaramalı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.