একটি সর্পিল লুপিং


154

একটি বন্ধু একটি অ্যালগরিদমের প্রয়োজন ছিল যা তাকে এনএক্সএম ম্যাট্রিক্সের উপাদানগুলি (এন এবং এম বিজোড়) দ্বারা লুপ করতে দেয়। আমি একটি সমাধান নিয়ে এসেছি, তবে আমি দেখতে চেয়েছিলাম যে আমার সহকর্মীরা আরও ভাল সমাধান নিয়ে আসতে পারে কিনা।

আমি এই প্রশ্নের উত্তর হিসাবে আমার সমাধান পোস্ট করছি।

উদাহরণ আউটপুট:

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 ম্যাট্রিক্স


নন-স্কয়ার ম্যাট্রিক্সের জন্য আপনি কী চান তা ব্যাখ্যা করতে পারেন? আপনার সমাধানের (২,১) থেকে (-২,১) একটি "লাফ" রয়েছে - এটি কি উদ্দেশ্য? [উদাহরণস্বরূপ, 7x3 ম্যাট্রিক্সের জন্য, এটি আরও দুটি "লাফান", এবং একটি (2 কে + 1) এক্স 3 ম্যাট্রিক্সের জন্য এটিতে 2 কে -3 লাফ দিতে হবে?]
শ্রীভাতসার

3
হ্যাঁ, জাম্পগুলি ইচ্ছাকৃত are আমি 5x3 ম্যাট্রিক্স চিত্র দিয়ে প্রশ্নটি আপডেট করেছি। ছবিটি থেকে আপনি দেখতে পাচ্ছেন, আমরা উপরের এবং নীচের সারিগুলি এড়িয়ে চলেছি।
বার্ক গ্যাডার

ঠিক আছে, তাহলে আপনার নিজের কোডটি সবচেয়ে পরিষ্কার মনে হচ্ছে। এবং যদিও এটি অফটোপিক: আপনি কীভাবে এই চিত্রগুলি তৈরি করেছেন? :)
শ্রীভাত্সারআর

=)) আমি এগুলি তৈরি করি নি। আসলে আমি যেভাবে তাদের তৈরি করেছি তা বেশ বোকা। আমি OO.org ক্যাল্কে টেবিলগুলি তৈরি করেছি, একটি স্ক্রিনশট নিয়েছি এবং জিআইএমপিতে স্ক্রিনশটটি সম্পাদনা করেছি। =))
বার্ক গেডার

1
@ ইয়িং: আমার বন্ধুটির কেন প্রয়োজন তা আমি সত্যিই জানি না, তবে তিনি বলেছিলেন যে তিনি অনুসন্ধানের অ্যালগরিদমে ম্যাট্রিক্সের সদস্যদের কাছাকাছি যেতে চান favor
বার্ক গ্যাডার

উত্তর:


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
আমি এটি যতদূর দেখতে পাচ্ছি এটি এটি লেখার সেরা উপায়। একমাত্র সম্ভাব্য উন্নতি হ'ল ও (ম্যাক্স (এম, এন) instead 2) এর পরিবর্তে ও (এমএন) তৈরি করা হবে যেগুলি মুদ্রণযোগ্য নয় (এক্স, ওয়াই) যা সরাসরি প্রিন্ট হচ্ছে না অতীতকে বাদ দিয়ে, তবে কোডটি তৈরি করবে কিছুটা কুরুচিপূর্ণ
শ্রীভাত্সারআর

আমি আমার সমাধানটি অপ্টিমাইজ করছি এবং আপনি ইতিমধ্যে যা পেয়েছেন তা বেশ কাছাকাছি। এটি আমার মনে হয় একটি দুর্দান্ত সমাধান। শ্রীভাতসার এর পরামর্শ ছাড়াও, এবং প্রতিটি পুনরাবৃত্তি x / 2 এবং y / 2 গণনা করার মতো স্টাফ ছাড়াও শৈলী ব্যতীত এর উন্নতি করার খুব বেশি কিছু নেই।
ট্রিপটিচ

মতলব জন্য কোন সমাধান ?!
স্যাম

এটি কি চিত্র বাফার ডেটা অ্যাক্সেস করার জন্য ভাল ক্যাশে সংহতি দেয়? (এখানে অনেক উত্তর রয়েছে তবে উচ্চ পারফরম্যান্স ইমেজ ক্রিয়াকলাপগুলির জন্য কোনটি সবচেয়ে ভাল কাজ করে সে সম্পর্কিত খুব বেশি তথ্য নেই)
ধারণাগুলি 42

