長方形の円パッキング


8

あなたの仕事は、N個の円が持つことができる最大半径を見つけ、それでもX×Yピクセルの大きさの長方形の内側に収まるプログラムを書くことです。(このウィキペディアの記事と同様)プログラムは、これらのN円の最大可能半径と最適位置を見つけて 、

  1. 2つの円が重なることはありません
  2. すべての円が長方形の内側に収まります。

次に、プログラムはこれをコンソールに出力します。

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) 

(明らかに、some_numberをプログラムが計算する半径、Nは最終的に使用する円の数、xとyは円の実際の座標に置き換える必要があります)

最後に、これらの円が描かれた画像を作成して保存する必要があります。

ルール:

  1. このプログラムは、任意のサイズの長方形と任意の数の円で実行する必要がありますが、有効な答えを得ることができます。コマンドライン引数、ユーザー入力、ハードコードされた変数など、必要なものを使用できます。

  2. 円が重なっている場合や、ボックスの内側に完全に収まらない場合、提出は無効です。

  3. 各円の半径は同じでなければなりません。

  4. これを合理的かつ実行可能にするために、すべての数値は小数点第2位まで正確でなければなりません。

これはコードゴルフなので、最短のプログラム(2014年10月28日現在)が優勝します。



1
すべての可能性を反復するソリューションを許可しますか?つまり、すべての定性的な構成ではなく、機械の精度までの各円の可能なすべての中心と半径を意味します。
xnor 2014年

4
言うまでもなく、プログラムが任意の数の円で実行する必要がある場合、サンプル出力では、任意の数の英語名を生成できる必要があります。
Peter Taylor

3
「小数点第2位まで」という意味ですか?100分の1は非常に合理的でも実行可能でもないようです。;)ただし、精度をほんの少しだけ必要とする場合は、整数ですべてを実行することもできます。とにかく、1単位が1ピクセルに対応している場合、より正確にプロットすることはできません。
マーティンエンダー2014年

3
この問題は、少なくとも2014年には文字通り不可能です。この問題の最適な解決策は数​​学には知られていないため、回答が有効かどうかを確認することは完全に不可能です。私は少し考えてこれを保存することは可能だと思います。たとえば、x、y、Nのいずれかの値に対してより良い解決策が見つかるとプログラムが無効になると言ったり、スコアベースのコードチャレンジを作成したりするだけです。あなたのプログラムが見つけることができる最大の半径で。しかし、現在書かれているように、有効な答えを得る方法はありません。
Nathaniel

回答:


8

JavaScript 782 725文字

最初の投稿、優しくしてください!

これで、プログラムはラップされた関数を介して呼び出されます。例:(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);


テスト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>

明らかに、半径は正確に50であると予想しますが、質問のコメントで説明されている理由により、合理的にそれを実現することはできませんでした。SVGは次のようになります...

200 200 4


テスト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>

そして、SVGは次のようになります...

ここに画像の説明を入力してください


テスト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>

そして、SVGは次のようになります...

ここに画像の説明を入力してください

彼らはすべてき​​れいではありません。


使い方

以下のゴルフされていないコード。このプログラムには2つの前提があります。

  1. 常に1つの円が隅にあります。これはかなり安全な賭けのようです。
  2. すべての円は常に別の円に触れています。なぜそうならないのかわかりません。

プログラムは、ボックスの寸法に基づいて大きな半径を計算することから始めます。次に、ボックスの隅に1つの円を収めようとします。その円が適合する場合、それはその円から直径線を延長し、線の端に円を作成しようとします。新しい円が収まると、新しい円から別の線が延長されます。収まらない場合は、ラインが360度スイングし、空きスペースを確認します。必要な数の円が作成される前にボックスがいっぱいになると、半径が小さくなり、すべてが最初からやり直されます。


Ungolfedコード(スニペット)

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.