सर्पिल में लूपिंग


154

एक दोस्त को एक एल्गोरिथ्म की आवश्यकता थी जो उसे एनएक्सएम मैट्रिक्स (एन और एम विषम) के तत्वों के माध्यम से लूप देगा। मैं एक समाधान के साथ आया था, लेकिन मैं देखना चाहता था कि मेरे साथी SO'ers बेहतर समाधान के साथ आ सकते हैं या नहीं।

मैं इस प्रश्न के उत्तर के रूप में अपना समाधान पोस्ट कर रहा हूं।

उदाहरण आउटपुट:

एक 3x3 मैट्रिक्स के लिए, आउटपुट होना चाहिए:

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

3x3 मैट्रिक्स

इसके अलावा, एल्गोरिथ्म को गैर-वर्ग मैट्रिक्स का समर्थन करना चाहिए, इसलिए उदाहरण के लिए 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)

5x3 मैट्रिक्स


क्या आप समझा सकते हैं कि आप गैर-वर्ग मैट्रिस के लिए क्या चाहते हैं? आपके समाधान में (2,1) से (-2,1) तक "कूद" है - क्या यह इरादा है? [जैसे 7x3 मैट्रिक्स के लिए, इसमें दो और "जंप" होंगे, और (2k + 1) x3 मैट्रिक्स के लिए इसमें 2k-3 जंप होंगे?]
श्रीवत्सर 18

3
हां, जानबूझकर कूदता है। मैंने 5x3 मैट्रिक्स छवि के साथ प्रश्न को अपडेट किया है। जैसा कि आप छवि से देख सकते हैं, हम ऊपर और नीचे की पंक्तियों को छोड़ रहे हैं।
बेर गर्डर

ठीक है, तो आपका अपना कोड सबसे साफ लगता है। और यद्यपि यह अपमानजनक है: आपने उन छवियों को कैसे उत्पन्न किया? :)
श्रीवत्सआर

=)) मैंने उन्हें उत्पन्न नहीं किया। वास्तव में, मैंने जिस तरह से उन्हें बनाया है वह काफी बेवकूफाना है। मैंने OO.org Calc में तालिकाओं का निर्माण किया, एक स्क्रीनशॉट लिया, और GIMP में स्क्रीनशॉट को संपादित किया। =))
कर सकते हैं Berk गर्डर

1
@ हाँ: मुझे नहीं पता कि मेरे मित्र को इसकी आवश्यकता क्यों है, लेकिन उन्होंने कहा कि वे मैट्रिक्स के सदस्यों को खोज एल्गोरिदम में केंद्र के करीब लाना चाहते हैं।
कैन बर्क गर्डर

जवाबों:


63

यहाँ मेरा समाधान है (पायथन में):

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
यह इसे लिखने का सबसे अच्छा तरीका है, जहाँ तक मैं देख सकता हूँ। एकमात्र संभव सुधार यह होगा कि इसे ओ (एमएन) के बजाय ओ (अधिकतम (एम, एन) ^ 2) बनाकर सीधे उन अतीत (एक्स, वाई) को छोड़ दिया जाएगा जो मुद्रित नहीं होने जा रहे हैं, लेकिन यह कोड बना देगा थोड़ा और बदसूरत।
श्रीवत्सआर

मैं अपने समाधान का अनुकूलन कर रहा हूं और यह बहुत करीब है जो आपने पहले ही प्राप्त कर लिया है। यह एक बहुत अच्छा उपाय है जो मुझे लगता है। श्रीवत्सआर के सुझाव के अलावा, और एक्स / 2 और वाई / 2 प्रत्येक पुनरावृत्ति की गणना नहीं करने जैसे सामान, शैली को छोड़कर सुधारने के लिए बहुत ज्यादा नहीं है।
२०:०२

Matlab के लिए कोई समाधान ?!
सैम

क्या यह छवि बफर डेटा तक पहुंचने के लिए अच्छे कैश सुसंगतता के लिए देता है? (यहां बहुत सारे उत्तर हैं, लेकिन बहुत अधिक जानकारी नहीं है, जिसके बारे में उच्च प्रदर्शन छवि संचालन के लिए सबसे अच्छा काम करता है)
ideasman42

