स्टार-स्पैंगल्ड कोड चुनौती


21

संयुक्त राज्य अमेरिका के झंडे में शामिल है, इसके कैंटन में, 50 राज्यों का प्रतिनिधित्व करने वाले 50 सितारे।

50-सितारा अमेरिकी ध्वज

अतीत में, जब कम राज्य थे, बेशक कम सितारे थे, और उन्हें अलग तरीके से व्यवस्थित किया गया था। उदाहरण के लिए, 1912-1959 (न्यू मैक्सिको और एरिज़ोना के प्रवेश के बाद लेकिन अलास्का से पहले), 6 × 8 आयताकार व्यवस्था में 48 सितारे थे।

48-सितारा अमेरिकी ध्वज

1867-1877 से (नेब्रास्का के प्रवेश के बाद लेकिन कोलोराडो से पहले) 37-सितारा ध्वज का उपयोग एक असममित सितारा पैटर्न के साथ किया था।

37-सितारा अमेरिकी ध्वज

यदि भविष्य में 51 वाँ राज्य जोड़ा जाता है, तो आर्मी इंस्टीट्यूट ऑफ़ हेराल्ड्री ने पहले ही एक नए झंडे के लिए एक प्रारंभिक डिजाइन विकसित कर लिया है।

51-सितारा अमेरिकी ध्वज

लेकिन तारों की व्यवस्था के लिए कोई सामान्य एल्गोरिदम नहीं है , तो चलो एक बनाते हैं!

चुनौती

एक कार्यक्रम लिखें जो अमेरिकी ध्वज के केंटन (नीला भाग) में जगह देने के लिए सितारों की एक संख्या के लिए, उन तारों को रखने के लिए आउटपुट इष्टतम निर्देशांक जिस पर स्थित है। समन्वय प्रणाली को केंटन के साथ परिभाषित किया गया है [ ध्वज नहीं पूरे के रूप में] 0≤x systemW और 0≤y .H के साथ।

इस चुनौती के उद्देश्य के लिए, एक "इष्टतम" व्यवस्था को एक के रूप में परिभाषित किया गया है, जो कि कैंटन और निकटतम स्टार के केंद्र के बीच के बीच की दूरी (यूक्लिडियन) को कम करता है।

इस मान को अनुमानित करने के लिए एक सीधा (यदि संभवत: सबॉप्टीमल) एल्गोरिदम है:

def mean_distance_to_nearest_star(stars, width, height, point_density=100):
   """
   Approximate the mean distance between a point in the rectangle
   0 < x < width and 0 < y < height, and the nearest point in stars.

   stars -- list of (x, y) points
   width, height -- dimensions of the canton
   """
   total = 0.0
   nx = round(width * point_density)
   ny = round(height * point_density)
   for ix in range(nx):
       x = (ix + 0.5) * width / nx
       for iy in range(ny):
          y = (iy + 0.5) * width / ny
          min_dist = float('inf')
          for sx, sy in stars:
              min_dist = min(min_dist, math.hypot(x - sx, y - sy))
          total += min_dist
   return total / (nx * ny)

आपका प्रोग्राम तीन कमांड-लाइन तर्क लेगा (प्रोग्राम का नाम खुद नहीं गिना जाएगा):

  1. केंटन में डालने के लिए सितारों की संख्या।
  2. केंटन की चौड़ाई। (फ्लोटिंग-पॉइंट मानों को स्वीकार करना चाहिए।)
  3. केंटन की ऊंचाई। (फ्लोटिंग-पॉइंट मानों को स्वीकार करना चाहिए।)

(यदि आपकी पसंदीदा प्रोग्रामिंग भाषा कमांड-लाइन तर्कों का समर्थन नहीं करती है, तो कुछ यथोचित समकक्ष करें, और इसे अपने उत्तर में दस्तावेज दें।)

आउटपुट में अल्पविराम से अलग किए गए X और Y मान शामिल होने चाहिए, जो एक पंक्ति में हैं। (अंकों का क्रम मायने नहीं रखता है।)

उदाहरण के लिए:

~$ flagstar 5 1.4 1.0
0.20,0.20
0.20,0.80
0.70,0.50
1.20,0.20
1.20,0.80

