Đóng gói hình tròn trong một hình chữ nhật


8

Nhiệm vụ của bạn là viết chương trình tìm bán kính lớn nhất mà N vòng tròn có thể có và vẫn vừa với bên trong hình chữ nhật có kích thước X x Y pixel lớn. (tương tự bài viết trên wikipedia này ) Chương trình của bạn phải tìm bán kính lớn nhất có thể và vị trí tối ưu của các vòng tròn N này để

  1. Không có hai vòng tròn trùng nhau
  2. Tất cả các vòng tròn phù hợp bên trong hình chữ nhật.

Chương trình của bạn sau đó sẽ in nó ra bàn điều khiển:

Highest possible radius: <some_number>
Circle 1 Focus: (x, y)
Circle 2 Focus: (x, y)
...
Circle N-1 Focus: (x, y)
Circle N Focus: (x, y) 

(Rõ ràng, bạn phải thay thế một số số bằng bán kính mà chương trình của bạn tính toán, N bằng số vòng tròn bạn kết thúc sử dụng và x và y bằng tọa độ thực của vòng tròn)

Cuối cùng, nó sẽ tạo và lưu một hình ảnh với các vòng tròn được vẽ.

Quy tắc:

  1. Chương trình này phải chạy với bất kỳ kích thước nào của hình chữ nhật và bất kỳ số lượng vòng tròn nào và vẫn nhận được câu trả lời hợp lệ. Bạn có thể sử dụng các đối số dòng lệnh, đầu vào của người dùng, các biến được mã hóa cứng hoặc bất cứ thứ gì bạn muốn.

  2. Nếu bất kỳ vòng tròn nào trùng lặp hoặc không vừa hoàn toàn bên trong hộp, việc gửi của bạn không hợp lệ.

  3. Mỗi vòng tròn phải có cùng bán kính.

  4. Để làm cho điều này hợp lý và có thể thực hiện được, tất cả các số phải chính xác đến vị trí thập phân thứ 2.

Đây là mã golf, vì vậy chương trình ngắn nhất (tính đến ngày 10/11/2014) sẽ thắng.



1
Bạn có cho phép một giải pháp lặp đi lặp lại trên mọi khả năng? Ý tôi là mọi trung tâm và bán kính có thể có cho mỗi vòng tròn cho đến độ chính xác của máy, không phải mọi cấu hình định tính.
xnor

4
Chưa kể rằng nếu chương trình phải chạy với bất kỳ số vòng tròn nào, đầu ra mẫu sẽ yêu cầu nó có thể tạo ra một tên tiếng Anh cho bất kỳ số nào.
Peter Taylor

3
Ý của bạn là "đến vị trí thập phân thứ hai"? Bởi vì thứ một trăm dường như không hợp lý cũng không rất khả thi. ;) Mặc dù, nếu bạn chỉ muốn rất ít độ chính xác, chúng tôi cũng có thể làm mọi thứ trong số nguyên. Chúng tôi thực sự không thể vẽ nó chính xác hơn nếu 1 đơn vị tương ứng với 1 pixel.
Martin Ender

3
Thách thức này theo nghĩa đen là không thể, ít nhất là trong năm 2014. Giải pháp tối ưu cho vấn đề này không được toán học biết đến, vì vậy sẽ hoàn toàn không thể kiểm tra xem câu trả lời có hợp lệ hay không. Tôi nghĩ rằng có thể lưu lại điều này với một chút suy nghĩ, ví dụ như bằng cách nói rằng chương trình của bạn trở nên không hợp lệ nếu có ai tìm được giải pháp tốt hơn cho bất kỳ giá trị nào của x, y và N. Hoặc chỉ thực hiện thử thách mã , với điểm số dựa trên trên bán kính lớn nhất chương trình của bạn có thể tìm thấy. Nhưng như đã viết bây giờ, không có cách nào bạn có thể nhận được bất kỳ câu trả lời hợp lệ nào.
Nathaniel

Câu trả lời:


8

JavaScript 782 725 ký tự

bài đầu tiên, hãy nhẹ nhàng!

Chương trình này được gọi thông qua chức năng gói. Vd : (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);


Kiểm tra 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>

Rõ ràng chúng ta sẽ mong đợi bán kính là chính xác 50, nhưng vì những lý do được thảo luận trong các bình luận của câu hỏi, tôi không thể làm cho nó xảy ra một cách hợp lý. SVG trông như thế này ...

200 200 4


Kiểm tra 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>

Và SVG trông như thế này ...

nhập mô tả hình ảnh ở đây


Bài kiểm tra 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>

Và SVG trông như thế này ...

nhập mô tả hình ảnh ở đây

Tất cả đều không đẹp.


Làm thế nào nó hoạt động

Mã mã dưới đây. Chương trình này có hai giả định:

  1. Một vòng tròn sẽ luôn ở trong góc. Đây có vẻ như là một đặt cược khá an toàn.
  2. Mỗi vòng tròn sẽ luôn được chạm vào một vòng tròn khác. Tôi không thấy lý do tại sao họ sẽ không.

Chương trình bắt đầu bằng cách tính bán kính lớn dựa trên kích thước hộp. Sau đó, nó cố gắng để phù hợp với một vòng tròn trong góc của hộp. Nếu vòng tròn đó vừa, nó sẽ kéo dài một đường kính từ vòng tròn đó và cố gắng tạo một vòng tròn ở cuối dòng. Nếu vòng tròn mới phù hợp, một dòng khác sẽ được mở rộng từ vòng tròn mới. Nếu nó không phù hợp, dòng sẽ xoay 360 độ, kiểm tra các không gian mở. Nếu hộp lấp đầy trước khi số vòng tròn mong muốn được tạo, bán kính sẽ giảm và tất cả bắt đầu lại.


Mã Ungolfed (đoạn trích)

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.