@ ideasman42 - जो खेल में नहीं आता है, क्योंकि परिणाम हमेशा निर्देशांक के समान सर्पिल पैटर्न होता है। सर्पिल पैटर्न कैश सुसंगत है या नहीं, मुझे लगता है कि छवि बफर कार्यान्वयन पर निर्भर है। (मेरा अनुमान है कि यह कैश को छवि से चलने के अन्य तरीकों की तुलना में अधिक जोर देगा, जैसे कि लाइन में क्रम से जा रहा है)। लेकिन इन समन्वय के उत्पादन के लिए एल्गोरिथ्म का विकल्प संभवतः कैश को प्रभावित नहीं करेगा।
Raptormeat

31

सी ++ कोई? अजगर से त्वरित अनुवाद, पूर्णता के लिए पोस्ट किया गया

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

तुम भी एस और डी एस का उपयोग कर सकते हैं जैसे मैं उन कोनों का पता लगाने के लिए करता हूं जो विशाल स्थिति से छुटकारा
दिलाते

1
इस पोस्ट के लिए एक संपादन यहाँ सुझाया गया था । हालाँकि संपादन अस्वीकार कर दिया गया था क्योंकि यह आपकी पोस्ट के अर्थ को बदल देता है, आप सुझाए गए परिवर्तनों को शामिल करने पर विचार करना चाह सकते हैं यदि यह ऐसा करने के लिए समझ में आता है।
रॉबर्ट हार्वे

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

विभिन्न प्रोग्रामिंग भाषाओं में लिखे गए इस समस्या के लिए कई प्रस्तावित समाधान हैं, हालांकि वे सभी एक ही दृढ़ दृष्टिकोण से उपजी हैं। मैं एक सर्पिल की गणना की अधिक सामान्य समस्या पर विचार करने जा रहा हूं जिसे प्रेरण के उपयोग से स्पष्ट रूप से व्यक्त किया जा सकता है।

आधार मामला: (0, 0) पर शुरू करें, 1 वर्ग आगे बढ़ें, बाएं मुड़ें, 1 वर्ग आगे बढ़ें, बाएं मुड़ें। आगमनात्मक कदम: आगे बढ़ें एन + 1 वर्ग, बाएं मुड़ें, आगे बढ़ें एन + 1 वर्ग, बाएं मुड़ें।

इस समस्या को व्यक्त करने की गणितीय लालसा दृढ़ता से बताती है कि समाधान की गणना करने के लिए एक सरल एल्गोरिथ्म होना चाहिए। अमूर्तता को ध्यान में रखते हुए, मैंने एल्गोरिथ्म को एक विशिष्ट प्रोग्रामिंग भाषा में लागू करने के लिए नहीं बल्कि छद्म कोड के रूप में चुना है।

पहले मैं लूप्स के 4 जोड़े का उपयोग करते हुए सर्पिल के सिर्फ 2 पुनरावृत्तियों की गणना करने के लिए एक एल्गोरिथ्म पर विचार करूंगा। प्रत्येक जोड़ी की संरचना समान है, फिर भी अपने आप में अलग है। यह पहली बार में पागल लग सकता है (कुछ छोरों को केवल एक बार निष्पादित किया जाता है) लेकिन कदम से कदम मैं परिवर्तन कर दूंगा जब तक कि हम 4 जोड़े छोरों पर नहीं पहुंचते हैं जो समान हैं और इसलिए उन्हें दूसरे लूप के अंदर रखी गई एकल जोड़ी से बदला जा सकता है। यह हमें बिना किसी शर्त के उपयोग के एन पुनरावृत्तियों की गणना का एक सामान्य समाधान प्रदान करेगा।

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

पहला परिवर्तन जो हम करेंगे, वह दिशा के लिए एक नए चर d का परिचय है, जो मान +1 या -1 रखता है। दिशा प्रत्येक जोड़ी छोरों के बाद स्विच करती है। चूँकि हम सभी बिंदुओं पर d के मान को जानते हैं, इसलिए हम प्रत्येक असमानता के प्रत्येक पक्ष को इसके द्वारा गुणा कर सकते हैं, असमानता की दिशा को तदनुसार समायोजित कर सकते हैं और d के किसी भी गुणन को दूसरे स्थिरांक से सरल बना सकते हैं। यह हमें निम्नलिखित के साथ छोड़ देता है।

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

अब हम ध्यान दें कि दोनों x * d और RHS पूर्णांक हैं, इसलिए हम असमानता के परिणाम को प्रभावित किए बिना, RHS से 0 और 1 के बीच किसी भी वास्तविक मूल्य को घटा सकते हैं। हम पैटर्न के अधिक स्थापित करने के लिए छोरों के हर दूसरे जोड़े की असमानताओं से 0.5 घटाना चुनते हैं।

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

