Kemasan lingkaran dalam persegi panjang

8

Tugas Anda adalah menulis sebuah program yang menemukan jari-jari terbesar yang bisa dimiliki lingkaran N dan masih muat di dalam persegi panjang berukuran X demi Y piksel. (Mirip dengan artikel wikipedia ini ) Program Anda harus menemukan radius terbesar dan posisi optimal dari lingkaran N ini sehingga

  1. Tidak ada dua lingkaran yang tumpang tindih
  2. Semua lingkaran pas di dalam persegi panjang.

Program Anda kemudian harus mencetak ini ke konsol:

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) 

(Jelas, Anda harus mengganti some_number dengan jari-jari yang dihitung program Anda, N dengan jumlah lingkaran yang akhirnya Anda gunakan, dan x dan y dengan koordinat sebenarnya dari lingkaran)

Terakhir, itu harus membuat dan menyimpan gambar dengan lingkaran ini digambar.

Aturan:

  1. Program ini harus dijalankan dengan berbagai ukuran persegi panjang, dan sejumlah lingkaran dan masih mendapatkan jawaban yang valid. Anda dapat menggunakan argumen baris perintah, input pengguna, variabel kode keras, atau apa pun yang Anda inginkan.

  2. Jika ada lingkaran yang tumpang tindih atau tidak sepenuhnya masuk ke dalam kotak, kiriman Anda tidak valid.

  3. Setiap lingkaran harus memiliki jari-jari yang sama.

  4. Hanya untuk membuat ini masuk akal dan bisa dilakukan, semua angka harus tepat ke tempat desimal ke-2.

Ini golf kode, jadi program tersingkat (per 10/28/2014) menang.

James
sumber
6
FYI melakukan ini secara optimal tidaklah mudah. "Solusi (belum tentu optimal) telah dihitung untuk setiap N≤10.000."
Calvin Hobi
1
Apakah Anda mengizinkan solusi yang dapat mengatasi setiap kemungkinan? Maksud saya setiap pusat dan radius yang memungkinkan untuk setiap lingkaran hingga ke presisi mesin, tidak setiap konfigurasi kualitatif.
xnor
4
Belum lagi bahwa jika program harus dijalankan dengan setiap jumlah lingkaran, output sampel akan memerlukannya untuk dapat menghasilkan nama bahasa Inggris untuk setiap nomor.
Peter Taylor
3
Apakah maksud Anda "ke tempat desimal kedua"? Karena keseratus tampaknya tidak terlalu masuk akal atau tidak bisa dilakukan. ;) Meskipun, jika Anda hanya menginginkan sedikit presisi, kami mungkin juga melakukan semuanya dalam bilangan bulat. Kami tidak dapat benar-benar merencanakannya dengan lebih akurat jika 1 unit sesuai dengan 1 piksel.
Martin Ender
3
Tantangan ini benar-benar mustahil, setidaknya pada tahun 2014. Solusi optimal untuk masalah ini tidak diketahui oleh matematika, sehingga sama sekali tidak mungkin untuk memeriksa apakah jawaban itu valid atau tidak. Saya pikir mungkin untuk menyimpan ini dengan sedikit pemikiran, misalnya dengan mengatakan bahwa program Anda menjadi tidak valid jika ada yang menemukan solusi yang lebih baik untuk setiap nilai x, y dan N. Atau hanya membuatnya menjadi tantangan kode , dengan skor berdasarkan pada radius terbesar yang bisa ditemukan oleh program Anda. Tetapi seperti yang tertulis sekarang tidak mungkin Anda bisa mendapatkan jawaban yang valid.
Nathaniel

Jawaban:

8

JavaScript 782 725 karakter

posting pertama, lembut!

Program sekarang dipanggil melalui fungsi terbungkus. Misalnya: (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);


Tes 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>

Jelas kami berharap radiusnya tepat 50, tetapi untuk alasan yang dibahas dalam komentar pertanyaan, saya tidak bisa secara wajar mewujudkannya. SVG terlihat seperti ini ...

200 200 4


Tes 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>

Dan SVG terlihat seperti ini ...

masukkan deskripsi gambar di sini


Tes 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>

Dan SVG terlihat seperti ini ...

masukkan deskripsi gambar di sini

Tidak semuanya cantik.


Bagaimana itu bekerja

Kode di bawah ini tidak dikumpulkan. Program ini memiliki dua asumsi:

  1. Satu lingkaran akan selalu ada di sudut. Sepertinya ini taruhan yang cukup aman.
  2. Setiap lingkaran akan selalu menyentuh lingkaran lain. Saya tidak mengerti mengapa tidak.

Program dimulai dengan menghitung radius besar berdasarkan dimensi kotak. Kemudian mencoba memasukkan satu lingkaran di sudut kotak. Jika lingkaran itu cocok, itu akan memperpanjang garis diameter dari lingkaran itu dan mencoba untuk membuat lingkaran di ujung garis. Jika lingkaran baru cocok, garis lain akan diperpanjang dari lingkaran baru. Jika tidak pas, garis akan berayun 360 derajat, memeriksa ruang terbuka. Jika kotak terisi sebelum jumlah lingkaran yang diinginkan dibuat, jari-jari dikurangi dan semuanya dimulai lagi.


Kode Tidak Terkunci (cuplikan)

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

Rip Leeb
sumber