JavaScript 782 725 characters
first post, be gentle!
The program is now called via the wrapped function. Eg: (function(e,f,g){...})(100,200,10)
.
function C(e,f,g,c,a,d){if(0>g-a||g+a>e||0>c-a||c+a>f)return d;for(var b in d)if(Math.sqrt(Math.pow(d[b].x-g,2)+Math.pow(d[b].y-c,2))<2*a)return d;d.push({x:g,y:c});for(b=0;b<Math.PI;)XX=Math.cos(b)*a*2+g,YY=Math.sin(b)*a*2+c,d=C(e,f,XX,YY,a,d),b+=.01;return d}
(function(e,f,g){var c=e+f,a,d;for(a=[];a.length<g;)a=d=c,a=C(e,f,a,d,c,[]),c-=.01;console.log("Highest possible radius: "+Math.round(100*c)/100);e='<svg width="'+e+'" height="'+f+'"><rect width="'+e+'" height="'+f+'" style="fill:red" />';for(var b in a)console.log("Circle "+b+" Focus: ("+Math.round(100*a[b].x)/100+", "+Math.round(100*a[b].y)/100+")"),e+='<circle cx="'+a[b].x+'" cy="'+a[b].y+'" r="'+c+'" fill="blue" />';console.log(e+"</svg>")})(400,300,13);
Test 1
(function(e,f,g){...})(200,200,4)
Highest possible radius: 49.96
Circle 1 Focus: (49.97, 49.97)
Circle 2 Focus: (149.91, 49.97)
Circle 3 Focus: (149.99, 149.91)
Circle 4 Focus: (50.05, 149.91)
<svg width="200" height="200"><rect width="200" height="200" style="fill:blue;" /><circle cx="49.97000000021743" cy="49.97000000021743" r="49.960000000217434" fill="white" /><circle cx="149.9100000006523" cy="49.97000000021743" r="49.960000000217434" fill="white" /><circle cx="149.98958489212322" cy="149.90996831285986" r="49.960000000217434" fill="white" /><circle cx="50.04958489168835" cy="149.90996831285986" r="49.960000000217434" fill="white" /></svg>
Obviously we would expect the radius to be exactly 50, but for reasons discussed in the question's comments, I couldn't reasonably make it happen. The SVG looks like this...
Test 2
(function(e,f,g){...})(100,400,14)
Highest possible radius: 26.55
Circle 1 Focus: (26.56, 26.56)
Circle 2 Focus: (79.68, 26.56)
Circle 3 Focus: (132.8, 26.56)
Circle 4 Focus: (185.92, 26.56)
Circle 5 Focus: (239.04, 26.56)
Circle 6 Focus: (292.16, 26.56)
Circle 7 Focus: (345.28, 26.56)
Circle 8 Focus: (372.63, 72.1)
Circle 9 Focus: (319.52, 73.25)
Circle 10 Focus: (265.47, 72.64)
Circle 11 Focus: (212.35, 73.25)
Circle 12 Focus: (159.23, 72.64)
Circle 13 Focus: (106.11, 73.25)
Circle 14 Focus: (52.99, 72.64)
<svg width="400" height="100"><rect width="400" height="100" style="fill:blue;" /><circle cx="26.560000000311106" cy="26.560000000311106" r="26.550000000311105" fill="white" /><circle cx="79.68000000093332" cy="26.560000000311106" r="26.550000000311105" fill="white" /><circle cx="132.80000000155553" cy="26.560000000311106" r="26.550000000311105" fill="white" /><circle cx="185.92000000217774" cy="26.560000000311106" r="26.550000000311105" fill="white" /><circle cx="239.04000000279996" cy="26.560000000311106" r="26.550000000311105" fill="white" /><circle cx="292.16000000342217" cy="26.560000000311106" r="26.550000000311105" fill="white" /><circle cx="345.2800000040444" cy="26.560000000311106" r="26.550000000311105" fill="white" /><circle cx="372.6271770491687" cy="72.09972230654316" r="26.550000000311105" fill="white" /><circle cx="319.5195599732359" cy="73.24663493712801" r="26.550000000311105" fill="white" /><circle cx="265.47097406711805" cy="72.63752174440503" r="26.550000000311105" fill="white" /><circle cx="212.35454341475625" cy="73.25330971030218" r="26.550000000311105" fill="white" /><circle cx="159.23097406587362" cy="72.63752174440503" r="26.550000000311105" fill="white" /><circle cx="106.11454341351183" cy="73.25330971030218" r="26.550000000311105" fill="white" /><circle cx="52.99097406462921" cy="72.63752174440503" r="26.550000000311105" fill="white" /></svg>
And the SVG looks like this...
Test 3
(function(e,f,g){...})(400,400,3)
Highest possible radius: 101.68
Circle 1 Focus: (101.69, 101.69)
Circle 2 Focus: (298.23, 153.98)
Circle 3 Focus: (154.13, 298.19)
<svg width="400" height="400"><rect width="400" height="400" style="fill:blue;" /><circle cx="101.69000000059772" cy="101.69000000059772" r="101.68000000059772" fill="white" /><circle cx="298.2343937547503" cy="153.97504264473156" r="101.68000000059772" fill="white" /><circle cx="154.13153961740014" cy="298.19269546075066" r="101.68000000059772" fill="white" /></svg>
And the SVG looks like this...
They aren't all pretty.
How it works
Ungolfed code below. This program has two assumptions:
- One circle will always be in the corner. This seems like a pretty safe bet.
- Every circle will always be touching another circle. I don't see why they wouldn't be.
The program starts by calculating a large radius based on the box dimensions. It then tries to fit one circle in the corner of the box. If that circle fits, it extends a diameter line from that circle and tries to create a circle at the end of the line. If the new circle fits, another line will be extended from the new circle. If it doesn't fit, the line will swing 360 degrees, checking for open spaces. If the box fills up before the desired number of circles are created, the radius is reduced and it all starts over again.
Ungolfed Code (snippet)
// this functions attempts to build a circle
// at the given coords. If it works, it will
// spawn additional circles.
function C(x, y, X, Y, r, cc){
// if this circle does not fit in the rectangle, BAIL
if(X-r < 0 || X+r > x || Y-r < 0 || Y+r > y)
return cc;
// if this circle is too close to another circle, BAIL
for(var c in cc){
if( Math.sqrt(Math.pow(cc[c].x - X, 2) + Math.pow(cc[c].y - Y, 2)) < (r*2) )
return cc;
}
// checks passed so lets call this circle valid and add it to stack
cc.push({"x": X, "y": Y});
// now rotate to try to find additional spots for circles
var a = 0; // radian for rotation
while(a < Math.PI){
XX = Math.cos(a)*r*2 + X;
YY = Math.sin(a)*r*2 + Y;
cc = C(x, y, XX, YY, r, cc);
a += .01; // CHANGE FOR MORE OR LESS PRECISION
}
return cc;
}
// this function slowly reduces the radius
// and checks for correct solutions
// also prints svg graphic code
(function B(x, y, n){
var r = x + y; // pick a big radius
var X, Y; // these are the coords of the current circle. golf by combining this with `var r..`?
var cc = []; // array of coordinates of the circles
// while we cant fit n circles, reduce the radius and try again
while(cc.length < n){
X = Y = r;
cc = C(x, y, X, Y, r, []);
r-=.01; // CHANGE FOR MORE OR LESS PRECISION
}
console.log('Highest possible radius: ' + Math.round(r*100)/100);
var s = '<svg width="' + x + '" height="' + y + '"><rect width="' + x + '" height="' + y + '" style="fill:red" />';
for(var c in cc){
console.log('Circle '+c+' Focus: (' + Math.round(cc[c].x*100)/100 + ', ' + Math.round(cc[c].y*100)/100 + ')');
s += '<circle cx="' + cc[c].x + '" cy="' + cc[c].y + '" r="' + r + '" fill="blue" />';
}
s += '</svg>';
console.log(s);
document.write(s);
})(150, 150, 5);
In this site he calculated the maximum number of circles in a square using two methods , normal method and triangle method, the question is how he calculated the number of circles using triangle method.. https://www.engineeringtoolbox.com/circles-within-rectangle-d_1905.html
– user732153 – 2019-12-05T21:59:58.5436
FYI doing this optimally is not exactly easy. "Solutions (not necessarily optimal) have been computed for every N≤10,000."
– Calvin's Hobbies – 2014-10-23T04:13:54.7071Would you allow a solution that iterates over every possibility? By which I mean every possible center and radius for each circle up to machine precision, not every qualitative configuration. – xnor – 2014-10-23T05:16:04.473
4Not to mention that if the program must run with any number of circles, the sample output would require it to be able to produce an English name for any number. – Peter Taylor – 2014-10-23T08:41:43.057
Fair point Martin, let me make the output more specific. Also, I said 300x300 with 5 circles because it's kind of confusing to say "Some number of circles with some size of rectangle" I'll make it a little more clear. – James – 2014-10-23T18:29:37.367
xnor, sure that will do fine. – James – 2014-10-23T18:30:29.367
3Did you mean "to the second decimal place"? Because the hundredth seems neither very reasonable nor very doable. ;) Although, if you only want so little precision we might as well do everything in integers. We can't really plot it more accurately anyway if 1 unit corresponds to 1 pixel. – Martin Ender – 2014-10-23T18:52:08.650
3This challenge is literally impossible, at least in 2014. The optimal solution to this problem is not known to mathematics, so it will be completely impossible to check whether answers are valid or not. I think it might be possible to save this with a little thought, e.g. by saying that your program becomes invalid if anyone finds a better solution for any values of x, y and N. Or just making it [tag:code-challenge], with the score based on the largest radius your program can find. But as it's written now there's no way you can possibly get any valid answers. – Nathaniel – 2014-10-24T05:16:36.670
So what do you propose I do? Leave it up as one of the impossible challenges that never get solved, Like this one? Edit the heck out of this until it becomes do-able? Scratch it and start over? I can't put it in the sand box, as I'm < 50 rep.
– James – 2014-10-24T05:49:49.767I'm a bit confused about the precision. You say "rectangle that is X by Y pixels large". Is that simply meant to specify a dimension of XY, or is the pixel the minimum unit of granularity (so that circles must be centered on a pixel)? Or does "all numbers must be precise to the 2nd decimal place" mean that there's X100 and Y*100 possible center locations? Or is that sentence simply saying how we should give our output? – xnor – 2014-10-24T05:59:45.600
1@user3524982 my suggestion was to limit it to 5 circles. That is doable. The solution is to arrange the circles in an X for squarish rectangles, and in a W for long rectangles (which ends up as a straight linde for l/w>5.) The interesting part is the transition from the X arrangement to the W arrangement, which occurs over a very small range of l/w ratios. I deleted the suggestion because it didn't get any responses so I felt it would confuse more. Then the question was closed and reopened but the issue of complexity per the current spec remains. – Level River St – 2014-10-24T10:37:12.263
@user3524982 I believe you only need 5 rep and not 50 for the sandbox. 50 is for commenting on others' posts. – Martin Ender – 2014-10-24T10:58:47.983
1I think this question should be closed until it's modified. Currently, there are two conflicting winning objectives: code length and optimal positioning/radii. Since optimality has not been proven for large N or X by Y rectangle, this question is essentially unanswerable correctly. – qwr – 2014-10-25T04:26:22.390