अब हम लूप्स के प्रत्येक जोड़े पर उठाए जाने वाले चरणों की संख्या के लिए एक और वैरिएबल एम पेश कर सकते हैं।

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

अंत में, हम देखते हैं कि लूप की प्रत्येक जोड़ी की संरचना समान है और इसे दूसरे लूप के अंदर रखे एक लूप में कम किया जा सकता है। इसके अलावा, वास्तविक मूल्य की संख्या का उपयोग करने से बचने के लिए मैंने एम के प्रारंभिक मूल्य को गुणा किया है; मूल्य m द्वारा वृद्धि की गई है; और 2 से प्रत्येक असमानता के दोनों पक्ष।

यह इस उत्तर की शुरुआत में दिखाए गए समाधान की ओर जाता है।


1
किन परिस्थितियों में आपका अंतिम समाधान समाप्त होगा?
मेरलिन मॉर्गन-ग्राहम

1
इस तरह के पैटर्न प्रिंटिंग का आवेदन क्या है?
आशीष शुक्ला

1
@ MerlynMorgan-Graham यह समाप्त हो जाता है जब कंप्यूटर मेमोरी या पावर से बाहर चला जाता है।
माइक

ऐसा लगता है कि उस समाधान की भव्यता समय और स्मृति बाधाओं की अनदेखी करने से उपजी है। मैं सलाह देता हूं कि यदि कोई हो सके तो टर्मिनेशन कंडीशन (यदि संभव हो) जोड़ दें। मैं इसे उत्तर के शीर्ष पर ले जाने और इसके नीचे व्युत्पत्ति दिखाने की भी सलाह देता हूं।
मेरलिन मॉर्गन-ग्राहम

1
जबकि मूल प्रश्न एक NxM मैट्रिक्स के बारे में था, यह वास्तव में एक बहुत ही उपयोगी उत्तर है यदि आपको जब तक कुछ नहीं मिल जाता है, तब तक आपको सर्पिल-आउटवर्ड की आवश्यकता होती है (यानी तब ब्रेक या वापसी)। बेशक, अन्य टिप्पणियों की तरह, आपको उस समाप्ति की स्थिति को परिभाषित करने की आवश्यकता है या यह हमेशा के लिए चलेगा।
cclogg

16

स्क्वेर्ड सर्पिल में स्थिति ज्ञात करने के लिए ओ (1) समाधान है: फिडल

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
केंद्र से शुरू करने के लिए दो लाइनें जोड़ें। if (n === 0) return [0, 0, r]; --n;फिडल देखें: jsfiddle.net/Wishmesh/nwd9gt1s/2
Maris B.

15

मुझे अजगर के जनरेटर पसंद हैं।

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

के साथ परीक्षण:

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

आपको मिला:

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

सी सर्पिल के आधार पर जावा सर्पिल "कोड गोल्फ" प्रयास।

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

यहां एक सी ++ समाधान है जो दिखाता है कि आप अगले (एक्स, वाई) की गणना सीधे और आसानी से पिछले वाले से कर सकते हैं - वर्तमान दिशा, त्रिज्या, या कुछ और पर नज़र रखने की कोई आवश्यकता नहीं है:

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

यदि आप सभी करने की कोशिश कर रहे हैं तो सर्पिल में पहला एन अंक उत्पन्न होता है (मूल समस्या के बिना एन एक्स एम क्षेत्र में मास्किंग की बाधा), कोड बहुत सरल हो जाता है:

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

चाल यह है कि आप x और y की तुलना यह निर्धारित करने के लिए कर सकते हैं कि आप किस वर्ग में हैं, और यह बताता है कि किस दिशा में जाना है।


5

जावा में TDD।

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

@ इलेप्पी: शायद नहीं - निश्चित रूप से बहुत कम नहीं है - लेकिन मुझे लगता है कि यह टीडीडी का एक अच्छा प्रदर्शन है, और यथोचित स्वच्छ, आसानी से समझने वाला, सही कोड है। मैं इसे छोड़ दूँगा।
कार्ल मैनस्टर

4

यहाँ मेरा समाधान है (रूबी में)

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}),"
}

फिर भी ओ (अधिकतम (एन, एम) ^ 2), लेकिन अच्छी शैली।
त्रिफलक

1
दिशा = -दिशा के बजाय दिशा-निर्देश * = - १? अगर आप d = -d से छोटे हैं तो d * = - 1 भी छोटा है
जॉन ला रूय