अतिरिक्त नियम और नोट्स

  • मुझे किसी भी समय नियमों में कमियां बंद करने का अधिकार है।
  • उत्तर के लिए समय सीमा शुक्रवार, 4 जुलाई को 24:00 CDT (UTC-05: 00) है। जवाब न मिलने के कारण समय सीमा बढ़ा दी गई है। टीबीए।
  • अपने उत्तर में शामिल करें:
    • आपके प्रोग्राम का कोड
    • यह कैसे काम करता है इसका स्पष्टीकरण
    • कमांड-लाइन तर्कों के साथ इसका आउटपुट 50 1.4 1.0
  • आपका कार्यक्रम उचित समय के भीतर चलना चाहिए: एक विशिष्ट पीसी पर अधिकतम 5 मिनट। मैं इस बारे में अति-सख्त नहीं होऊंगा, लेकिन अगर घंटे लगते हैं तो यह आपके कार्यक्रम को अयोग्य घोषित कर देगा ।
  • आपका कार्यक्रम नियतात्मक होना चाहिए, अर्थात, हमेशा समान तर्कों के लिए समान आउटपुट दें। तो, पर निर्भर नहीं है time()या rand()। जब तक आप अपना खुद का PRNG रोल करते हैं मोंटे कार्लो तरीके ठीक हैं।
  • सितारों के केवल केंद्र बिंदु ही मायने रखते हैं। ओवरलैप या उस जैसी किसी चीज़ से बचने की कोशिश करने के बारे में चिंता न करें।

स्कोरिंग

  • केंटन में एक बिंदु से निकटतम स्टार की औसत दूरी को कम करें। (ऊपर देखो।)
  • आपको 13 और 50 सितारों के बीच, किसी भी ऐतिहासिक अमेरिकी झंडे के आधार पर स्कोर किया जा सकता है। एकल रैंकिंग में स्कोर करने के लिए सटीक एल्गोरिदम को बाद में पोस्ट किया जाएगा।
  • एक टाई के मामले में, विजेता को नेट अपवोट्स की संख्या द्वारा चुना जाएगा।
  • मैं शायद अपना खुद का एक कार्यक्रम पोस्ट करूंगा, लेकिन खुद को चेकमार्क के लिए योग्य होने से बाहर कर दूंगा।

@primo: आप यह कैसे आंकते हैं? मेरे उदाहरण में 0.289 के निकटतम स्टार से दूरी है, जबकि सभी 5 बिंदुओं को केंद्र में रखकर 0.561 का MDNS है।
dan04

आप मेरी पिछली प्रशंसा की अवहेलना कर सकते हैं। मैं कैंटन पर हर बिंदु से निकटतम स्टार तक गलत मतलब रखता हूं , क्योंकि हर स्टार से निकटतम स्टार की दूरी का मतलब है ।
प्रिमो

3
यदि यह आपके अनुमोदन को पूरा करता है, तो उत्तर के आउटपुट की जांच करने के लिए प्रश्न में स्टैक स्निपेट के रूप में jsfiddle.net/nf2mk2gr को शामिल करने के लिए स्वतंत्र महसूस करें । यह N ग्रिड द्वारा N के आधार पर माध्य दूरी को प्रदर्शित करता है, N के उत्तरोत्तर आप जितना लंबा इंतजार करेंगे। (यह इस प्रश्न के लिए विशेष रूप से लिखा गया था।)
ट्राइकोप्लाक्स

जवाबों:


4

जावास्क्रिप्ट - सितारों को सबसे अलग-थलग बिंदु की ओर ले जाएं

(प्रक्रिया के एक एनीमेशन के साथ)

दृष्टिकोण बहुत सरल है:

  • बड़ी संख्या में यादृच्छिक बिंदु चुनें
  • प्रत्येक के लिए निकटतम तारा खोजें
  • वह बिंदु चुनें जिसके लिए निकटतम तारा सबसे दूर है
  • उस बिंदु के पास उस तारे को स्थानांतरित करें