@ ধারণাগুলি 42 - এটি কার্যকর হয় না, কারণ ফলাফল সর্বদা স্থানাঙ্কগুলির একই সর্পিল প্যাটার্ন। সর্পিল প্যাটার্নটি ক্যাশে সুসংগত কিনা তা আমি অনুমান করি যে চিত্র বাফার বাস্তবায়নের উপর নির্ভরশীল। (আমার অনুমান যে এটি চিত্রের চলার অন্যান্য পদ্ধতির চেয়ে ক্যাশে ছুঁড়ে ফেলা হবে, যাতে ক্রমে ক্রমান্বয়ে লাইনে যেতে হবে)। কিন্তু এই সমন্বয়গুলির উত্পাদন করতে অ্যালগরিদমের পছন্দ সম্ভবত ক্যাশে প্রভাব ফেলবে না।
র‌্যাপুরমাট

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 বর্গটি এগিয়ে যান, বাম দিকে ঘুরুন। প্ররোচিত পদক্ষেপ: n + 1 স্কোয়ারের সামনে এগিয়ে যান, বাম দিকে ঘুরুন, n + 1 স্কোয়ারের দিকে এগিয়ে যান, বাম দিকে ঘুরুন।

এই সমস্যাটি প্রকাশের গাণিতিক কমনীয়তা দৃts়ভাবে পরামর্শ দেয় যে সমাধানটি গণনা করার জন্য একটি সাধারণ অ্যালগরিদম থাকা উচিত। বিমূর্ততা মাথায় রেখে, আমি একটি নির্দিষ্ট প্রোগ্রামিং ভাষায় অ্যালগরিদমটি প্রয়োগ না করে সিউডো কোড হিসাবে বেছে নিয়েছি।

প্রথমে আমি 4 জোড়া জোড় লুপ ব্যবহার করে সর্পিলটির মাত্র 2 পুনরাবৃত্তি গণনা করতে একটি অ্যালগরিদম বিবেচনা করব। প্রতিটি জোড়ের কাঠামোটি একই রকম, তবুও তার নিজস্বভাবে পৃথক। এটি প্রথমে ক্রেজি মনে হতে পারে (কিছু লুপগুলি কেবল একবার সম্পাদিত হয়ে যায়) তবে ধাপে ধাপে আমি রূপান্তরগুলি করব যতক্ষণ না আমরা 4 জোড়া লুপগুলি অভিন্ন এবং এটি অন্য লুপের ভিতরে রাখা একক জোড়া দিয়ে প্রতিস্থাপন করা যেতে পারে। এটি আমাদের কোনও শর্ত ছাড়াই গণনা n পুনরাবৃত্তিগুলির একটি সাধারণ সমাধান সরবরাহ করবে।

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

প্রথম রূপান্তরটি আমরা করব, দিকনির্দেশের জন্য একটি নতুন ভেরিয়েবল ডি এর পরিচিতি, যা মান +1 বা -1 রাখে। প্রতিটি জোড়া লুপের পরে দিকটি স্যুইচ করে। যেহেতু আমরা সমস্ত পয়েন্টে ডি এর মান জানি, তাই আমরা প্রতিটি বৈষম্যের প্রতিটি দিককে এর দ্বারা গুণিত করতে পারি, সেই অনুযায়ী অসমতার দিকটি সামঞ্জস্য করতে পারি এবং ডি এর কোনও গুণকে অন্য ধ্রুবকের সাথে ধ্রুবক করে তুলতে পারি। এটি আমাদের নীচের সাথে ছেড়ে দেয়।

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

এখন আমরা লক্ষ করি যে এক্স * ডি এবং আরএইচএস উভয়ই পূর্ণসংখ্যা তাই আমরা অসমতার ফলাফলকে প্রভাবিত না করে আরএইচএস থেকে 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

অবশেষে, আমরা দেখতে পাচ্ছি যে প্রতিটি লুপের সময় লুপের কাঠামোটি অভিন্ন এবং অন্য লুপের ভিতরে রাখা একক লুপে হ্রাস করা যায়। এছাড়াও, আসল মূল্যবান সংখ্যার ব্যবহার এড়াতে আমি এম এর প্রাথমিক মানটি বহুগুণ করেছি; মান মি দ্বারা বৃদ্ধি করা হয়; এবং প্রতিটি অসমতা উভয় পক্ষের দ্বারা 2 দ্বারা।

এটি এই উত্তরের শুরুতে দেখানো সমাধানের দিকে নিয়ে যায়।


1
কোন পরিস্থিতিতে আপনার চূড়ান্ত সমাধানটি শেষ হবে?
মের্লিন মরগান-গ্রাহাম

1
এই ধরণের প্যাটার্ন প্রিন্টিংয়ের প্রয়োগ কী?
আশিস শুক্লা