3

हास्केल, अपनी पिक लें:

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
कृपया इसे शेख़ी या ट्रोल की टिप्पणी के रूप में न लें, लेकिन भगवान कुरूप है!
पेट्रूज़ा

1
मैं उपरोक्त टिप्पणी से अधिक सहमत नहीं हो सका।
चुपके

यह हास्केल मुझे बहुत फैशनेबल लगता है।

1
हां, लेकिन ध्यान दें कि यह कितना स्पष्ट है। यहां पोस्ट किए गए कुछ अन्य उदाहरणों से इसकी लंबाई की तुलना करें।
रॉबर्ट हार्वे

@Petruza वास्तव में, यह हास्केल में सबसे अच्छा समाधान नहीं है। यहां देखें: rosettacode.org/wiki/Spiral_matrix#Haskell
polkovnikov.ph

2

यह C में है।

मैं खराब परिवर्तनीय नामों को चुनने के लिए हुआ। नामों में टी == शीर्ष, एल == बाएं, बी == नीचे, आर == दाएं। तो, tli ऊपर बाएँ i और brj नीचे दायें 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

मेरे पास एक ओपन सोर्स लाइब्रेरी है, पिक्सकैन , यह एक पायथन लाइब्रेरी है जो विभिन्न स्थानिक पैटर्न में ग्रिड पर पिक्सल्स को स्कैन करने के लिए फ़ंक्शंस प्रदान करती है। स्थानिक पैटर्न में शामिल हैं, परिपत्र, अंगूठियां, ग्रिड, सांप और यादृच्छिक चलता है। विभिन्न परिवर्तन भी हैं (जैसे, क्लिप, स्वैप, घुमाएँ, अनुवाद)। मूल ओपी समस्या को निम्नानुसार हल किया जा सकता है

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

जो अंक देता है

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

पुस्तकालयों जनरेटर और परिवर्तनों को विभिन्न प्रकार के आदेशों और स्थानिक पैटर्न में बिंदुओं को बदलने के लिए जंजीर किया जा सकता है।


2

यहाँ सर्पिल क्लॉक वाइज और वामावर्त में लगातार पूर्णांक मुद्रित करने के लिए पायथन 3 में एक समाधान है।

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

व्याख्या

एक सर्पिल संकेंद्रित वर्गों से बना होता है, उदाहरण के लिए घड़ी के घुमाव के साथ 5x5 वर्ग इस तरह दिखता है:

 5x5        3x3      1x1

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

( >>>>>"5 बार दाईं ओर जाएं" या कॉलम इंडेक्स को 5 गुना vबढ़ाएं , नीचे पंक्ति इंडेक्स बढ़ाएं, आदि)

सभी वर्ग अपने आकार के समान हैं, मैंने गाढ़ा वर्गों पर लूप किया।

प्रत्येक वर्ग के लिए कोड में चार लूप (प्रत्येक पक्ष के लिए एक) होते हैं, प्रत्येक लूप में हम कॉलम या रो इंडेक्स को बढ़ाते या घटाते हैं। यदि iपंक्ति अनुक्रमणिका और jस्तंभ अनुक्रमणिका है, तो 5x5 वर्ग का निर्माण किया जा सकता है: - j0 से 4 तक (5 गुना) - i1 से 4 तक वृद्धि (4 गुना) - j3 से 0 (4 गुना) से घटते - घटते i3 से 1 (3 बार)

अगले वर्गों (3x3 और 1x1) के लिए हम ऐसा ही करते हैं लेकिन प्रारंभिक और अंतिम सूचकांकों को उचित रूप से स्थानांतरित करते हैं। मैंने एक इंडेक्स का इस्तेमाल कियाk प्रत्येक संकेंद्रित वर्ग के लिए , वहाँ n // 2 + 1 संकेंद्रित वर्ग हैं।

अंत में, सुंदर-छपाई के लिए कुछ गणित।

अनुक्रमित मुद्रित करने के लिए:

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

यहाँ 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);
    }
  }

}

प्रश्न का पहला उदाहरण (3x3) होगा:

var coords = SpiralCoords.GenerateOutTo(1);

प्रश्न का दूसरा उदाहरण (5x3) होगा:

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

1