इस प्रक्रिया को बड़ी संख्या में दोहराया जाता है, धीरे-धीरे उस मात्रा को कम करना जिसके द्वारा तारों को स्थानांतरित किया जाता है। यह एक बिंदु से निकटतम स्टार की अधिकतम दूरी को कम करता है, परोक्ष रूप से निकटतम बिंदु को एक बिंदु से निकटतम स्टार तक कम करता है।

प्रश्न के रूप में आवश्यक है, यह xorshift का उपयोग करने के बजाय यादृच्छिक फ़ंक्शन में निर्मित का उपयोग नहीं करता है ।

अधिकांश कोड कवर सेट अप और एनीमेशन - एल्गोरिदम लागू करने वाला भाग फ़ंक्शन है adjustStars

कोड

आप नीचे दिए गए स्टैक स्निपेट में प्रक्रिया को प्रगति पर देख सकते हैं।

stars = [];
timeoutId = 0;

resetRandomNumberGenerator();

function resetRandomNumberGenerator() {
  rng_x = 114; // Numbers for the random number generator.
  rng_y = 342;
  rng_z = 982;
  rng_w = 443;
}

$(document).ready(function() {
  c = document.getElementById('canton');
  ctx = c.getContext('2d');
  resizeCanvas();
});

function stop() {
  clearTimeout(timeoutId);
}

function arrange() {
  clearTimeout(timeoutId);
  resetStars();
  resetRandomNumberGenerator();
  maxStepSize = Math.min(cantonWidth, cantonHeight) / 4;
  adjustStars(maxStepSize, 8000, 10000);
}

function resizeCanvas() {
  cantonWidth = parseFloat($('#width').val());
  cantonHeight = parseFloat($('#height').val());
  starRadius = cantonHeight / 20;
  document.getElementById('canton').width = cantonWidth;
  document.getElementById('canton').height = cantonHeight;
  ctx.fillStyle = 'white';
  resetStars();
}

function resetStars() {
  stop();
  stars = [];
  population = parseInt($('#stars').val(), 10);
  shortSide = Math.floor(Math.sqrt(population));
  longSide = Math.ceil(population / shortSide);
  if (cantonWidth < cantonHeight) {
    horizontalStars = shortSide;
    verticalStars = longSide;
  } else {
    horizontalStars = longSide;
    verticalStars = shortSide;
  }
  horizontalSpacing = cantonWidth / horizontalStars;
  verticalSpacing = cantonHeight / verticalStars;
  for (var i = 0; i < population; i++) {
    x = (0.5 + (i % horizontalStars)) * horizontalSpacing;
    y = (0.5 + Math.floor(i / horizontalStars)) * verticalSpacing;
    stars.push([x, y]);
  }
  drawStars();
  updateOutputText();
}

function adjustStars(stepSize, maxSteps, numberOfPoints) {
  $('#stepsRemaining').text(maxSteps + ' steps remaining');
  points = randomPoints(numberOfPoints);
  mostIsolatedPoint = 0;
  distanceToNearestStar = 0;
  for (var i = 0; i < numberOfPoints; i++) {
    point = points[i];
    x = point[0];
    y = point[1];
    star = stars[nearestStar(x, y)];
    d = distance(x, y, star[0], star[1]);
    if (d > distanceToNearestStar) {
      distanceToNearestStar = d;
      mostIsolatedPoint = i;
    }
  }
  point = points[mostIsolatedPoint];
  x = point[0];
  y = point[1];

  starToMove = nearestStar(x, y);

  star = stars[starToMove];
  separationX = x - star[0];
  separationY = y - star[1];
  if (separationX || separationY) {
    hypotenuse = distance(x, y, star[0], star[1]);
    currentStep = Math.min(stepSize, hypotenuse / 2);
    deltaX = currentStep * separationX / hypotenuse;
    deltaY = currentStep * separationY / hypotenuse;
    star[0] += deltaX;
    star[1] += deltaY;
    if (star[0] < 0) star[0] = 0;
    if (star[0] > cantonWidth) star[0] = cantonWidth;
    if (star[1] < 0) star[1] = 0;
    if (star[1] > cantonHeight) star[1] = cantonHeight;

    drawStars();
    updateOutputText();
  }

  if (maxSteps > 0) {
    timeoutId = setTimeout(adjustStars, 10, stepSize * 0.9992, maxSteps - 1, numberOfPoints);
  }
}

