حلقات في دوامة
سؤال
كان صديقا بحاجة إلى خوارزمية من شأنها السماح له بحلقة من خلال عناصر مصفوفة NXM (N و M غرابة). لقد توصلت إلى حل، لكنني أردت أن أرى ما إذا كان زملائي قد يأتيون إلى حل أفضل.
أنا نشر الحل الخاص بي كإجابة على هذا السؤال.
مثال الإخراج:
للحصول على مصفوفة 3x3، يجب أن يكون الإخراج:
(0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1)
علاوة على ذلك، يجب أن تدعم الخوارزمية المصفوفات غير المربعة، لذلك على سبيل المثال لمصفوفة 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)
المحلول
إليك حلاي (في بيثون):
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
نصائح أخرى
C ++ أي شخص؟ ترجمة سريعة من Python، نشرت للوصول
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;
}
}
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 مربع، انعطف يسارا، والمضي قدما مربع واحد، ثم انعطف يسارا. الخطوة الاستقرائية: نقل المربعات N + 1 إلى الأمام، انعطف يسارا، مواكبة المربعات N + 1، انعطف يسارا.
تشير الأناقة الرياضية للتعبير عن هذه المشكلة بشدة أنه يجب أن تكون هناك خوارزمية بسيطة لحساب الحل. عند مراعاة التجريد في الاعتبار، اخترت عدم تطبيق الخوارزمية بلغة برمجة محددة ولكنها كود زائف.
أولا، سأفكر في خوارزمية لحساب 2 تكرار فقط من دوامة باستخدام 4 أزواج من الحلقات. هيكل كل زوج متشابه، لكن متميزا بحقه. قد يبدو هذا مجنونا في البداية (بعض الحلقات تنفذ مرة واحدة فقط مرة واحدة) ولكن الخطوة بخطوة، سأجري التحولات حتى وصلنا إلى 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
التحول الأول الذي سنصنعه هو إدخال متغير جديد 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 هي أعداد صحيحة حتى نتمكن من طرح أي قيمة حقيقية بين 0 و 1 من RHS دون التأثير على نتيجة عدم المساواة. نختار طرح 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.
هذا يؤدي إلى الحل الموضح في بداية هذه الإجابة.
أنا أحب مولدات بيثون.
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)
إليك حل O (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;
}
محاولة جافا دوامة "رمز الغولف"، بناء على البديل C ++.
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;
}
}
إليك حل C ++ يدل على أنه يمكنك حساب إحداثيات Next (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);
}
}
إذا كان كل ما تحاول القيام به هو إنشاء نقاط N الأولى في دوامة (دون عائق المشكلة الأصلية للإخفاء إلى منطقة N X M)، يصبح التعليمات البرمجية بسيطة للغاية:
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 لتحديد أي جانب من المربع الذي تقوم به، ويخبرك ما الاتجاه الذي يجب أن تتحرك فيه.
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;
}
}
هنا حلاي (في روبي)
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}),"
}
Haskell، خذ اختيار الخاص بك:
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] ]
لدي مكتبة مفتوحة المصدر، pixelscan., ، هذه هي مكتبة بيثون توفر وظائف لمسح البكسل على شبكة في مجموعة متنوعة من الأنماط المكانية. الأنماط المكانية المضمنة هي دائري، حلقات، شبكات، ثعابين، ومشي عشوائي. هناك أيضا تحويلات مختلفة (على سبيل المثال، مقطع، مبادلة، تدوير، ترجمة). يمكن حل مشكلة OP الأصلية على النحو التالي
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)
يمكن بالسلاسل مولدات المكتبات والتحولات لتغيير النقاط في مجموعة واسعة من الطلبات وأنماط مكانية.
هذا في C.
لقد حدثت اختيار أسماء متغيرة سيئة. في أسماء T == TOP، L == اليسار، ب == أسفل، ص == الصحيح. لذلك، TLI هو الجزء العلوي الأيسر أنا و 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]);
}
}
هنا 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);
هذه نسخة مختلفة قليلا - في محاولة للاستخدام 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
إليك حل تكريري جافا سكريبت (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. يتم تطبيق التنفيذ دائما الحركة في الترتيب التالي - أعلى، اليمين، أسفل، غادر.
من فضلك، لاحظ أن هذا التنفيذ يخلق مصفوفات مربعة.
إليك إجابة في جوليا: نهجي هو تعيين النقاط في المربعات المركزية ("اللوالب") حول الأصل (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 = 3
في المعادلة للعثور على N يعطي 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}
, ، ولكن هنا أغيرها إلى tuples-(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)
إليك حلا في Python 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 بواسطة: - زيادة j
من 0 إلى 4 (5 مرات) - زيادة i
من 1 إلى 4 (4 مرات) - تناقص j
من 3 إلى 0 (4 مرات) - تناقص i
من 3 إلى 1 (3 مرات)
بالنسبة إلى المربعات التالية (3 × 3 و 1 × 1) نحن نفعل الشيء نفسه ولكنه تحول المؤشرات الأولية والنهائية بشكل مناسب. لقد استخدمت فهرس 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)
هذا يعتمد على الحل الخاص بك، ولكن يمكننا أن نكون أكثر ذكاء حول العثور على الزوايا. هذا يجعل من الأسهل معرفة كيفية تخطي المناطق في الخارج إذا كانت M و N مختلفة تماما.
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
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;
}
هذا هو الحل السيئ للغاية، مصنوع من معرفة الحد الأدنى من جافا. هنا يجب أن أضع وحدات في حقل في دوامة. لا يمكن وضع الوحدات أعلى وحدات أخرى أو على الجبال أو في المحيط.
أن تكون واضحة. هذا ليس حلا جيدا. هذا هو الحل السيء للغاية يضاف للمتعة من الآخرين أن تضحك على مدى سوء ذلك
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 لأي شخص يمكنه بالفعل قراءة هذا
سؤال المكافأة: ما هو وقت تشغيل هذه "الخوارزمية"؟ : P.
حل ل 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
أجريت مؤخرا تحديا مماثلا حيث اضطررت إلى إنشاء صفيف ثنائية الأبعاد واستخدام خوارزمية مصفوفة دوامة لفرز النتائج وطباعةها. سيعمل رمز 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;
}
// تنفيذ 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>';
}
أنا جعلت هذا واحد مع صديق يضبط دوامة إلى نسبة الجانب قماش على جافا سكريبت. أفضل حل حصلت على Pixly Evolution Pixel بواسطة Pixel، ملء الصورة بأكملها.
آمل أن يساعد بعض واحد.
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/ وبعد فقط تأكد من تغيير عرض وارتفاع قماش على JavaScript Vars وعلى السمات الموجودة على HTML.
فقط للمتعة في جافا سكريبت:
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);
نسخة C #، تعامل مع الأحجام غير المربعة كذلك.
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;
}
أنا أتقاسم هذا القانون الذي صممته لغرض مختلف؛ يتعلق الأمر بإيجاد رقم العمود "X"، ورقم الصف "Y" من عنصر الصفيف @ فهرس دوامة "فهرس". تأخذ هذه الوظيفة العرض "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 };
}
بيثون حلقات في اتجاه عقارب الساعة رمز حلزوني باستخدام يمكن إجابة بيرك güder.
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
حل دافيدونت ممتاز في 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
هذا هو نهج دوامة مربعة في ج #، لقد قمت بذلك منذ بعض الوقت، لقد اعتقدت أنني أستطيع إضافته، لأنه مختلف عن جميع الآخرين، وليس الأفضل، ولكن مجرد طريقة مختلفة، أنا متأكد من أنه يمكن أن يكون تكييفها لعدد غير مربع أيضا.
هذا النهج الذي اتخذه الحد الأقصى لعدد الخطوات في، بدلا من ماكس ناقلات ثو.
الشيء الرئيسي في هذا النهج هو الزوايا، هناك بعض التعديلات للخطوة الأولى وخطوة "التقدم" اللازمة للخروج من "الزاوية" في الزاوية السفلية اليمنى.
private void Spiral(int sequence)
{
const int x = 0;
const int y = 1;
int[,] matrix = new int[2, sequence];
int dirX, dirY, prevX, prevY, curr;
dirX = dirY = prevX = prevY = curr = default(int);
do
{
if (curr > 0)
{
prevX = matrix[x, curr - 1];
prevY = matrix[y, curr - 1];
}
//Change direction based on the corner.
if (Math.Abs(prevX) == Math.Abs(prevY) && curr > 0)
{
dirX = dirY = 0;
if (prevY > 0 && prevX > 0)
dirX = -1;
else if (prevY > 0 && prevX < 0)
dirY = -1;
else if (prevY < 0 && prevX < 0)
dirX = 1;
else if (prevY < 0 && prevX > 0) //Move forward
dirX = 1;
else if (prevY == 0 && prevX == 0) //For the first step.
dirX = 1;
}
else if (prevY < 0 && prevX > 0 && (Math.Abs(matrix[x, curr - 2]) == Math.Abs(matrix[y, curr - 2]))) //Move forward
{
dirX = 0;
dirY = 1;
}
else if (prevX == 1 && prevY == 0) //For the second step.
{
dirY = 1;
dirX = 0;
}
matrix[x, curr] = prevX + dirX;
matrix[y, curr] = prevY + dirY;
System.Console.Write($"({matrix[x, curr]},{matrix[y, curr]}) ");
} while (++curr < sequence);
}