Bir sarmal içinde döngü


154

Bir arkadaşının bir NxM matrisinin elemanları arasında döngü yapmasına izin verecek bir algoritmaya ihtiyacı vardı (N ve M garip). Bir çözüm buldum, ama diğer SO'ers'ımın daha iyi bir çözüm bulup bulamayacağını görmek istedim.

Çözümümü bu sorunun cevabı olarak gönderiyorum.

Örnek Çıktı:

3x3'lük bir matris için çıktı şöyle olmalıdır:

(0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1 )

3x3 matris

Ayrıca, algoritma kare olmayan matrisleri desteklemelidir, bu nedenle örneğin 5x3'lük bir matris için çıktı şu şekilde olmalıdır:

(0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1 ) (2, -1) (2, 0) (2, 1) (-2, 1) (-2, 0) (-2, -1)

5x3 matris


Kare olmayan matrisler için ne istediğinizi açıklayabilir misiniz? Çözümünüzün (2,1) 'den (-2,1)' e "sıçraması" var - bu amaçlanıyor mu? [Örneğin, 7x3'lük bir matris için iki tane daha “atlama” olacak ve (2k + 1) x3 matrisi için 2k-3 atlama olacak mı?]
ShreevatsaR 29:08

3
Evet, atlamalar kasıtlı. Soruyu 5x3'lük bir matris görüntüsü ile güncelledim. Resimden de görebileceğiniz gibi, üst ve alt satırları atlıyoruz.
Can Berk Güder

Tamam, kendi kodunuz en temiz görünüyor. Ve bu offtopik olmasına rağmen: bu görüntüleri nasıl oluşturdunuz? :)
ShreevatsaR

=)) Onları ben yaratmadım. Aslında, onları yaratma şeklim oldukça aptalca. Tabloları OO.org Calc'da oluşturdum, ekran görüntüsü aldım ve ekran görüntüsünü GIMP'de düzenledim. =))
Can Berk Güder

1
@Ying: Arkadaşımın neden buna ihtiyacı olduğunu bilmiyorum, ama bir arama algoritmasında merkeze yakın matris üyelerini tercih etmek istediğini söyledi.
Can Berk Güder

Yanıtlar:


63