1
@ মেরলিনমর্গান-গ্রাহাম কম্পিউটারের স্মৃতি বা শক্তি শেষ হয়ে গেলে এটি শেষ হয়।
মাইক

দেখে মনে হয় যে সমাধানটির কমনীয়তা সময় এবং স্মৃতিচারণের প্রতিবন্ধকতাগুলি উপেক্ষা করেই ডেকে আনে। আমি মার্জিতভাবে একটি সমাপ্তির শর্ত যুক্ত করার পরামর্শ দিচ্ছি (যদি সম্ভব হয়)। আমি এটিকে উত্তরের শীর্ষে স্থানান্তরিত করার এবং তার নীচে ডেরাইভেশনটি দেখানোর পরামর্শ দিচ্ছি।
মের্লিন মরগান-গ্রাহাম

1
যদিও মূল প্রশ্নটি একটি এনএক্সএম ম্যাট্রিক্স সম্পর্কে ছিল, এটি আসলে একটি খুব কার্যকর উত্তর যদি আপনার কিছু না পাওয়া পর্যন্ত (যেমন বিরতি বা ফিরে) অবিরতভাবে সর্পিল-বাহ্যিক প্রয়োজন হয় need অবশ্যই, অন্যান্য মন্তব্য হিসাবে উল্লিখিত, আপনার সেই সমাপ্তির শর্তটি নির্ধারণ করা দরকার বা এটি চিরকাল চলবে।
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
মারিস বি।

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

এখানে একটি সি ++ সমাধান রয়েছে যা দেখায় যে আপনি পূর্বেরগুলি থেকে পরবর্তী (x, y) স্থানাঙ্কগুলি সরাসরি এবং সহজেই গণনা করতে পারবেন - বর্তমান দিকনির্দেশ, ব্যাসার্ধ বা অন্য কিছু ট্র্যাক করার প্রয়োজন নেই:

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

টিডিডি, জাভাতে।

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

@ লেপ্পি: সম্ভবত না - অবশ্যই যথেষ্ট সংক্ষিপ্ত নয় - তবে আমি মনে করি এটি টিডিডির একটি ভাল প্রদর্শন, এবং যুক্তিযুক্তভাবে পরিষ্কার, সহজে বোঝার, সঠিক কোড। আমি এর মধ্যে ছেড়ে দেব।
কার্ল Manaster

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
দিক = দিকনির্দেশের পরিবর্তে * = - 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
দয়া করে এটিকে বাজে বা ট্রোলের মন্তব্য হিসাবে গ্রহণ করবেন না, তবে hasশ্বর শীঘ্রই কুৎসিত!
পেট্রুজা

1
আমি উপরের মন্তব্যের সাথে আরও একমত হতে পারি না।
স্নিগ্ধতা

এই হাসেলটি আমার কাছে খুব ট্রেন্ডি দেখাচ্ছে।

1
হ্যাঁ, তবে লক্ষ্য করুন যে এটি কতটা ভাবপূর্ণ। এখানে পোস্ট করা অন্যান্য কয়েকটি উদাহরণের সাথে এর দৈর্ঘ্যের তুলনা করুন।
রবার্ট হার্ভে

@ পেত্রুজা আসলে, এটি হাস্কেলের সেরা সমাধান নয়। এখানে একবার দেখুন: rosettacode.org/wiki/Spiral_matrix# হাস্কেল
polkovnikov.ph

2

এটি সি।

আমি খারাপ ভেরিয়েবলের নামগুলি বেছে নিতে পেরেছি। নামগুলিতে টি == শীর্ষ, এল == বাম, বি == নীচে, আর == ডানদিকে। সুতরাং, tli উপরের বাম i এবং brj নীচে ডান জে আছে।

#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 বার) থেকে বৃদ্ধি - বৃদ্ধিi থেকে 1 থেকে 4 (4 বার) থেকে - j3 থেকে 0 (4 বার) থেকে হ্রাস - হ্রাস i3 থেকে 1 (3 বার) পর্যন্ত

পরবর্তী স্কোয়ারগুলির জন্য (3x3 এবং 1x1) আমরা একই কাজ করি তবে প্রাথমিক এবং চূড়ান্ত সূচকগুলি যথাযথভাবে স্থানান্তর করি। আমি একটি সূচক ব্যবহার করেছিk প্রতিটি কেন্দ্রীভূত বর্গক্ষেত্রের জন্য , সেখানে এন // 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

এখানে সি #, লিনাকিশ।

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এবং iteratorsLUA এ। প্রতিটি পদক্ষেপে প্রোগ্রামটি ম্যাট্রিক্স এবং লুপগুলির আরও ভিতরে নেমে আসে। আমি সর্পিল 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