यह थोड़ा अलग संस्करण है - उपयोग करने की कोशिश में recursionऔर iteratorsएलयूए में। प्रत्येक चरण में कार्यक्रम मैट्रिक्स के अंदर और छोरों पर उतरता है। मैंने सर्पिल clockwiseया के लिए एक अतिरिक्त ध्वज भी जोड़ा anticlockwise। आउटपुट निचले दाएं कोने से शुरू होता है और केंद्र की ओर पुनरावृत्ति करता है।

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 कार्यान्वयन

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

इस समस्या का एक जावास्क्रिप्ट (ES6) पुनरावृत्ति समाधान है:

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

इसका उपयोग कैसे करें:

spiralMatrix(0, 0, 1, 100);

यह एक बाहरी सर्पिल बनाएगा, जो 1 के चरण के साथ निर्देशांक (x = 0, y = 0) से शुरू होता है और कुल आइटमों की संख्या 100 के बराबर होती है। कार्यान्वयन हमेशा निम्नलिखित क्रम में आंदोलन शुरू करता है - ऊपर, दाएं, नीचे, बाएं।

कृपया ध्यान दें कि यह कार्यान्वयन वर्ग मैट्रिसेस बनाता है।


1

यहाँ जूलिया में एक उत्तर दिया गया है: मेरा दृष्टिकोण मूल के चारों ओर संकेंद्रित वर्गों ('स्पाइरल्स') में बिंदुओं को निर्दिष्ट करना है (0,0), जहाँ प्रत्येक वर्ग की लंबाई लंबाई है m = 2n + 1, स्थान संख्या के साथ एक शब्दकोश का निर्माण करने के लिए (मूल के लिए 1 से शुरू) कुंजी के रूप में और संबंधित मूल्य के रूप में समन्वय करते हैं।

चूंकि प्रति सर्पिल में अधिकतम स्थान है (n,-n), बाकी बिंदुओं को इस बिंदु से पीछे की ओर काम करके पाया जा सकता है, अर्थात m-1इकाइयों द्वारा नीचे दाएं कोने से , फिर इकाइयों के लंबवत 3 खंडों के लिए दोहराते हुए m-1

इस प्रक्रिया को उल्टे क्रम में नीचे लिखा गया है, इस उलटी गिनती की प्रक्रिया के बजाय सर्पिल कैसे आगे बढ़ता है, अर्थात ra[दायाँ आरोही] खंड इसके द्वारा घटाया जाता है 3(m+1), फिर la[वाम आरोही] द्वारा 2(m+1), और इसी तरह - उम्मीद है कि यह स्व-व्याख्यात्मक है ।

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

इसलिए आपके पहले उदाहरण के लिए, m = 3n को खोजने के लिए समीकरण में प्लग करना n = (5-1)/2 = 2, और walk(2)निर्देशांक को स्थानों का आदेश दिया शब्दकोश देता है, जिसे आप शब्दकोश के valsक्षेत्र तक पहुंचकर निर्देशांक के एक सरणी में बदल सकते हैं :

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)

ध्यान दें कि कुछ कार्यों के लिए [जैसे norm] इसके बजाय सरणियों में निर्देशांक को छोड़ना बेहतर हो सकता है Tuple{Int,Int}, लेकिन यहां मैं (x,y)सूची बोध का उपयोग करते हुए उन्हें ट्यूपल्स में बदल देता हूं - अनुरोध किया गया।

"समर्थन" एक गैर वर्ग मैट्रिक्स निर्दिष्ट नहीं है (ध्यान दें कि यह समाधान अभी भी ऑफ-ग्रिड मूल्यों की गणना करता है), लेकिन के लिए संदर्भ आप केवल श्रृंखला के लिए फिल्टर करना चाहते हैं xद्वारा y(यहाँ के लिए x=5, y=3पूर्ण सर्पिल की गणना के बाद) फिर intersectइस मैट्रिक्स से मूल्यों के खिलाफ 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

आपका प्रश्न सर्पिल मेमोरी नामक प्रश्न जैसा दिखता है। उस समस्या में, ग्रिड पर प्रत्येक वर्ग को 1 से शुरू होने वाले सर्पिल पैटर्न में आवंटित किया जाता है जो मूल पर स्थित होता है। और फिर बाहर की ओर सर्पिल करते हुए गिनती करें। उदाहरण के लिए:

17  16  15  14  13

18   5   4   3  12

19   6   1   2  11

20   7   8   9  10

21  22  23  ---->

इस सर्पिल पैटर्न के बाद प्रत्येक संख्या के निर्देशांक की गणना करने के लिए मेरा समाधान नीचे पोस्ट किया गया है:

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