function updateOutputText() {
  starText = '';
  for (var i = 0; i < stars.length; i++) {
    starText += stars[i][0] + ', ' + stars[i][1] + '\n';
  }
  $('#coordinateList').text(starText);
}

function randomPoints(n) {
  pointsToReturn = [];
  for (i = 0; i < n; i++) {
    x = xorshift() * cantonWidth;
    y = xorshift() * cantonHeight;
    pointsToReturn.push([x, y]);
  }
  return pointsToReturn;
}

function xorshift() {
  rng_t = rng_x ^ (rng_x << 11);
  rng_x = rng_y;
  rng_y = rng_z;
  rng_z = rng_w;
  rng_w = rng_w ^ (rng_w >> 19) ^ rng_t ^ (rng_t >> 8);
  result = rng_w / 2147483648
  return result
}

function nearestStar(x, y) {
  var distances = [];
  for (var i = 0; i < stars.length; i++) {
    star = stars[i];
    distances.push(distance(x, y, star[0], star[1]));
  }
  minimum = Infinity;
  for (i = 0; i < distances.length; i++) {
    if (distances[i] < minimum) {
      minimum = distances[i];
      nearest = i;
    }
  }
  return nearest;
}

function distance(x1, y1, x2, y2) {
  var x = x2 - x1;
  var y = y2 - y1;
  return Math.sqrt(x * x + y * y);
}

function drawStars() {
  ctx.clearRect(0, 0, cantonWidth, cantonHeight);
  for (i = 0; i < stars.length; i++) {
    star = stars[i];
    x = star[0];
    y = star[1];
    drawStar(x, y);
  }
}

