سؤال

أحاول التوصل إلى وظيفة تكرارية تنشئ إحداثيات XYZ لشبكة سداسية. مع وضع سداسي يبدأ (قل 0،0،0 للبساطة)، أريد حساب الإحداثيات لكل "حلقة" متتالية من السداسي، كما هو موضح هنا:

حتى الآن، كل ما تمكنت من التوصل إليه هو (مثال على جافا سكريبت):

var radius = 3
var xyz = [0,0,0];

// for each ring
for (var i = 0; i < radius; i++) {
    var tpRing = i*6;
    var tpVect = tpRing/3;
    // for each vector of ring
    for (var j = 0; j < 3; j++) {
        // for each tile in vector
        for(var k = 0; k < tpVect; k++) {
            xyz[0] = ???;
            xyz[1] = ???;
            xyz[2] = ???;
            console.log(xyz);
        }
    }
}

أعلم أن كل حلقة تحتوي على ست نقاط إضافية أكثر من سابق ناقلات 120 درجة يحتوي على نقطة إضافية واحدة لكل خطوة من المركز. أنا أعرف أيضا ذلك x + y + z = 0 لجميع البلاط. ولكن كيف يمكنني توليد قائمة الإحداثيات التي اتبع التسلسل أدناه؟

    0, 0, 0

    0,-1, 1
    1,-1, 0
    1, 0,-1
    0, 1,-1
   -1, 1, 0
   -1, 0, 1

    0,-2, 2
    1,-2, 1
    2,-2, 0
    2,-1,-1
    2, 0,-2
    1, 1,-2
    0, 2,-2
   -1, 2,-1
   -2, 2, 0
   -2, 1, 1
   -2, 0, 2
   -1,-1, 2
هل كانت مفيدة؟

المحلول

حل آخر ممكن، الذي يعمل في س (دائرة نصف قطرها2), على عكس. س (دائرة نصف قطرها4) من حل تيميك (على حساب الكثير من الأسلوب) هل هذا:

radius = 4
for r in range(radius):
    print "radius %d" % r
    x = 0
    y = -r
    z = +r
    print x,y,z
    for i in range(r):
        x = x+1
        z = z-1
        print x,y,z
    for i in range(r):
        y = y+1
        z = z-1
        print x,y,z
    for i in range(r):
        x = x-1
        y = y+1
        print x,y,z
    for i in range(r):
        x = x-1
        z = z+1
        print x,y,z
    for i in range(r):
        y = y-1
        z = z+1
        print x,y,z
    for i in range(r-1):
        x = x+1
        y = y-1
        print x,y,z

أو مكتوبة بقليل قليلا:

radius = 4
deltas = [[1,0,-1],[0,1,-1],[-1,1,0],[-1,0,1],[0,-1,1],[1,-1,0]]
for r in range(radius):
    print "radius %d" % r
    x = 0
    y = -r
    z = +r
    print x,y,z
    for j in range(6):
        if j==5:
            num_of_hexas_in_edge = r-1
        else:
            num_of_hexas_in_edge = r
        for i in range(num_of_hexas_in_edge):
            x = x+deltas[j][0]
            y = y+deltas[j][1]
            z = z+deltas[j][2]            
            print x,y,z

إنها مستوحاة من حقيقة أن السداسي هي في الواقع في الخارج من مسدس أنفسهم، حتى تتمكن من العثور على إحداثيات 1 من نقاطها، ثم احسب الآخرين عن طريق التحرك على حوافها الستة.

نصائح أخرى

ليس فقط x + y + z = 0, ، ولكن القيم المطلقة ل X، Y و Z تساوي ضعف نصف قطر الحلبة. يجب أن يكون هذا كافيا لتحديد كل مسدس في كل حلقة متتالية:

var radius = 4;
for(var i = 0; i < radius; i++)
{
    for(var j = -i; j <= i; j++)
    for(var k = -i; k <= i; k++)
    for(var l = -i; l <= i; l++)
        if(Math.abs(j) + Math.abs(k) + Math.abs(l) == i*2 && j + k + l == 0)
            console.log(j + "," + k + "," + l);
    console.log("");
}

كان هذا لغز ممتع.

س (دائرة نصف قطرها2) ولكن مع (نأمل) أسلوب أكثر قليلا من حل أوفري. حدث لي أن الإحداثيات يمكن أن يتم إنشاؤها كما لو كنت "تمشي" حول الحلبة باستخدام متجه الاتجاه (الحركة)، وأن الدور الذي كان يعادل تحويل الصفر حول ناقلات النقل.

هذا الإصدار لديه أيضا ميزة أكثر حل إريك لأنه لا يلمس أبدا إحداثيات غير صالحة (يرفضها إريك، ولكن هذا لا يتعين عليه أن يختبرها أبدا).

# enumerate coords in rings 1..n-1; this doesn't work for the origin
for ring in range(1,4):
    # start in the upper right corner ...
    (x,y,z) = (0,-ring,ring)
    # ... moving clockwise (south-east, or +x,-z)
    move = [1,0,-1]         

    # each ring has six more coordinates than the last
    for i in range(6*ring):
        # print first to get the starting hex for this ring
        print "%d/%d: (%d,%d,%d) " % (ring,i,x,y,z)
        # then move to the next hex
        (x,y,z) = map(sum, zip((x,y,z), move))

        # when a coordinate has a zero in it, we're in a corner of
        # the ring, so we need to turn right
        if 0 in (x,y,z):
            # left shift the zero through the move vector for a
            # right turn
            i = move.index(0)
            (move[i-1],move[i]) = (move[i],move[i-1])

    print # blank line between rings

ثلاثة هتافات لتزلق تسلسل بيثون.

حسنا، بعد تجربة كل من الخيارات التي قمت باستقرتها على حل Ofri حيث إنها أسرع قليلا وتسهل تقديم قيمة إزاحة أولية. يبدو رمزي الآن مثل هذا:

var xyz = [-2,2,0];
var radius = 16;
var deltas = [[1,0,-1],[0,1,-1],[-1,1,0],[-1,0,1],[0,-1,1],[1,-1,0]];
for(var i = 0; i < radius; i++) {
        var x = xyz[0];
        var y = xyz[1]-i;
        var z = xyz[2]+i;
        for(var j = 0; j < 6; j++) {
                for(var k = 0; k < i; k++) {
                        x = x+deltas[j][0]
                        y = y+deltas[j][1]
                        z = z+deltas[j][2]
                        placeTile([x,y,z]);
                }
        }
}

تستخدم الطريقة "placetile" clonenode لنسخ عنصر SVG محدد مسبقا ويستغرق حوالي 0.5ms لكل بلاط لتنفيذ أي أكثر من جيدة بما فيه الكفاية. شكرا جزيلا على Tehmick و Ofri لمساعدتكم!

ج إس

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top