यह आपके स्वयं के समाधान पर आधारित है, लेकिन हम कोनों को खोजने के बारे में होशियार हो सकते हैं। इससे यह देखना आसान हो जाता है कि एम और एन बहुत अलग होने पर आप बाहर के क्षेत्रों को कैसे छोड़ सकते हैं।

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

और एक जनरेटर आधारित समाधान जो O (अधिकतम (n, m) ^ 2) से बेहतर है, यह O (nm + abs (nm) ^ 2) है क्योंकि यह संपूर्ण स्ट्रिप्स को छोड़ देता है यदि वे समाधान का हिस्सा नहीं हैं।

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

यह मेरा बहुत बुरा समाधान है, जो जावा के नंगे न्यूनतम ज्ञान से बना है। यहां मुझे एक सर्पिल में एक क्षेत्र पर इकाइयां डालनी हैं। इकाइयों को अन्य इकाइयों के ऊपर या पहाड़ों पर या समुद्र में नहीं रखा जा सकता है।

स्पष्ट होना। यह एक अच्छा उपाय नहीं है। यह अन्य लोगों के मज़े के लिए जोड़ा जाने वाला एक बहुत ही बुरा समाधान है कि यह कितना बुरा हो सकता है

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

Cudos किसी को भी, जो वास्तव में यह पढ़ सकते हैं

बोनस प्रश्न: इस "एल्गोरिथ्म" का रनिंग टाइम क्या है? : पी


1
+1 के कारण " यह अन्य लोगों के मज़े के लिए जोड़ा जाने वाला एक बहुत बुरा समाधान है कि यह कितना बुरा हो सकता है "।
ओरिऑल

0

AutoIt के लिए समाधान

#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

मेरे पास हाल ही में एक ऐसी ही चुनौती थी, जहाँ मुझे परिणामों को छाँटने और छापने के लिए 2 डी सरणी बनाना और सर्पिल मैट्रिक्स एल्गोरिथ्म का उपयोग करना था। यह C # कोड N, N 2D सरणी के साथ काम करेगा। यह स्पष्टता के लिए क्रिया है और संभवत: आपकी आवश्यकताओं को पूरा करने के लिए इसे फिर से सच किया जा सकता है।

//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

मैंने इसे एक मित्र के साथ बनाया था जो कि जावास्क्रिप्ट पहलू अनुपात को जावास्क्रिप्ट पर समायोजित करता है। सबसे अच्छा समाधान मुझे पिक्सेल द्वारा छवि विकास पिक्सेल के लिए मिला, पूरी छवि को भरना।

आशा है कि यह कुछ मदद करता है।

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/ पर काम करते हुए देख सकते हैं । बस जावास्क्रिप्ट की चौड़ाई और ऊंचाई को जावास्क्रिप्ट संस्करण पर और एचटीएमएल पर विशेषताओं पर बदलना सुनिश्चित करें।


0

बस जावास्क्रिप्ट में मनोरंजन के लिए:

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

सी # संस्करण, गैर-वर्ग आकार भी संभालता है।

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

मैं इस कोड को साझा कर रहा हूं जिसे मैंने एक अलग उद्देश्य के लिए डिज़ाइन किया है; यह कॉलम संख्या "X", और सरणी तत्व @ सर्पिल सूचकांक "सूचकांक" की पंक्ति संख्या "Y" को खोजने के बारे में है। यह फ़ंक्शन मैट्रिक्स की चौड़ाई "डब्ल्यू" और ऊंचाई "एच", और आवश्यक "इंडेक्स" लेता है। बेशक, इस फ़ंक्शन का उपयोग उसी आवश्यक आउटपुट का उत्पादन करने के लिए किया जा सकता है। मुझे लगता है कि यह सबसे तेज़ संभव तरीका है (क्योंकि यह उन्हें स्कैन करने के बजाय कोशिकाओं पर कूदता है)।

    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

पायन लूपिंग क्लॉक वाइज सर्पिल कोड कैन कैन गर्डर उत्तर का उपयोग कर

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
यह दक्षिणावर्त है और मैंने कैन बर्क गडर का हवाला दिया। मूल प्रश्न काउंटर क्लॉकवाइज clock के लिए है। मुझे एक दक्षिणावर्त फ़ंक्शन की आवश्यकता थी इसलिए मुझे लगा कि इसे वहां छोड़ना उपयोगी होगा।
एड्रिनामेलिक

0

VB.Net में डेविडोंट का उत्कृष्ट समाधान

    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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.