function drawStar(x, y) {
  ctx.beginPath();
  ctx.moveTo(x, y - starRadius);
  ctx.lineTo(x - 0.588 * starRadius, y + 0.809 * starRadius);
  ctx.lineTo(x + 0.951 * starRadius, y - 0.309 * starRadius);
  ctx.lineTo(x - 0.951 * starRadius, y - 0.309 * starRadius);
  ctx.lineTo(x + 0.588 * starRadius, y + 0.809 * starRadius);
  ctx.fill();
}
canvas {
  margin: 0;
  border: medium solid gray;
  background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<input id='stars' onchange='resetStars()' type='number' value='13' min='13' max='50' maxlength='2' step='1'>stars
<br>
<input id='width' onchange='resizeCanvas()' type='number' value='494' min='1' max='500' maxlength='3' step='any'>width
<br>
<input id='height' onchange='resizeCanvas()' type='number' value='350' min='1' max='500' maxlength='3' step='any'>height
<br>
<button type='button' onclick='resetStars()'>Reset Stars</button>
<button type='button' onclick='arrange()'>Arrange Stars</button>
<button type='button' onclick='stop()'>Stop</button>
<textarea id='stepsRemaining' rows='1' readonly></textarea>
<br>
<canvas id='canton' width='494' height='350'></canvas>
<br>
<textarea id='coordinateList' rows='50' cols='40' readonly></textarea>

50 सितारों के लिए आउटपुट

(चौड़ाई = 1.4, ऊंचाई = 1.0)

औसत दूरी 0.0655106697162357 अनुमानित।

निर्देशांक:

0.028377044205135808, 0.2128159150679491
0.10116766857540277, 0.05156676609341312
0.2903566419069437, 0.07216263690037035
0.49154061258041604, 0.004436102736309105
0.6930026352073071, 0.07060477929576484
1.0988644764108417, 0.022979778480838074
1.1735677936511582, 0.18600858289592742
1.3056806950504931, 0.062239869036660435
0.3967626880807638, 0.24483447327177033
0.27004118129346155, 0.40467589936498805
0.4996665039421278, 0.13023282430440133
0.5148978532656602, 0.6161298793146592
0.5907056537744844, 0.2614323599301046
0.8853042432872087, 0.048123917861564044
0.7753680330575412, 0.22938793622044834
1.365432954694329, 0.2355377720528128
0.1985172068244217, 0.23551298706793927
0.4477558465270544, 0.4170264112485973
0.6084424566752479, 0.7764909501169484
0.6099528761580699, 0.4395002434593519
0.9506038166406011, 0.34903243854585914
1.1898331497634231, 0.5756784243472182
1.0933574395540542, 0.46422120794648786
1.1516574254138159, 0.2930213338333888
0.07646053006349718, 0.40665000611360175
0.0634456093015551, 0.5853189455014883
0.3470036636019768, 0.5938838331082922
0.7591083341283029, 0.4005456925638841
0.9745306853981277, 0.184624209972443
1.3552011948311598, 0.549607060691302
1.3334000268566828, 0.7410204535471169
1.2990417572304487, 0.39571229988825735
0.05853941030364222, 0.7734808757471414
0.19396697551982484, 0.5678753467094985
0.7103231124251072, 0.5955041661956884
0.6168410756137566, 0.948561537739087
0.8967624790188228, 0.5368666961690878
0.9751229155529001, 0.8323724819557795
0.9987127931392165, 0.652902038374714
1.3231032600971289, 0.9164326184290812
0.20785221980162555, 0.7566700629874374
0.3987967842137651, 0.7678025218448816
0.44395949605458546, 0.9137553802571048
0.775611700149756, 0.9029717946067138
0.806442448003616, 0.7328147396477286
0.9481952441521928, 0.9872963855418118
1.1528689317425114, 0.9346775634274639
1.1651295140721658, 0.7591158327925681
0.09316709042512515, 0.934205211493484
0.2769325337580081, 0.9341145493466471

विभिन्न नंबरों के साथ अपने एनीमेशन को चलाने के बाद, ऐसा लगता है कि इसमें सितारों को बॉक्स के किनारों के करीब रखने की प्रवृत्ति है। हालांकि, सही इष्टतम व्यवस्था को नहीं जानते हुए, मैं यह नहीं बता सकता कि यह एक बग है या एक सुविधा।
dan04

@ dan04 और न ही - मुझे इस बात का अंदाजा है कि ऐसा क्यों होता है। किनारे के पास के तारे इसके बहुत करीब होते हैं, जिससे उनकी ओर बढ़ने की एक महत्वपूर्ण संभावना होती है (सितारे ज्यादातर सबसे अलग-थलग बिंदु की ओर बढ़ते हैं, पास के बिंदु नहीं)। लेकिन वे किनारे के पास दो दूर बिंदुओं की ओर बढ़ने के बीच वैकल्पिक रूप से, अप्रत्यक्ष रूप से किनारे की ओर बढ़ सकते हैं, जिसके परिणामस्वरूप एक झिझक मार्ग हो सकता है। मुझे संदेह है कि इसका मतलब यह है कि किनारों के पास सितारों का होना आवश्यक है, लेकिन मैं एक और दृष्टिकोण को देखने के लिए उत्सुक हूं कि क्या यह बग / फीचर साझा करता है ...
ट्राइकोप्लाक्स

@ dan04 मेरा दूसरा उत्तर यह प्रतीत होता है कि सितारों को किनारों के पास होने की आवश्यकता नहीं है जैसा मैंने सोचा था, और मेरे पहले उत्तर की तुलना में बेहतर परिणाम देता है। अप्रत्यक्ष रूप से अधिकतम के माध्यम से सीधे मतलब के साथ काम करना अधिक प्रभावी हो जाता है।
ट्राइकोप्लाक्स

3

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

from __future__ import division
import math
import sys

def divisors(n):
    """
    Return all divisors of n (including n itself) as a set.
    """
    result = {1, n}
    # Use +2 instead of +1 to allow for floating-point error.
    for i in range(2, int(math.sqrt(n)) + 2):
        if n % i == 0:
            result.add(i)
            result.add(n // i)
    return result

def squareness(width, height):
    """
    Given the dimensions of a rectangle, return a value between 0 and 1
    (1 iff width == height) measuring how close it is to being a square.
    """
    if width and height:
        return min(width / height, height / width)
    else:
        return 0.0

def star_grid(num_stars, width, height):
    """
    Return the factors (x, y) of num_stars that optimize the mean
    distance to the nearest star.
    """
    best_squareness = 0.0
    best_dimensions = (None, None)
    for nx in divisors(num_stars):
        ny = num_stars // nx
        sq = squareness(width / nx, height / ny)
        if sq > best_squareness:
            best_squareness = sq
            best_dimensions = (nx, ny)
    return best_dimensions

def star_coords(num_stars, width, height):
    """
    Return a list of (x, y) coordinates for the stars.
    """
    nx, ny = star_grid(num_stars, width, height)
    for ix in range(nx):
        x = (ix + 0.5) * width / nx
        for iy in range(ny):
            y = (iy + 0.5) * height / ny
            yield (x, y)

def _main(argv=sys.argv):
    num_stars = int(argv[1])
    width = float(argv[2])
    height = float(argv[3])
    for coord in star_coords(num_stars, width, height):
        print('%g,%g' % coord)

if __name__ == '__main__':
    _main()

50 सितारों के लिए आउटपुट

(चौड़ाई = 1.4, ऊंचाई = 1.0)

एक 10 × 5 आयत।

0.07,0.1
0.07,0.3
0.07,0.5
0.07,0.7
0.07,0.9
0.21,0.1
0.21,0.3
0.21,0.5
0.21,0.7
0.21,0.9
0.35,0.1
0.35,0.3
0.35,0.5
0.35,0.7
0.35,0.9
0.49,0.1
0.49,0.3
0.49,0.5
0.49,0.7
0.49,0.9
0.63,0.1
0.63,0.3
0.63,0.5
0.63,0.7
0.63,0.9
0.77,0.1
0.77,0.3
0.77,0.5
0.77,0.7
0.77,0.9
0.91,0.1
0.91,0.3
0.91,0.5
0.91,0.7
0.91,0.9
1.05,0.1
1.05,0.3
1.05,0.5
1.05,0.7
1.05,0.9
1.19,0.1
1.19,0.3
1.19,0.5
1.19,0.7
1.19,0.9
1.33,0.1
1.33,0.3
1.33,0.5
1.33,0.7
1.33,0.9

0

जावास्क्रिप्ट - एक स्टार को बेतरतीब ढंग से स्थानांतरित करें यदि मतलब दूरी कम हो

(प्रक्रिया के एक एनीमेशन के साथ)

यह मेरे पहले जवाब के रूप में इस तरह के एक व्यस्त एनीमेशन नहीं देता है, लंबे समय तक बिना किसी आंदोलन के साथ संभावित पुनर्व्यवस्थाओं का परीक्षण और अस्वीकार कर दिया जाता है। हालांकि, अंतिम परिणाम में कम औसत दूरी है, इसलिए यह विधि एक सुधार है।

दृष्टिकोण अभी भी बहुत सरल है:

  • यादृच्छिक पर एक स्टार चुनें
  • इसे एक यादृच्छिक दिशा में एक यादृच्छिक दूरी पर ले जाएं
  • यदि औसत दूरी कम हो जाती है, तो नई स्थिति रखें

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

प्रश्न के रूप में आवश्यक है, यह xorshift का उपयोग करने के बजाय यादृच्छिक फ़ंक्शन में निर्मित का उपयोग नहीं करता है ।

अधिकांश कोड कवर सेट अप और एनीमेशन - एल्गोरिदम लागू करने वाला भाग फ़ंक्शन है adjustStars

कोड

आप नीचे दिए गए स्टैक स्निपेट में प्रक्रिया को प्रगति पर देख सकते हैं।

stars = [];
timeoutId = 0;

resetRandomNumberGenerator();

function resetRandomNumberGenerator() {
  rng_x = 114; // Numbers for the random number generator.
  rng_y = 342;
  rng_z = 982;
  rng_w = 443;
}

$(document).ready(function() {
  c = document.getElementById('canton');
  ctx = c.getContext('2d');
  resizeCanvas();
});

function stop() {
  clearTimeout(timeoutId);
}

function arrange() {
  clearTimeout(timeoutId);
  resetStars();
  resetRandomNumberGenerator();
  maxStepSize = Math.min(cantonWidth, cantonHeight) / 16;
  adjustStars(maxStepSize, 7000, 15000);
}

function resizeCanvas() {
  cantonWidth = parseFloat($('#width').val());
  cantonHeight = parseFloat($('#height').val());
  starRadius = cantonHeight / 20;
  document.getElementById('canton').width = cantonWidth;
  document.getElementById('canton').height = cantonHeight;
  ctx.fillStyle = 'white';
  resetStars();
}

function resetStars() {
  stop();
  stars = [];
  population = parseInt($('#stars').val(), 10);
  shortSide = Math.floor(Math.sqrt(population));
  longSide = Math.ceil(population / shortSide);
  if (cantonWidth < cantonHeight) {
    horizontalStars = shortSide;
    verticalStars = longSide;
  } else {
    horizontalStars = longSide;
    verticalStars = shortSide;
  }
  horizontalSpacing = cantonWidth / horizontalStars;
  verticalSpacing = cantonHeight / verticalStars;
  for (var i = 0; i < population; i++) {
    x = (0.5 + (i % horizontalStars)) * horizontalSpacing;
    y = (0.5 + Math.floor(i / horizontalStars)) * verticalSpacing;
    stars.push([x, y]);
  }
  drawStars();
  updateOutputText();
}

function adjustStars(stepSize, maxSteps, numberOfPoints) {
  $('#stepsRemaining').text(maxSteps + ' steps remaining');
  var points = randomPoints(numberOfPoints);
  currentMean = meanDistance(stars, points);
  potentialStars = shiftedStars(stepSize);
  potentialMean = meanDistance(potentialStars, points);
  if (potentialMean < currentMean) {
    stars = potentialStars;
  }
  drawStars();
  updateOutputText();
  
  if (maxSteps > 0) {
    timeoutId = setTimeout(adjustStars, 10, stepSize * 0.999, maxSteps - 1, numberOfPoints);
  }
}

function shiftedStars(stepSize) {
  shifted = [];
  chosenOne = Math.floor(xorshift() * stars.length);
  for (i = 0; i < stars.length; i++) {
    star = stars[i];
    x = star[0];
    y = star[1];
    if (i === chosenOne) {
      for (n = 0; n < 10; n++) {
        x += xorshift() * stepSize;
        x -= xorshift() * stepSize;
        y += xorshift() * stepSize;
        y -= xorshift() * stepSize;
      }
      if (x < 0) x = 0;
      if (x > cantonWidth) x = cantonWidth;
      if (y < 0) y = 0;
      if (y > cantonHeight) y = cantonHeight;
    }
    shifted.push([x, y]);
  }
  return shifted;    
}

function meanDistance(arrayOfStars, arrayOfPoints) {
  var totalDistance = 0;
  for (i = 0; i < arrayOfPoints.length; i++) {
    point = arrayOfPoints[i];
    x = point[0];
    y = point[1];
    totalDistance += nearestStarDistance(x, y, arrayOfStars);
  }
  return totalDistance / arrayOfPoints.length;
}

function randomPoints(numberOfPoints) {
  var arrayOfPoints = [];
  for (i = 0; i < numberOfPoints; i++) {
    x = xorshift() * cantonWidth;
    y = xorshift() * cantonHeight;
    arrayOfPoints.push([x, y]);
  }
  return arrayOfPoints;
}

function updateOutputText() {
  starText = '';
  for (var i = 0; i < stars.length; i++) {
    starText += stars[i][0] + ', ' + stars[i][1] + '\n';
  }
  $('#coordinateList').text(starText);
}

function xorshift() {
  rng_t = rng_x ^ (rng_x << 11);
  rng_x = rng_y;
  rng_y = rng_z;
  rng_z = rng_w;
  rng_w = rng_w ^ (rng_w >> 19) ^ rng_t ^ (rng_t >> 8);
  result = rng_w / 2147483648
  return result
}

function nearestStarDistance(x, y, starsToUse) {
  var distances = [];
  for (var i = 0; i < stars.length; i++) {
    star = starsToUse[i];
    distances.push(distance(x, y, star[0], star[1]));
  }
  minimum = Infinity;
  for (i = 0; i < distances.length; i++) {
    if (distances[i] < minimum) {
      minimum = distances[i];
    }
  }
  return minimum;
}

function distance(x1, y1, x2, y2) {
  var x = x2 - x1;
  var y = y2 - y1;
  return Math.sqrt(x * x + y * y);
}

function drawStars() {
  ctx.clearRect(0, 0, cantonWidth, cantonHeight);
  for (i = 0; i < stars.length; i++) {
    star = stars[i];
    x = star[0];
    y = star[1];
    drawStar(x, y);
  }
}

function drawStar(x, y) {
  ctx.beginPath();
  ctx.moveTo(x, y - starRadius);
  ctx.lineTo(x - 0.588 * starRadius, y + 0.809 * starRadius);
  ctx.lineTo(x + 0.951 * starRadius, y - 0.309 * starRadius);
  ctx.lineTo(x - 0.951 * starRadius, y - 0.309 * starRadius);
  ctx.lineTo(x + 0.588 * starRadius, y + 0.809 * starRadius);
  ctx.fill();
}
canvas {
  margin: 0;
  border: medium solid gray;
  background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<input id='stars' onchange='resetStars()' type='number' value='13' min='13' max='50' maxlength='2' step='1'>stars
<br>
<input id='width' onchange='resizeCanvas()' type='number' value='494' min='1' max='500' maxlength='3' step='any'>width
<br>
<input id='height' onchange='resizeCanvas()' type='number' value='350' min='1' max='500' maxlength='3' step='any'>height
<br>
<button type='button' onclick='resetStars()'>Reset Stars</button>
<button type='button' onclick='arrange()'>Arrange Stars</button>
<button type='button' onclick='stop()'>Stop</button>
<textarea id='stepsRemaining' rows='1' readonly></textarea>
<br>
<canvas id='canton' width='494' height='350'></canvas>
<br>
<textarea id='coordinateList' rows='50' cols='40' readonly></textarea>

50 सितारों के लिए आउटपुट

(चौड़ाई = 1.4, ऊंचाई = 1.0)

औसत दूरी 0.06402754713808706 है।

निर्देशांक:

0.08147037630270487, 0.07571240182553095
0.24516777356538358, 0.0803538189052793
0.431021735247462, 0.07821284835132788
0.6001163609128221, 0.08278495286739646
0.7668077034213632, 0.0821321119375313
0.941333266969696, 0.08040530195264808
1.1229190363750599, 0.07255685332834291
1.3074771164489858, 0.07681674948141588
0.09227450444336446, 0.2257047798057907
0.33559513774978766, 0.20668611954667682
0.5182463448452704, 0.23841239342827816
0.6630614113293541, 0.26097114328053417
0.821886619004045, 0.23577904321258844
1.012597304977012, 0.23308200382761057
1.174938874706673, 0.22593017096601203
1.3285181935709358, 0.24024108928169902
0.0746772556909648, 0.3920030109869904
0.23006559905554042, 0.3204287339854068
0.4086004105498357, 0.3507788129168045
0.5669847710831315, 0.4371913211100495
0.7399474422203116, 0.41599441829489137
0.9099913571857917, 0.36933063808924294
1.1170137101288482, 0.3905679602615213
1.3037811235560612, 0.3979526346564911
0.09290206345982034, 0.5678420747594305
0.23463227399157258, 0.47552307265325633
0.4042403660145938, 0.5030345851947539
0.6611151741402685, 0.5918138006294138
0.8237963249937061, 0.5663224022272697
0.9812774216782155, 0.5032518469083094
1.146386501309064, 0.570255729516661
1.3185563715676663, 0.5571870810112576
0.07541940949872694, 0.7356649763259809
0.2877585652075202, 0.6321535875762999
0.4952646673275116, 0.6343336480073624
0.6965646728710738, 0.9178076185211137
0.7903485281657828, 0.7508031981325222
0.9774998621426763, 0.6683301268754337
1.1539480102558823, 0.7513836972857155
1.3177199931376755, 0.7245296168327016
0.22215183098388988, 0.7769843436963862
0.4048364942297627, 0.7779653803681718
0.5021290208205218, 0.9254525763987298
0.6058821167972933, 0.7683130432395833
0.8777330967719849, 0.9201076171801651
0.9894820530574747, 0.8172934111543102
1.1143371956097312, 0.9265012354173626
1.3045771339439551, 0.9069856484512913
0.0930066325438706, 0.9157592790749175
0.2959676633891297, 0.9251379492518523
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.