İşte benim çözümüm (Python'da):

def spiral(X, Y):
    x = y = 0
    dx = 0
    dy = -1
    for i in range(max(X, Y)**2):
        if (-X/2 < x <= X/2) and (-Y/2 < y <= Y/2):
            print (x, y)
            # DO STUFF...
        if x == y or (x < 0 and x == -y) or (x > 0 and x == 1-y):
            dx, dy = -dy, dx
        x, y = x+dx, y+dy

1
Görebildiğim kadarıyla yazmanın en iyi yolu bu. Olası tek iyileştirme, yazdırılamayacak (x, y) 'yi doğrudan atlayarak O (max (M, N) ^ 2) yerine O (MN) yapmak olacaktır, ancak bu kodu yapacak biraz daha çirkin.
ShreevatsaR

Çözümümü optimize ediyorum ve zaten sahip olduğunuza oldukça yakın. Bence bu oldukça iyi bir çözüm. ShreevatsaR'ın önerisi ve her yinelemenin x / 2 ve y / 2 hesaplanmaması gibi şeylerin yanı sıra, stil dışında iyileştirilecek çok fazla şey yoktur.
Triptych

Matlab için çözüm var mı ?!
Sam

Bu, görüntü arabelleği verilerine erişmek için iyi bir önbellek tutarlılığı sağlıyor mu? (Burada çok fazla cevap var, ancak yüksek performanslı görüntü işlemleri için hangisinin en iyi
olduğuna

@ ideasman42 - bu devreye girmez, çünkü sonuç her zaman aynı sarmal koordinat paternidir. Spiral paternin önbellek uyumlu olup olmadığı sanırım görüntü tamponu uygulamasına bağlıdır. (Benim tahminim, önbelleği sırayla satır satır gitmek gibi, görüntüyü yürürken diğer yollardan daha fazla atmak olacaktır). Ancak bu koordinatları üretmek için algoritma seçimi muhtemelen önbelleği etkilemez.
Raptormeat

31

C ++ kimse var mı? Tamlık için gönderilen python'dan hızlı çeviri

void Spiral( int X, int Y){
    int x,y,dx,dy;
    x = y = dx =0;
    dy = -1;
    int t = std::max(X,Y);
    int maxI = t*t;
    for(int i =0; i < maxI; i++){
        if ((-X/2 <= x) && (x <= X/2) && (-Y/2 <= y) && (y <= Y/2)){
            // DO STUFF...
        }
        if( (x == y) || ((x < 0) && (x == -y)) || ((x > 0) && (x == 1-y))){
            t = dx;
            dx = -dy;
            dy = t;
        }
        x += dx;
        y += dy;
    }
}

ayrıca büyük koşullardan kurtulur köşeleri tespit etmek için yaptığım gibi s ve ds kullanabilirsiniz
John La Rooy

1
Burada bu yayında bir düzenleme yapılması önerildi . Düzenleme, yayınınızın anlamını değiştirdiği için reddedilmiş olsa da, yapılması mantıklıysa önerilen değişiklikleri eklemeyi düşünebilirsiniz.
Robert Harvey

19
let x = 0
let y = 0
let d = 1
let m = 1

while true
  while 2 * x * d < m
    print(x, y)
    x = x + d
  while 2 * y * d < m
    print(x, y)
    y = y + d
  d = -1 * d
  m = m + 1

Bu problem için çeşitli programlama dillerinde yazılmış birçok çözüm önerilmiştir, ancak hepsi aynı kıvrımlı yaklaşımdan kaynaklanmaktadır. İndüksiyon kullanılarak kısaca ifade edilebilecek bir spiral hesaplamanın daha genel problemini ele alacağım.

Temel durum: (0, 0) 'dan başlayın, 1 kare ileri, sola dön, 1 kare ileri, sola dön. Endüktif adım: İleriye doğru n + 1 kareler, sola dönün, ileriye doğru n + 1 kareler, sola dönün.

Bu problemi ifade etmenin matematiksel şıklığı, çözümü hesaplamak için basit bir algoritma olması gerektiğini göstermektedir. Soyutlamayı akılda tutarak, algoritmayı belirli bir programlama dilinde değil, sahte kod olarak uygulamayı seçtim.

İlk önce 4 çift while döngüsü kullanarak spiralin sadece 2 tekrarını hesaplamak için bir algoritma düşüneceğim. Her çiftin yapısı benzerdir, ancak kendi başına farklıdır. Bu başlangıçta çılgınca görünebilir (bazı döngüler sadece bir kez yürütülür), ancak aynı olan ve dolayısıyla başka bir döngünün içine yerleştirilmiş tek bir çiftle değiştirilebilen 4 çift döngüye ulaşana kadar adım adım dönüşümler yapacağım. Bu, bize herhangi bir koşul kullanmadan genel bir hesaplama yinelemesi sağlayacaktır.

let x = 0
let y = 0

//RIGHT, UP
while x < 1
  print(x, y)
  x = x + 1
while y < 1
  print(x, y)
  y = y + 1

//LEFT, LEFT, DOWN, DOWN
while x > -1
  print(x, y)
  x = x - 1
while y > -1
  print(x, y)
  y = y - 1

//RIGHT, RIGHT, RIGHT, UP, UP, UP
while x < 2
  print(x, y)
  x = x + 1
while y < 2
  print(x, y)
  y = y + 1

//LEFT, LEFT, LEFT, LEFT, DOWN, DOWN, DOWN, DOWN
while x > -2
  print(x, y)
  x = x - 1
while y > -2
  print(x, y)
  y = y - 1

Yapacağımız ilk dönüşüm, yön için +1 veya -1 değerini tutan yeni bir d değişkeninin getirilmesidir. Her döngü çiftinden sonra yön değişir. D'nin değerini tüm noktalarda bildiğimiz için, her bir eşitsizliğin her iki tarafını da onunla çarpabilir, eşitsizliğin yönünü buna göre ayarlayabilir ve d'nin çarpımlarını sabit ile başka bir sabit arasında basitleştirebiliriz. Bu bizi aşağıdakilere bırakıyor.

let x = 0
let y = 0
let d = 1

//RIGHT, UP
while x * d < 1
  print(x, y)
  x = x + d
while y * d < 1
  print(x, y)
  y = y + d
d = -1 * d

//LEFT, LEFT, DOWN, DOWN
while x * d < 1
  print(x, y)
  x = x + d
while y * d < 1
  print(x, y)
  y = y + d
d = -1 * d

//RIGHT, RIGHT, RIGHT, UP, UP, UP
while x * d < 2
  print(x, y)
  x = x + d
while y * d < 2
  print(x, y)
  y = y + d
d = -1 * d

//LEFT, LEFT, LEFT, LEFT, DOWN, DOWN, DOWN, DOWN
while x * d < 2
  print(x, y)
  x = x + d
while y * d < 2
  print(x, y)
  y = y + d

Şimdi hem x * d hem de RHS'nin tamsayı olduğuna dikkat ediyoruz, böylece eşitsizliğin sonucunu etkilemeden RHS'den 0 ile 1 arasındaki herhangi bir gerçek değeri çıkarabiliriz. Daha fazla model oluşturmak için diğer her bir çift döngüdeki eşitsizliklerden 0.5 çıkarmayı seçiyoruz.

let x = 0
let y = 0
let d = 1

//RIGHT, UP
while x * d < 0.5
  print(x, y)
  x = x + d
while y * d < 0.5
  print(x, y)
  y = y + d
d = -1 * d

//LEFT, LEFT, DOWN, DOWN
while x * d < 1
  print(x, y)
  x = x + d
while y * d < 1
  print(x, y)
  y = y + d
d = -1 * d

//RIGHT, RIGHT, RIGHT, UP, UP, UP
while x * d < 1.5
  print(x, y)
  x = x + d
while y * d < 1.5
  print(x, y)
  y = y + d
d = -1 * d

//LEFT, LEFT, LEFT, LEFT, DOWN, DOWN, DOWN, DOWN
while x * d < 2
  print(x, y)
  x = x + d
while y * d < 2
  print(x, y)
  y = y + d

Artık while döngülerinin her bir çiftinde attığımız adım sayısı için başka bir m değişkeni ekleyebiliriz.

let x = 0
let y = 0
let d = 1
let m = 0.5

//RIGHT, UP
while x * d < m
  print(x, y)
  x = x + d
while y * d < m
  print(x, y)
  y = y + d
d = -1 * d
m = m + 0.5

//LEFT, LEFT, DOWN, DOWN
while x * d < m
  print(x, y)
  x = x + d
while y * d < m
  print(x, y)
  y = y + d
d = -1 * d
m = m + 0.5

//RIGHT, RIGHT, RIGHT, UP, UP, UP
while x * d < m
  print(x, y)
  x = x + d
while y * d < m
  print(x, y)
  y = y + d
d = -1 * d
m = m + 0.5

//LEFT, LEFT, LEFT, LEFT, DOWN, DOWN, DOWN, DOWN
while x * d < m
  print(x, y)
  x = x + d
while y * d < m
  print(x, y)
  y = y + d

Son olarak, her bir while döngüsü çiftinin yapısının aynı olduğunu ve başka bir ilmeğin içine yerleştirilmiş tek bir ilmeğe indirgenebileceğini görüyoruz. Ayrıca, gerçek değerli sayılar kullanmaktan kaçınmak için m'nin başlangıç ​​değerini çarptım; m değeri şu şekilde arttırılır; ve her bir eşitsizliğin her iki tarafı da 2.

Bu, bu cevabın başında gösterilen çözüme götürür.


1
Nihai çözümünüz hangi koşullarda sona erer?
Merlyn Morgan-Graham

1
Bu tür desen baskısının uygulaması nedir?
Ashish Shukla

1
@ MerlynMorgan-Graham Bilgisayarın belleği veya gücü bittiğinde sona erer.
Mike

Bu çözümün zarafeti, zaman ve bellek kısıtlamalarını göz ardı etmekten kaynaklanıyor gibi görünüyor. Zarif bir şekilde bir sonlandırma koşulu eklemenizi öneririm (mümkünse). Ayrıca cevabın tepesine gitmenizi ve altındaki türevi göstermenizi de öneririm.
Merlyn Morgan-Graham

1
Orijinal soru bir NxM matrisi ile ilgili olsa da, bir şey bulana kadar (yani kırılma veya geri dönme) sonsuza kadar spiral şeklinde dışarıya doğru çıkmanız gerekiyorsa, bu gerçekten çok yararlı bir cevaptır. Tabii ki, belirtilen diğer yorumlar gibi, bu fesih koşulunu tanımlamanız gerekir, aksi takdirde sonsuza kadar çalışacaktır.
cclogg

16

Kareli bir spiralin konumunu bulmak için O (1) çözümü: Fiddle

function spiral(n) {
    // given n an index in the squared spiral
    // p the sum of point in inner square
    // a the position on the current square
    // n = p + a

    var r = Math.floor((Math.sqrt(n + 1) - 1) / 2) + 1;

    // compute radius : inverse arithmetic sum of 8+16+24+...=
    var p = (8 * r * (r - 1)) / 2;
    // compute total point on radius -1 : arithmetic sum of 8+16+24+...

    var en = r * 2;
    // points by face

    var a = (1 + n - p) % (r * 8);
    // compute de position and shift it so the first is (-r,-r) but (-r+1,-r)
    // so square can connect

    var pos = [0, 0, r];
    switch (Math.floor(a / (r * 2))) {
        // find the face : 0 top, 1 right, 2, bottom, 3 left
        case 0:
            {
                pos[0] = a - r;
                pos[1] = -r;
            }
            break;
        case 1:
            {
                pos[0] = r;
                pos[1] = (a % en) - r;

            }
            break;
        case 2:
            {
                pos[0] = r - (a % en);
                pos[1] = r;
            }
            break;
        case 3:
            {
                pos[0] = -r;
                pos[1] = r - (a % en);
            }
            break;
    }
    console.log("n : ", n, " r : ", r, " p : ", p, " a : ", a, "  -->  ", pos);
    return pos;
}

3
Merkezden başlamak için iki satır ekleyin. if (n === 0) return [0, 0, r]; --n;Keman: jsfiddle.net/Wishmesh/nwd9gt1s/2
Maris B.

15

Python'un jeneratörlerini seviyorum.

def spiral(N, M):
    x,y = 0,0   
    dx, dy = 0, -1

    for dumb in xrange(N*M):
        if abs(x) == abs(y) and [dx,dy] != [1,0] or x>0 and y == 1-x:  
            dx, dy = -dy, dx            # corner, change direction

        if abs(x)>N/2 or abs(y)>M/2:    # non-square
            dx, dy = -dy, dx            # change direction
            x, y = -y+dx, x+dy          # jump

        yield x, y
        x, y = x+dx, y+dy

Şununla test:

print 'Spiral 3x3:'
for a,b in spiral(3,3):
    print (a,b),

print '\n\nSpiral 5x3:'
for a,b in spiral(5,3):
    print (a,b),

Şunları elde edersiniz:

Spiral 3x3:
(0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1) 

Spiral 5x3:
(0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1) (2, -1) (2, 0) (2, 1) (-2, 1) (-2, 0) (-2, -1)

8

Java sarmal "Kod golf" girişimi, C ++ varyantına dayalı.

public static void Spiral(int X, int Y) {
    int x=0, y=0, dx = 0, dy = -1;
    int t = Math.max(X,Y);
    int maxI = t*t;

    for (int i=0; i < maxI; i++){
        if ((-X/2 <= x) && (x <= X/2) && (-Y/2 <= y) && (y <= Y/2)) {
            System.out.println(x+","+y);
            //DO STUFF
        }

        if( (x == y) || ((x < 0) && (x == -y)) || ((x > 0) && (x == 1-y))) {
            t=dx; dx=-dy; dy=t;
        }   
        x+=dx; y+=dy;
    }
}

7

Bir sonraki (x, y) koordinatlarını öncekilerden doğrudan ve kolayca hesaplayabileceğinizi gösteren bir C ++ çözümü: mevcut yönü, yarıçapı veya başka bir şeyi izlemeye gerek yok:

void spiral(const int M, const int N)
{
    // Generate an Ulam spiral centered at (0, 0).
    int x = 0;
    int y = 0;

    int end = max(N, M) * max(N, M);
    for(int i = 0; i < end; ++i)
    {
        // Translate coordinates and mask them out.
        int xp = x + N / 2;
        int yp = y + M / 2;
        if(xp >= 0 && xp < N && yp >= 0 && yp < M)
            cout << xp << '\t' << yp << '\n';

        // No need to track (dx, dy) as the other examples do:
        if(abs(x) <= abs(y) && (x != y || x >= 0))
            x += ((y >= 0) ? 1 : -1);
        else
            y += ((x >= 0) ? -1 : 1);
    }
}

Yapmaya çalıştığınız tek şey sarmaldaki ilk N noktalarını oluşturmaksa (orijinal sorunun bir N x M bölgesine maskeleme kısıtlaması olmadan), kod çok basit hale gelir:

void spiral(const int N)
{
    int x = 0;
    int y = 0;
    for(int i = 0; i < N; ++i)
    {
        cout << x << '\t' << y << '\n';
        if(abs(x) <= abs(y) && (x != y || x >= 0))
            x += ((y >= 0) ? 1 : -1);
        else
            y += ((x >= 0) ? -1 : 1);
    }
}

İşin püf noktası, karenin hangi tarafında olduğunuzu belirlemek için x ve y'yi karşılaştırabilmenizdir ve bu da hangi yöne hareket edeceğinizi söyler.


5

TDD, Java ile.

SpiralTest.java:

import java.awt.Point;
import java.util.List;

import junit.framework.TestCase;

public class SpiralTest extends TestCase {

    public void test3x3() throws Exception {
        assertEquals("(0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1)", strung(new Spiral(3, 3).spiral()));
    }

    public void test5x3() throws Exception {
        assertEquals("(0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1) (2, -1) (2, 0) (2, 1) (-2, 1) (-2, 0) (-2, -1)",
                strung(new Spiral(5, 3).spiral()));
    }

    private String strung(List<Point> points) {
        StringBuffer sb = new StringBuffer();
        for (Point point : points)
            sb.append(strung(point));
        return sb.toString().trim();
    }

    private String strung(Point point) {
        return String.format("(%s, %s) ", point.x, point.y);
    }

}

Spiral.java:

import java.awt.Point;
import java.util.ArrayList;
import java.util.List;

public class Spiral {
    private enum Direction {
    E(1, 0) {Direction next() {return N;}},
    N(0, 1) {Direction next() {return W;}},
    W(-1, 0) {Direction next() {return S;}},
    S(0, -1) {Direction next() {return E;}},;

        private int dx;
        private int dy;

        Point advance(Point point) {
            return new Point(point.x + dx, point.y + dy);
        }

        abstract Direction next();

        Direction(int dx, int dy) {
            this.dx = dx;
            this.dy = dy;
        }
    };
    private final static Point ORIGIN = new Point(0, 0);
    private final int   width;
    private final int   height;
    private Point       point;
    private Direction   direction   = Direction.E;
    private List<Point> list = new ArrayList<Point>();

    public Spiral(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public List<Point> spiral() {
        point = ORIGIN;
        int steps = 1;
        while (list.size() < width * height) {
            advance(steps);
            advance(steps);
            steps++;
        }
        return list;
    }

    private void advance(int n) {
        for (int i = 0; i < n; ++i) {
            if (inBounds(point))
                list.add(point);
            point = direction.advance(point);
        }
        direction = direction.next();
    }

    private boolean inBounds(Point p) {
        return between(-width / 2, width / 2, p.x) && between(-height / 2, height / 2, p.y);
    }

    private static boolean between(int low, int high, int n) {
        return low <= n && n <= high;
    }
}

@ leppie: Belki de - kesinlikle yeterince kısa değil - ama bence TDD'nin iyi bir gösterimi ve makul derecede temiz, anlaşılması kolay, doğru kod. İçinde bırakacağım.
Carl Manaster

4

İşte benim çözümüm (Ruby'de)

def spiral(xDim, yDim)
   sx = xDim / 2
   sy = yDim / 2

   cx = cy = 0
   direction = distance = 1

   yield(cx,cy)
   while(cx.abs <= sx || cy.abs <= sy)
      distance.times { cx += direction; yield(cx,cy) if(cx.abs <= sx && cy.abs <= sy); } 
      distance.times { cy += direction; yield(cx,cy) if(cx.abs <= sx && cy.abs <= sy); } 
      distance += 1
      direction *= -1
   end
end

spiral(5,3) { |x,y|
   print "(#{x},#{y}),"
}

Hala O (max (n, m) ^ 2), ama güzel bir stil.
Triptik

1
yön = yön yerine yön = * - 1? Eğer golf oynuyorsanız d = -d d'den daha kısadır * = - 1 de
John La Rooy

3

Haskell, seçiminizi yapın:

spiral x y = (0, 0) : concatMap ring [1 .. max x' y'] where
    ring n | n > x' = left x' n  ++ right x' (-n)
    ring n | n > y' = up   n  y' ++ down (-n) y'
    ring n          = up n n ++ left n n ++ down n n ++ right n n
    up    x y = [(x, n) | n <- [1-y .. y]]; down = (.) reverse . up
    right x y = [(n, y) | n <- [1-x .. x]]; left = (.) reverse . right
    (x', y') = (x `div` 2, y `div` 2)

spiral x y = filter (\(x',y') -> 2*abs x' <= x && 2*abs y' <= y) .
             scanl (\(a,b) (c,d) -> (a+c,b+d)) (0,0) $
             concat [ (:) (1,0) . tail 
                    $ concatMap (replicate n) [(0,1),(-1,0),(0,-1),(1,0)]
                    | n <- [2,4..max x y] ]

22
Lütfen bunu bir rant veya trol yorumu olarak almayın, ama ALLAH çirkin bir haskell!
Petruza

1
Yukarıdaki yorumu daha fazla kabul edemedim.
Sneakyness

Bu Haskell bana çok şık geliyor.

1
Evet, ama ne kadar etkileyici olduğuna dikkat edin. Uzunluğunu, burada yayınlanan diğer örneklerle karşılaştırın.
Robert Harvey

@Petruza Aslında Haskell'deki en iyi çözüm değil. Buraya bir göz atın: rosettacode.org/wiki/Spiral_matrix#Haskell
polkovnikov.ph

2

Bu C cinsindendir.

Kötü değişken isimlerini seçtim. T == üst, L == sol, B == alt, R == sağ. Yani, tli sol üstte i ve brj sağ altta j.

#include<stdio.h>

typedef enum {
   TLTOR = 0,
   RTTOB,
   BRTOL,
   LBTOT
} Direction;

int main() {
   int arr[][3] = {{1,2,3},{4,5,6}, {7,8,9}, {10,11,12}};
   int tli = 0, tlj = 0, bri = 3, brj = 2;
   int i;
   Direction d = TLTOR;

   while (tli < bri || tlj < brj) {
     switch (d) {
     case TLTOR:
    for (i = tlj; i <= brj; i++) {
       printf("%d ", arr[tli][i]);
    }
    tli ++;
    d = RTTOB;
    break;
     case RTTOB:
    for (i = tli; i <= bri; i++) {
       printf("%d ", arr[i][brj]);
    }
    brj --;
    d = BRTOL;
    break;
     case BRTOL:
    for (i = brj; i >= tlj; i--) {
       printf("%d ", arr[bri][i]);
    }
    bri --;
        d = LBTOT;
    break;
     case LBTOT:
    for (i = bri; i >= tli; i--) {
       printf("%d ", arr[i][tlj]);
    }
    tlj ++;
        d = TLTOR;
    break;
 }
   }
   if (tli == bri == tlj == brj) {
      printf("%d\n", arr[tli][tlj]);
   }
}

2

Bir açık kaynak kütüphanesi, pikseller , bir uzayda çeşitli şablonlarda piksel taramak için işlevler sağlayan bir python kütüphanesi var. Dahil mekansal desenler dairesel, halkalar, ızgaralar, yılanlar ve rastgele yürüyüşlerdir. Ayrıca çeşitli dönüşümler de vardır (örn. Klip, takas, döndürme, çevirme). Orijinal OP sorunu aşağıdaki gibi çözülebilir

for x, y in clip(swap(ringscan(0, 0, 0, 2)), miny=-1, maxy=1):
    print x, y

puan veren

(0,0) (1,0) (1,1) (0,1) (-1,1) (-1,0) (-1,-1) (0,-1) (1,-1) (2,0) (2,1) (-2,1) (-2,0)
(-2,-1) (2,-1)

Kütüphane jeneratörleri ve dönüşümleri, çok çeşitli düzenlerde ve mekânsal örüntülerdeki noktaları değiştirmek için zincirlenebilir.


2

Python 3'te ardışık tamsayıları spiral olarak saat yönünde ve saat yönünün tersine yazdırmak için bir çözüm.

import math

def sp(n): # spiral clockwise
    a=[[0 for x in range(n)] for y in range(n)]
    last=1
    for k in range(n//2+1):
      for j in range(k,n-k):
          a[k][j]=last
          last+=1
      for i in range(k+1,n-k):
          a[i][j]=last
          last+=1
      for j in range(n-k-2,k-1,-1):
          a[i][j]=last
          last+=1
      for i in range(n-k-2,k,-1):
          a[i][j]=last
          last+=1

    s=int(math.log(n*n,10))+2 # compute size of cell for printing
    form="{:"+str(s)+"}"
    for i in range(n):
        for j in range(n):
            print(form.format(a[i][j]),end="")
        print("")

sp(3)
# 1 2 3
# 8 9 4
# 7 6 5

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

def sp_cc(n): # counterclockwise
    a=[[0 for x in range(n)] for y in range(n)]
    last=1
    for k in range(n//2+1):
      for j in range(n-k-1,k-1,-1):
          a[n-k-1][j]=last
          last+=1
      for i in range(n-k-2,k-1,-1):
          a[i][j]=last
          last+=1
      for j in range(k+1,n-k):
          a[i][j]=last
          last+=1
      for i in range(k+1,n-k-1):
          a[i][j]=last
          last+=1

    s=int(math.log(n*n,10))+2 # compute size of cell for printing
    form="{:"+str(s)+"}"
    for i in range(n):
        for j in range(n):
            print(form.format(a[i][j]),end="")
        print("")

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

açıklama

Spiral eşmerkezli karelerden yapılır, örneğin saat yönünde dönüşlü 5x5 kare şöyle görünür:

 5x5        3x3      1x1

>>>>>
^   v       >>>
^   v   +   ^ v   +   >
^   v       <<<
<<<<v

( >>>>>"5 kez sağa git" veya sütun dizini 5 kez artır,v aşağı veya satır dizini artır vb. anlamına gelir)

Tüm kareler boyutlarına kadar aynı, eşmerkezli karelerin üzerinden geçtim.

Her kare için kodun dört döngüsü vardır (her bir taraf için bir tane), her döngüde sütunları veya satır dizinini artırır veya azaltırız. Eğer isıra göstergesi ve bir jartan: - daha sonra kolon göstergesi 5x5 kare inşa edilebilir j0 ile 4 (5 kez) göre - artan i1: 4 (4 kere) göre - azaltma j3 0 (4 kez) göre - azaltmai 3'ten 1'e (3 kez)

Bir sonraki kareler için (3x3 ve 1x1) aynısını yapıyoruz, ancak başlangıç ​​ve son endeksleri uygun şekilde kaydırıyoruz. kHer eşmerkezli kare için bir indeks kullandım , n // 2 + 1 eşmerkezli kareler var.

Son olarak, güzel baskı için biraz matematik.

Dizinleri yazdırmak için:

def spi_cc(n): # counter-clockwise
    a=[[0 for x in range(n)] for y in range(n)]
    ind=[]
    last=n*n
    for k in range(n//2+1):
      for j in range(n-k-1,k-1,-1):
          ind.append((n-k-1,j))
      for i in range(n-k-2,k-1,-1):
          ind.append((i,j))
      for j in range(k+1,n-k):
          ind.append((i,j))
      for i in range(k+1,n-k-1):
          ind.append((i,j))

    print(ind)

spi_cc(5)

1

İşte c #, linq'ish.

public static class SpiralCoords
{
  public static IEnumerable<Tuple<int, int>> GenerateOutTo(int radius)
  {
    //TODO trap negative radius.  0 is ok.

    foreach(int r in Enumerable.Range(0, radius + 1))
    {
      foreach(Tuple<int, int> coord in GenerateRing(r))
      {
        yield return coord;
      }
    }
  }

  public static IEnumerable<Tuple<int, int>> GenerateRing(int radius)
  {
    //TODO trap negative radius.  0 is ok.

    Tuple<int, int> currentPoint = Tuple.Create(radius, 0);
    yield return Tuple.Create(currentPoint.Item1, currentPoint.Item2);

    //move up while we can
    while (currentPoint.Item2 < radius)
    {
      currentPoint.Item2 += 1;
      yield return Tuple.Create(currentPoint.Item1, currentPoint.Item2);
    }
    //move left while we can
    while (-radius < currentPoint.Item1)
    {
      currentPoint.Item1 -=1;
      yield return Tuple.Create(currentPoint.Item1, currentPoint.Item2);    
    }
    //move down while we can
    while (-radius < currentPoint.Item2)
    {
      currentPoint.Item2 -= 1;
      yield return Tuple.Create(currentPoint.Item1, currentPoint.Item2);
    }
    //move right while we can
    while (currentPoint.Item1 < radius)
    {
      currentPoint.Item1 +=1;
      yield return Tuple.Create(currentPoint.Item1, currentPoint.Item2);    
    }
    //move up while we can
    while (currentPoint.Item2 < -1)
    {
      currentPoint.Item2 += 1;
      yield return Tuple.Create(currentPoint.Item1, currentPoint.Item2);
    }
  }

}

Sorunun ilk örneği (3x3) şöyle olacaktır:

var coords = SpiralCoords.GenerateOutTo(1);

Sorunun ikinci örneği (5x3) şöyle olacaktır:

var coords = SpiralCoords.GenerateOutTo(2).Where(x => abs(x.Item2) < 2);

1

Bu biraz farklı bir versiyonudur - kullanım çalışıyor recursionve iteratorsLUA içinde. Her adımda program matrisin içine doğru iner ve döngüler. Ayrıca spiral clockwiseveya anticlockwise. Çıktı sağ alt köşelerden başlar ve tekrar tekrar merkeze doğru döngüler.

local row, col, clockwise

local SpiralGen
SpiralGen = function(loop)  -- Generator of elements in one loop
    local startpos = { x = col - loop, y = row - loop }
    local IteratePosImpl = function() -- This function calculates returns the cur, next position in a loop. If called without check, it loops infinitely

        local nextpos = {x = startpos.x, y = startpos.y}        
        local step = clockwise and {x = 0, y = -1} or { x = -1, y = 0 }

        return function()

            curpos = {x = nextpos.x, y = nextpos.y}
            nextpos.x = nextpos.x + step.x
            nextpos.y = nextpos.y + step.y
            if (((nextpos.x == loop or nextpos.x == col - loop + 1) and step.y == 0) or 
                ((nextpos.y == loop or nextpos.y == row - loop + 1) and step.x == 0)) then --Hit a corner in the loop

                local tempstep = {x = step.x, y = step.y}
                step.x = clockwise and tempstep.y or -tempstep.y
                step.y = clockwise and -tempstep.x or tempstep.x
                -- retract next step with new step
                nextpos.x = curpos.x + step.x 
                nextpos.y = curpos.y + step.y

            end         
            return curpos, nextpos
        end
    end
    local IteratePos = IteratePosImpl() -- make an instance
    local curpos, nextpos = IteratePos()
    while (true) do
        if(nextpos.x == startpos.x and nextpos.y == startpos.y) then            
            coroutine.yield(curpos)
            SpiralGen(loop+1) -- Go one step inner, since we're done with this loop
            break -- done with inner loop, get out
        else
            if(curpos.x < loop + 1 or curpos.x > col - loop or curpos.y < loop + 1 or curpos.y > row - loop) then
                break -- done with all elemnts, no place to loop further, break out of recursion
            else
                local curposL = {x = curpos.x, y = curpos.y}
                curpos, nextpos = IteratePos()
                coroutine.yield(curposL)
            end
        end     
    end 
end


local Spiral = function(rowP, colP, clockwiseP)
    row = rowP
    col = colP
    clockwise = clockwiseP
    return coroutine.wrap(function() SpiralGen(0) end) -- make a coroutine that returns all the values as an iterator
end


--test
for pos in Spiral(10,2,true) do
    print (pos.y, pos.x)
end

for pos in Spiral(10,9,false) do
    print (pos.y, pos.x)
end

1

// PHP uygulaması

function spiral($n) {

    $r = intval((sqrt($n + 1) - 1) / 2) + 1;

    // compute radius : inverse arithmetic sum of 8+16+24+...=
    $p = (8 * $r * ($r - 1)) / 2;
    // compute total point on radius -1 : arithmetic sum of 8+16+24+...

    $en = $r * 2;
    // points by face

    $a = (1 + $n - $p) % ($r * 8);
    // compute de position and shift it so the first is (-r,-r) but (-r+1,-r)
    // so square can connect

    $pos = array(0, 0, $r);
    switch (intval($a / ($r * 2))) {
        // find the face : 0 top, 1 right, 2, bottom, 3 left
        case 0:
            $pos[0] = $a - $r;
            $pos[1] = -$r;
            break;
        case 1:
            $pos[0] = $r;
            $pos[1] = ($a % $en) - $r;
            break;
        case 2:
            $pos[0] = $r - ($a % $en);
            $pos[1] = $r;
            break;
        case 3:
            $pos[0] = -$r;
            $pos[1] = $r - ($a % $en);
            break;
    }
    return $pos;
}

for ($i = 0; $i < 168; $i++) {

    echo '<pre>';
    print_r(spiral($i));
    echo '</pre>';
}

1

İşte bu sorunun bir JavaScript (ES6) yinelemeli çözümü:

let spiralMatrix = (x, y, step, count) => {
    let distance = 0;
    let range = 1;
    let direction = 'up';

    for ( let i = 0; i < count; i++ ) {
        console.log('x: '+x+', y: '+y);
        distance++;
        switch ( direction ) {
            case 'up':
                y += step;
                if ( distance >= range ) {
                    direction = 'right';
                    distance = 0;
                }
                break;
            case 'right':
                x += step;
                if ( distance >= range ) {
                    direction = 'bottom';
                    distance = 0;
                    range += 1;
                }
                break;
            case 'bottom':
                y -= step;
                if ( distance >= range ) {
                    direction = 'left';
                    distance = 0;
                }
                break;
            case 'left':
                x -= step;
                if ( distance >= range ) {
                    direction = 'up';
                    distance = 0;
                    range += 1;
                }
                break;
            default:
                break;
        }
    }
}

Bunu nasıl kullanacağınız aşağıda açıklanmıştır:

spiralMatrix(0, 0, 1, 100);

Bu, 1 adımı ile koordinatlardan (x = 0, y = 0) başlayarak ve toplam öğe sayısı 100'e eşit olan bir dış spiral oluşturacaktır. Uygulama her zaman hareketi şu sıraya göre başlatır: sağ, alt, ayrıldı.

Bu uygulamanın kare matrisler oluşturduğunu lütfen unutmayın.


1

İşte Julia'da bir cevap: yaklaşımım, (0,0)her karenin yan uzunluğuna sahip olduğu orijin etrafında eşmerkezli karelerdeki ('spiraller') noktaları m = 2n + 1anahtar olarak konum numaralarıyla (başlangıç ​​için 1'den başlayarak) sıralı bir sözlük oluşturmaktır. ve karşılık gelen koordinatı değer olarak gösterir.

Spiral başına maksimum yer olduğu için (n,-n), noktaların geri kalanı bu noktadan geriye doğru, yani sağ alt köşeden m-1birimlerle geriye doğru çalışarak ve ardından dikey 3 segment için tekrarlanarak bulunabilir.m-1 .

Bu işlem, sarmalın bu ters sayma işleminden ziyade nasıl ilerlediğine karşılık gelen aşağıda ters sırada yazılır, yani ra[sağa ​​yükselen] segment, azaltılır 3(m+1), sonra la[soldan yükselir] 2(m+1)ve böylece - umarım bu kendiliğinden açıklayıcıdır .

import DataStructures: OrderedDict, merge

function spiral(loc::Int)
    s = sqrt(loc-1) |> floor |> Int
    if s % 2 == 0
        s -= 1
    end
    s = (s+1)/2 |> Int
    return s
end

function perimeter(n::Int)
    n > 0 || return OrderedDict([1,[0,0]])
    m = 2n + 1 # width/height of the spiral [square] indexed by n
    # loc_max = m^2
    # loc_min = (2n-1)^2 + 1
    ra = [[m^2-(y+3m-3), [n,n-y]] for y in (m-2):-1:0]
    la = [[m^2-(y+2m-2), [y-n,n]] for y in (m-2):-1:0]
    ld = [[m^2-(y+m-1), [-n,y-n]] for y in (m-2):-1:0]
    rd = [[m^2-y, [n-y,-n]] for y in (m-2):-1:0]
    return OrderedDict(vcat(ra,la,ld,rd))
end

function walk(n)
    cds = OrderedDict(1 => [0,0])
    n > 0 || return cds
    for i in 1:n
        cds = merge(cds, perimeter(i))
    end
    return cds
end

İlk örneğiniz için, m = 3n'yi bulmak için denkleme takmak n = (5-1)/2 = 2ve walk(2)koordinatlara konumların sıralı bir sözlüğünü verir; bu, sözlüğün valsalanına erişerek yalnızca bir koordinat dizisine dönüştürebilirsiniz :

walk(2)
DataStructures.OrderedDict{Any,Any} with 25 entries:
  1  => [0,0]
  2  => [1,0]
  3  => [1,1]
  4  => [0,1]
    => 

[(co[1],co[2]) for co in walk(2).vals]
25-element Array{Tuple{Int64,Int64},1}:
 (0,0)  
 (1,0)  
        
 (1,-2) 
 (2,-2)

Bazı işlevler için [ör. norm] Koordinatları dizilerden ziyade diziler halinde bırakmak tercih edilebilir Tuple{Int,Int}, ancak burada bunları tuples olarak değiştiriyorum (x,y)- talep edildiğinde liste kavrayışı kullanarak.

(Bu çözelti hala dışı kılavuz değerlerini hesaplar not) olmayan bir kare matris belirtilmemişse "destek", ancak bağlam sadece aralığına filtre istiyorum xile y(burada örnek olarak x=5, y=3tam spiral hesaplandıktan sonra) sonra intersectbu matris değerlerine karşı walk.

grid = [[x,y] for x in -2:2, y in -1:1]
5×3 Array{Array{Int64,1},2}:
 [-2,-1]  [-2,0]  [-2,1]
                  
 [2,-1]   [2,0]   [2,1]

[(co[1],co[2]) for co in intersect(walk(2).vals, grid)]
15-element Array{Tuple{Int64,Int64},1}:
 (0,0)  
 (1,0)  
  
 (-2,0) 
 (-2,-1)

1

Sorunuz spiral bellek adı verilen bir soruya benziyor. Bu problemde, ızgaradaki her kare, başlangıç ​​noktasında bulunan 1 numaradan başlayarak spiral bir düzende ayrılır. Ve sonra dışarı doğru spirating yaparken geri sayım. Örneğin:

17  16  15  14  13

18   5   4   3  12

19   6   1   2  11

20   7   8   9  10

21  22  23  ---->

Bu sarmal paterni takip eden her bir sayının koordinatlarını hesaplamak için kullandığım çözüm aşağıdaki gibidir:

def spiral_pattern(num):
    x = y = 0
    for _ in range(num-1):
        x, y = find_next(x, y)
    yield (x, y)


def find_next(x, y):
    """find the coordinates of the next number"""
    if x == 0 and y == 0:
        return 1, 0

    if abs(x) == abs(y):
        if x > 0 and y > 0:
            x, y = left(x, y)
        elif x < 0 and y > 0:
            x, y = down(x, y)
        elif x < 0 and y < 0:
            x, y = right(x, y)
        elif x > 0 and y < 0:
            x, y = x+1, y
    else:
        if x > y and abs(x) > abs(y):
            x, y = up(x, y)
        elif x < y and abs(x) < abs(y):
            x, y = left(x, y)
        elif x < y and abs(x) > abs(y):
            x, y = down(x, y)
        elif x > y and abs(x) < abs(y):
            x, y = right(x, y)

    return x, y

def up(x, y):
    return x, y+1


def down(x, y):
    return x, y-1


def left(x, y):
    return x-1, y


def right(x, y):
    return x+1, y

0

Bu kendi çözümünüze dayanıyor, ancak köşeleri bulma konusunda daha akıllı olabiliriz. Bu, M ve N çok farklıysa dışarıdaki alanları nasıl atlayabileceğinizi görmenizi kolaylaştırır.

def spiral(X, Y):
    x = y = 0
    dx = 0
    dy = -1
    s=0
    ds=2
    for i in range(max(X, Y)**2):
            if abs(x) <= X and abs(y) <= Y/2:
                    print (x, y)
                    # DO STUFF...
            if i==s:
                    dx, dy = -dy, dx
                    s, ds = s+ds/2, ds+1
            x, y = x+dx, y+dy

ve O (max (n, m) ^ 2) 'den daha iyi olan jeneratör bazlı bir çözelti, O (nm + abs (nm) ^ 2)' dir, çünkü çözeltinin bir parçası değilse bütün şeritleri atlar.

def spiral(X,Y):
X = X+1>>1
Y = Y+1>>1
x = y = 0
d = side = 1
while x<X or y<Y:
    if abs(y)<Y:
        for x in range(x, x+side, d):
            if abs(x)<X: yield x,y
        x += d
    else:
        x += side
    if abs(x)<X:
        for y in range(y, y+side, d):
            if abs(y)<Y: yield x,y
        y += d
    else:
        y += side
    d =-d
    side = d-side

0
Here is my attempt for simple C solution. First print the outer spiral and move one block inside..and repeat.

#define ROWS        5
#define COLS        5
//int A[ROWS][COLS] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {11, 12, 13, 14}, {15, 16, 17, 18} };
//int A[ROWS][COLS] = { {1, 2, 3}, {6, 7, 8}, { 12, 13, 14} };
//int A[ROWS][COLS] = { {1, 2}, {3, 4}};

int A[ROWS][COLS] = { {1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {11, 12, 13, 14, 15} , {16, 17, 18, 19, 20}, {21, 22, 23, 24, 25} };


void print_spiral(int rows, int cols)
{
    int row = 0;
    int offset = 0;

    while (offset < (ROWS - 1)) {
        /* print one outer loop at a time. */
        for (int col = offset; col <= cols; col++) {
            printf("%d ", A[offset][col]);
        }

        for (row = offset + 1; row <= rows; row++) {
            printf("%d ", A[row][cols]);
        }

        for (int col = cols - 1; col >= offset; col--) {
            printf("%d ", A[rows][col]);
        }

        for (row = rows - 1; row >= offset + 1; row--) {
            printf("%d ", A[row][offset]);
        }

       /* Move one block inside */
        offset++;
        rows--;
        cols--;
    }
    printf("\n");
}

int _tmain(int argc, _TCHAR* argv[])
{
    print_spiral(ROWS-1, COLS-1);
    return 0;
}

0

Bu benim en az Java bilgimden yapılmış çok kötü bir çözüm. Burada birimleri sarmal bir alana yerleştirmeliyim. Birimler diğer birimlerin üzerine veya dağlara veya okyanusa yerleştirilemez.

Açık olmak gerekirse. Bu iyi bir çözüm değil. Bu, diğer insanların eğlencesinin ne kadar kötü yapılabileceğine gülmesi için eklenen çok kötü bir çözümdür

private void unitPlacementAlgorithm(Position p, Unit u){
    int i = p.getRow();
    int j = p.getColumn();

    int iCounter = 1;
    int jCounter = 0;

    if (getUnitAt(p) == null) {
            unitMap.put(p, u);
    } else {
        iWhileLoop(i, j, iCounter, jCounter, -1, u);
    }

}

private void iWhileLoop(int i, int j, int iCounter, int jCounter, int fortegn, Unit u){
    if(iCounter == 3) {
        for(int k = 0; k < 3; k++) {
            if(k == 2) { //This was added to make the looping stop after 9 units
                System.out.println("There is no more room around the city");
                return; 
            }
            i--;

            if (getUnitAt(new Position(i, j)) == null 
                && !(getTileAt(new Position(i, j)).getTypeString().equals(GameConstants.OCEANS)) 
                && !(getTileAt(new Position(i, j)).getTypeString().equals(GameConstants.MOUNTAINS))) {
                    unitMap.put(new Position(i, j), u);
                    return;
            }
            iCounter--;
        }
    }

    while (iCounter > 0) {
        if (fortegn > 0) {
            i++;
        } else {
            i--;
        }

        if (getUnitAt(new Position(i, j)) == null 
            && !(getTileAt(new Position(i, j)).getTypeString().equals(GameConstants.OCEANS)) 
            && !(getTileAt(new Position(i, j)).getTypeString().equals(GameConstants.MOUNTAINS))) {
                unitMap.put(new Position(i, j), u);
                return;
        }
        iCounter--;
        jCounter++;
    }
    fortegn *= -1;
    jWhileLoop(i, j, iCounter, jCounter, fortegn, u);
}

private void jWhileLoop(int i, int j, int iCounter, int jCounter,
        int fortegn, Unit u) {
    while (jCounter > 0) {
        if (fortegn > 0) {
            j++;
        } else {
            j--;
        }

        if (getUnitAt(new Position(i, j)) == null 
            && !(getTileAt(new Position(i, j)).getTypeString().equals(GameConstants.OCEANS)) 
            && !(getTileAt(new Position(i, j)).getTypeString().equals(GameConstants.MOUNTAINS))) {
                unitMap.put(new Position(i, j), u);
                return;

        }
        jCounter--;
        iCounter++;
        if (jCounter == 0) {
            iCounter++;
        }

    }
    iWhileLoop(i, j, iCounter, jCounter, fortegn, u);
}

Bunu gerçekten okuyabilen herkese cudos

Bonus soru: Bu "algoritmanın" çalışma süresi nedir? : P


1
+1 çünkü " Bu, diğer insanların eğlencesinin ne kadar kötü yapılabileceğine gülmesi için eklenen çok kötü bir çözümdür ".
Oriol

0

AutoIt için çözüm

#include <Math.au3>
#include <Array.au3>

Func SpiralSearch($xMax,$yMax)
    $x = 0
    $y = 0
    $dx = 0
    $dy = -1
    for $i=0 To _max($xMax, $yMax)^2-1 Step 1
        if -$xMax/2 < $x and $x <= $xMax/2 And -$yMax/2 < $y And $y <= $yMax/2 Then
            MsgBox(0, "We are here ", $x & " " & $y)
        EndIf
        if $x == $y or ($x < 0 and $x == -$y) or ($x > 0 and $x == 1-$y) Then
            _ArraySwap ($dx, $dy)
            $dx=-$dx
        EndIf
        $x += $dx
        $y += $dy
    Next
EndFunc

0

Geçenlerde benzer bir zorluk yaşadım ve bir 2D dizi oluşturmak ve sonuçları sıralamak ve yazdırmak için bir spiral matris algoritması kullanmak zorunda kaldım. Bu C # kodu bir N, N 2D dizisi ile çalışacaktır. Netlik için ayrıntılıdır ve muhtemelen ihtiyaçlarınıza uyacak şekilde yeniden faktörlendirilebilir.

//CREATE A NEW MATRIX OF SIZE 4 ROWS BY 4 COLUMNS - SCALE MATRIX SIZE HERE
SpiralMatrix SM = new SpiralMatrix(4, 4);
string myData = SM.Read();


public class SpiralMatrix
{
    //LETS BUILD A NEW MATRIX EVERY TIME WE INSTANTIATE OUR CLASS
    public SpiralMatrix(int Rows, int Cols)
    {
        Matrix = new String[Rows, Cols];

        int pos = 1;
        for(int r = 0; r<Rows; r++){
            for (int c = 0; c < Cols; c++)
            {
                //POPULATE THE MATRIX WITH THE CORRECT ROW,COL COORDINATE
                Matrix[r, c] = pos.ToString();
                pos++;
            }
        }
    }

    //READ MATRIX
    public string Read()
    {
        int Row = 0;
        int Col = 0;

        string S = "";
        bool isDone = false;

        //CHECK tO SEE IF POSITION ZERO IS AVAILABLE
        if(PosAvailable(Row, Col)){
            S = ConsumePos(Row, Col);
        }


        //START READING SPIRAL
        //THIS BLOCK READS A FULL CYCLE OF RIGHT,DOWN,LEFT,UP EVERY ITERATION
        while(!isDone)
        {
            bool goNext = false;

            //READ ALL RIGHT SPACES ON THIS PATH PROGRESSION
            while (PosAvailable(Row, Col+1))
            {
                //Is ReadRight Avail
                Col++;
                S += ConsumePos(Row, Col);
                goNext = true;
            }

            //READ ALL DOWN SPACES ON THIS PATH PROGRESSION
            while(PosAvailable(Row+1, Col)){
                //Is ReadDown Avail
                Row++;
                S += ConsumePos(Row, Col);
                goNext = true;
            }

            //READ ALL LEFT SPACES ON THIS PATH PROGRESSION
            while(PosAvailable(Row, Col-1)){
                //Is ReadLeft Avail
                Col--;
                S += ConsumePos(Row, Col);
                goNext = true;
            }

            //READ ALL UP SPACES ON THIS PATH PROGRESSION
            while(PosAvailable(Row-1, Col)){
                //Is ReadUp Avail
                Row--;
                S += ConsumePos(Row, Col);
                goNext = true;
            }

            if(!goNext){
                //DONE - SET EXIT LOOP FLAG
                isDone = true;
            }
        }

        return S;
    }

    //DETERMINE IF THE POSITION IS AVAILABLE
    public bool PosAvailable(int Row, int Col)
    {
        //MAKE SURE WE ARE WITHIN THE BOUNDS OF THE ARRAY
        if (Row < Matrix.GetLength(0) && Row >= 0
            && Col < Matrix.GetLength(1) && Col >= 0)
        {
            //CHECK COORDINATE VALUE
            if (Matrix[Row, Col] != ConsumeChar)
                return true;
            else
                return false;
        }
        else
        {
            //WE ARE OUT OF BOUNDS
            return false;
        }
    }

    public string ConsumePos(int Row, int Col)
    {
        string n = Matrix[Row, Col];
        Matrix[Row, Col] = ConsumeChar;
        return n;
    }

    public string ConsumeChar = "X";
    public string[,] Matrix;
}

0

Bunu, Javascript'teki spirali tuval en boy oranına ayarlayan bir arkadaşımla yaptım. Tüm görüntüyü dolduran bir piksel evrim piksel için elde ettiğim en iyi çözüm.

Umarım bazılarına yardımcı olur.

var width = 150;
var height = 50;

var x = -(width - height)/2;
var y = 0;
var dx = 1;
var dy = 0;
var x_limit = (width - height)/2;
var y_limit = 0;
var counter = 0;

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');

setInterval(function(){
   if ((-width/2 < x && x <= width/2)  && (-height/2 < y && y <= height/2)) {
       console.log("[ " + x + " , " +  y + " ]");
       ctx.fillStyle = "#FF0000";
       ctx.fillRect(width/2 + x, height/2 - y,1,1);
   }
   if( dx > 0 ){//Dir right
       if(x > x_limit){
           dx = 0;
           dy = 1;
       }
   }
   else if( dy > 0 ){ //Dir up
       if(y > y_limit){
           dx = -1;
           dy = 0;
       }
   }
   else if(dx < 0){ //Dir left
       if(x < (-1 * x_limit)){
           dx = 0;
           dy = -1;
       }
   }
   else if(dy < 0) { //Dir down
       if(y < (-1 * y_limit)){
           dx = 1;
           dy = 0;
           x_limit += 1;
           y_limit += 1;
       }
   }
   counter += 1;
   //alert (counter);
   x += dx;
   y += dy;      
}, 1);

Http://jsfiddle.net/hitbyatruck/c4Kd6/ adresinde çalıştığını görebilirsiniz . Javascript değişkenlerinde ve HTML'deki niteliklerde tuvalin genişliğini ve yüksekliğini değiştirdiğinizden emin olun.


0

Javascript'te eğlenmek için:

function spiral(x, y) {
  var iy = ix = 0
    , hr = (x - 1) / 2
    , vr = (y - 1) / 2
    , tt = x * y
    , matrix = []
    , step = 1
    , dx = 1
    , dy = 0;

  while(matrix.length < tt) {

    if((ix <= hr && ix >= (hr * -1)) && (iy <= vr && (iy >= (vr * -1)))) {
      console.log(ix, iy);
      matrix.push([ix, iy]);
    }

    ix += dx;
    iy += dy;

    // check direction
    if(dx !== 0) {
      // increase step
      if(ix === step && iy === (step * -1)) step++;

      // horizontal range reached
      if(ix === step || (ix === step * -1)) {
        dy = (ix === iy)? (dx * -1) : dx;
        dx = 0;  
      }
    } else {
      // vertical range reached
      if(iy === step || (iy === step * -1)) {
        dx = (ix === iy)? (dy * -1) : dy;
        dy = 0;
      }
    }
  }

  return matrix;
}

var sp = spiral(5, 3);

0

C # sürümü, kare olmayan boyutları da işler.

private static Point[] TraverseSpiral(int width, int height) {
    int numElements = width * height + 1;
    Point[] points = new Point[numElements];

    int x = 0;
    int y = 0;
    int dx = 1;
    int dy = 0;
    int xLimit = width - 0;
    int yLimit = height - 1;
    int counter = 0;

    int currentLength = 1;
    while (counter < numElements) {
        points[counter] = new Point(x, y);

        x += dx;
        y += dy;

        currentLength++;
        if (dx > 0) {
            if (currentLength >= xLimit) {
                dx = 0;
                dy = 1;
                xLimit--;
                currentLength = 0;
            }
        } else if (dy > 0) {
            if (currentLength >= yLimit) {
                dx = -1;
                dy = 0;
                yLimit--;
                currentLength = 0;
            }
        } else if (dx < 0) {
            if (currentLength >= xLimit) {
                dx = 0;
                dy = -1;
                xLimit--;
                currentLength = 0;
            }
        } else if (dy < 0) {
            if (currentLength >= yLimit) {
                dx = 1;
                dy = 0;
                yLimit--;
                currentLength = 0;
            }
        }

        counter++;
    }

    Array.Reverse(points);
    return points;
}

0

Farklı bir amaç için tasarladığım bu kodu paylaşıyorum; sütun dizisi "X" ve dizi elemanı @ spiral endeksi "index" "Y" satır numarasını bulmakla ilgilidir. Bu işlev, matrisin "w" genişliğini ve "h" yüksekliğini ve gerekli "index" değerini alır. Tabii ki, bu işlev aynı aynı çıktıyı üretmek için kullanılabilir. Bence mümkün olan en hızlı yöntem (onları taramak yerine hücrelere atlıyor).

    rec BuildSpiralIndex(long w, long h, long index = -1)
    {  
        long count = 0 , x = -1,  y = -1, dir = 1, phase=0, pos = 0,                            length = 0, totallength = 0;
        bool isVertical = false;
        if(index>=(w*h)) return null;

        do 
        {                
            isVertical = (count % 2) != 0;
            length = (isVertical ? h : w) - count/2 - count%2 ;
            totallength += length;
            count++;
        } while(totallength<index);

        count--; w--; h--;
        phase = (count / 4); pos = (count%4);
        x = (pos > 1 ? phase : w - phase);
        y = ((pos == 1 || pos == 2) ? h - phase : phase) + (1 * (pos == 3 ? 1 : 0));
        dir = pos > 1 ? -1 : 1;
        if (isVertical) y -= (totallength - index - 1) * dir;
        else x -= (totallength - index -1) * dir;
        return new rec { X = x, Y = y };
    }

0

Can Berk Güder cevabını kullanarak python saat yönünde dönen spiral kod .

def spiral(X, Y):
    x = y = 0
    dx = 0
    dy = 1
    for i in range(max(X, Y)**2):
        if (-X/2 < x <= X/2) and (-Y/2 < y <= Y/2):
            print (x, y)
            # DO STUFF...
        if x == -y or (x < 0 and x == y) or (x > 0 and x-1 == y):
            dx, dy = dy, -dx
        x, y = x+dx, y+dy

1
Saat yönünde 🔃 ve ben Can Berk Güder'den bahsettim. Orijinal soru saat yönünün tersine 🔄 içindir. Saat yönünde bir fonksiyona ihtiyacım vardı, bu yüzden onu orada bırakmanın yararlı olacağını hissettim.
adrianmelic

0

Davidont'un VB.Net'teki mükemmel çözümü

    Public Function Spiral(n As Integer) As RowCol
    ' given n an index in the squared spiral
    ' p the sum of point in inner square
    ' a the position on the current square
    ' n = p + a
    ' starts with row 0 col -1
    Dim r As Integer = CInt(Math.Floor((Math.Sqrt(n + 1) - 1) / 2) + 1)

    ' compute radius : inverse arithmetic sum of 8+16+24+...=
    Dim p As Integer = (8 * r * (r - 1)) \ 2
    ' compute total point on radius -1 : arithmetic sum of 8+16+24+...

    Dim en As Integer = r * 2
    ' points by face

    Dim a As Integer = (1 + n - p) Mod (r * 8)
    ' compute the position and shift it so the first is (-r,-r) but (-r+1,-r)
    ' so square can connect

    Dim row As Integer
    Dim col As Integer

    Select Case Math.Floor(a \ (r * 2))
        ' find the face : 0 top, 1 right, 2, bottom, 3 left
        Case 0
            row = a - r
            col = -r
        Case 1
            row = r
            col = (a Mod en) - r
        Case 2
            row = r - (a Mod en)
            col = r
        Case 3
            row = -r
            col = r - (a Mod en)
    End Select

    Return New RowCol(row, col)
End Function
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.