// পিএইচপি বাস্তবায়ন

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

এটি বাহ্যিক সর্পিল তৈরি করবে, স্থানাঙ্কগুলি (x = 0, y = 0) থেকে শুরু করে 1 পদক্ষেপ এবং মোট আইটেমের সংখ্যা 100 এর সমান The পড়ে থাকবে।

দয়া করে নোট করুন যে এই বাস্তবায়নটি বর্গ ম্যাট্রিক্স তৈরি করে।


1

জুলিয়ার একটি উত্তর এখানে: আমার পদ্ধতির উত্সের চারপাশে কেন্দ্রীভূত স্কোয়ারগুলিতে ('সর্পিলস') পয়েন্টগুলি নির্ধারণ করা (0,0), যেখানে প্রতিটি বর্গক্ষেত্রের দৈর্ঘ্য রয়েছে m = 2n + 1, যাতে স্থান হিসাবে নম্বরগুলির সাথে একটি অর্ডার করা অভিধান তৈরি করতে হবে (উত্সের জন্য 1 থেকে শুরু) এবং মান হিসাবে সংশ্লিষ্ট সমন্বয়।

যেহেতু সর্পিল প্রতি সর্বাধিক অবস্থানটি রয়েছে (n,-n), তাই বাকি পয়েন্টগুলি কেবল এই বিন্দু থেকে পিছনে কাজ করে, অর্থাৎ ডানদিকে নীচের কোণ থেকে m-1একক দ্বারা কাজ করে, তারপরে লম্ব p বিভাগের 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 = 3এন প্রদানের সমীকরণে প্লাগ ইন করা 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}but তবে এখানে আমি (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

এবং একটি জেনারেটর ভিত্তিক সমাধান যা ও (সর্বোচ্চ (এন, এম) ^ 2) এর চেয়ে ভাল, এটি ও (এনএম + অ্যাবস (এনএম) ^ 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);
}

চুডোস যে কেউ আসলে এটি পড়তে পারে

বোনাস প্রশ্ন: এই "অ্যালগরিদম" চলমান সময় কি? : P: P


1
+1 এর কারণে " এটি করা খুব খারাপ সমাধান হ'ল অন্য লোকের মজাদার জন্য এটি কীভাবে খারাপ হতে পারে " laugh
ওরিওল

0

অটোআইটির জন্য সমাধান

#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

আমার সম্প্রতি একটি অনুরূপ চ্যালেঞ্জ ছিল যেখানে আমাকে 2D অ্যারে তৈরি করতে হয়েছিল এবং ফলাফলগুলি বাছাই করতে এবং মুদ্রণের জন্য একটি সর্পিল ম্যাট্রিক্স অ্যালগরিদম ব্যবহার করতে হয়েছিল। এই সি # কোডটি একটি এন, এন 2 ডি অ্যারের সাথে কাজ করবে। এটি স্পষ্টতার জন্য ভার্জোজ এবং আপনার প্রয়োজনের সাথে খাপ খায় এমনটি পুনরায় ফ্যাক্টর করা যেতে পারে।

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

আমি এই কোডটি ভাগ করছি যা আমি অন্য উদ্দেশ্যে ডিজাইন করেছি; এটি কলাম নম্বর "এক্স" এবং অ্যারের উপাদান @ সর্পিল সূচক "সূচক" এর সারি নম্বর "ওয়াই" সন্ধান করার বিষয়ে। এই ফাংশনটি ম্যাট্রিক্সের প্রস্থ "w" এবং উচ্চতা "h" এবং প্রয়োজনীয় "সূচক" নেয়। অবশ্যই, এই ফাংশনটি একই প্রয়োজনীয় আউটপুট উত্পাদন করতে ব্যবহৃত হতে পারে। আমি মনে করি এটি দ্রুততম পদ্ধতি (এটি স্ক্যানের পরিবর্তে কোষগুলির উপরে ঝাঁপিয়ে পড়ে)।

    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
এটি ঘড়ির কাঁটার দিকে 🔃 এবং আমি ক্যান বার্ক গেডারকে উদ্ধৃত করেছিলাম। আসল প্রশ্নটি ঘড়ির কাঁটার বিপরীতে 🔄 আমার একটি ঘড়ির কাঁটা ফাংশন প্রয়োজন তাই আমি অনুভব করেছি যে এটি সেখানে রেখে দেওয়া কার্যকর হবে।
অ্যাড্রিনিমেলিক

0

ভিবি.নেটে ডেভিডন্টের দুর্দান্ত সমাধান

    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
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.