Bir Apollon Contası çiz


28

Karşılıklı üç teğet daire verildiğinde , bu üçünün hepsine teğet olan iki daire daha bulabiliriz . Bu ikisine Apollon çevreleri denir . Apollonian çevrelerinden birinin gerçekte üç ilk çevrenin etrafında olabileceğini unutmayın .

Üç teğet çemberden başlayarak , aşağıdaki işlemle Apollonian conta adı verilen bir fraktal oluşturabiliriz :

  1. İlk 3 çevreyi ana çevreleri çağırın
  2. Ebeveyn çevrelerin iki Apollon çemberini bulun
  3. Her Apollon çemberi için:
    1. Üç çift üst çemberin her çifti için:
      1. Apollonian çevreye çağrı yapın ve iki ebeveyn yeni ebeveyn çevreler kümesini çevreleyin ve 2. adımdan itibaren yeniden başlayın.

Örneğin eşit büyüklükte dairelerle başlayalım:

görüntü tanımını buraya girin

Wikipedia'da bulunan resim

İhtiyacımız olan bir not daha var. Biz yarıçaplı bir daire varsa r merkezi (x, y) , biz 's eğrilik tanımlayabilir k = ± 1 / r . Genellikle k pozitif olur, ancak contadaki diğer tüm daireleri saran daireyi belirtmek için negatif k kullanabiliriz (yani tüm teğetler o daireye içerden temas eder). Ardından, üçlü sayıları olan bir daire belirleyebilirsiniz: (k, x * k, y * k) .

Bu sorunun amacı için, pozitif ve k ve rasyonel x ve y tamsayılarını alacağız .

Bu çevreler için başka örnekler Wikipedia makalesinde bulunabilir .

Bu makalede, entegre contalarla ilgili bazı ilginç şeyler de vardır (dairelerin bulunduğu diğer eğlenceli şeyler arasında).

Meydan okuma

Sen verilecektir 4 gibi görünecek, her biri çember spesifikasyonlarını, (14, 28/35, -112/105). Herhangi bir liste formatını ve bölme işlecini, istediğiniz zaman basit bir evalşekilde girebileceğiniz şekilde kullanabilirsiniz. 4 dairenin birbirine gerçekten teğet olduğunu ve ilkinde negatif eğriliğe sahip olduğunu varsayabilirsiniz. Bu size zaten diğer üçünün çevre Apollon çemberi verildiği anlamına gelir. Geçerli örnek girdilerin bir listesi için mücadelenin en altına bakın.

Bu girdi verildiğinde bir Apollonian conta çizen bir program veya işlev yazın.

Fonksiyon argümanı ARGV veya STDIN üzerinden giriş yapabilir ve fraktalı ekranda görüntüleyebilir veya istediğiniz bir formatta bir görüntü dosyasına yazabilirsiniz.

Sonuçta ortaya çıkan görüntü rasterleştirilirse, her bir tarafta en az 400 piksel olmalı ve en büyük dairenin etrafında% 20'den daha az dolgu yapılmalıdır. Yarıçapı, en büyük giriş çemberinin 400'ünden az olan dairelere veya pikselden daha küçük olan dairelere (hangisi önce gelirse) ulaştığınızda özyinelemeyi durdurabilirsiniz.

Tam diskleri değil, yalnızca daire anahatlarını çizmelisiniz, ancak arka plan ve çizgilerin renkleri sizin seçiminizdir. Ana hatlar, dış daireler çapının 200'ünden daha geniş olmamalıdır.

Bu kod golf, yani en kısa cevap (bayt cinsinden) kazanır.

Örnek Girişler

İşte öngörülen giriş formatına dönüştürülen Vikipedi makalesinden tümleşik contalar:

[[-1, 0, 0], [2, 1, 0], [2, -1, 0], [3, 0, 2]]
[[-2, 0, 0], [3, 1/2, 0], [6, -2, 0], [7, -3/2, 2]]
[[-3, 0, 0], [4, 1/3, 0], [12, -3, 0], [13, -8/3, 2]]
[[-3, 0, 0], [5, 2/3, 0], [8, -4/3, -1], [8, -4/3, 1]]
[[-4, 0, 0], [5, 1/4, 0], [20, -4, 0], [21, -15/4, 2]]
[[-4, 0, 0], [8, 1, 0], [9, -3/4, -1], [9, -3/4, 1]]
[[-5, 0, 0], [6, 1/5, 0], [30, -5, 0], [31, -24/5, 2]]
[[-5, 0, 0], [7, 2/5, 0], [18, -12/5, -1], [18, -12/5, 1]]
[[-6, 0, 0], [7, 1/6, 0], [42, -6, 0], [43, -35/6, 2]]
[[-6, 0, 0], [10, 2/3, 0], [15, -3/2, 0], [19, -5/6, 2]]
[[-6, 0, 0], [11, 5/6, 0], [14, -16/15, -4/5], [15, -9/10, 6/5]]
[[-7, 0, 0], [8, 1/7, 0], [56, -7, 0], [57, -48/7, 2]]
[[-7, 0, 0], [9, 2/7, 0], [32, -24/7, -1], [32, -24/7, 1]]
[[-7, 0, 0], [12, 5/7, 0], [17, -48/35, -2/5], [20, -33/35, 8/5]]
[[-8, 0, 0], [9, 1/8, 0], [72, -8, 0], [73, -63/8, 2]]
[[-8, 0, 0], [12, 1/2, 0], [25, -15/8, -1], [25, -15/8, 1]]
[[-8, 0, 0], [13, 5/8, 0], [21, -63/40, -2/5], [24, -6/5, 8/5]]
[[-9, 0, 0], [10, 1/9, 0], [90, -9, 0], [91, -80/9, 2]]
[[-9, 0, 0], [11, 2/9, 0], [50, -40/9, -1], [50, -40/9, 1]]
[[-9, 0, 0], [14, 5/9, 0], [26, -77/45, -4/5], [27, -8/5, 6/5]]
[[-9, 0, 0], [18, 1, 0], [19, -8/9, -2/3], [22, -5/9, 4/3]]
[[-10, 0, 0], [11, 1/10, 0], [110, -10, 0], [111, -99/10, 2]]
[[-10, 0, 0], [14, 2/5, 0], [35, -5/2, 0], [39, -21/10, 2]]
[[-10, 0, 0], [18, 4/5, 0], [23, -6/5, -1/2], [27, -4/5, 3/2]]
[[-11, 0, 0], [12, 1/11, 0], [132, -11, 0], [133, -120/11, 2]]
[[-11, 0, 0], [13, 2/11, 0], [72, -60/11, -1], [72, -60/11, 1]]
[[-11, 0, 0], [16, 5/11, 0], [36, -117/55, -4/5], [37, -112/55, 6/5]]
[[-11, 0, 0], [21, 10/11, 0], [24, -56/55, -3/5], [28, -36/55, 7/5]]
[[-12, 0, 0], [13, 1/12, 0], [156, -12, 0], [157, -143/12, 2]]
[[-12, 0, 0], [16, 1/3, 0], [49, -35/12, -1], [49, -35/12, 1]]
[[-12, 0, 0], [17, 5/12, 0], [41, -143/60, -2/5], [44, -32/15, 8/5]]
[[-12, 0, 0], [21, 3/4, 0], [28, -4/3, 0], [37, -7/12, 2]]
[[-12, 0, 0], [21, 3/4, 0], [29, -5/4, -2/3], [32, -1, 4/3]]
[[-12, 0, 0], [25, 13/12, 0], [25, -119/156, -10/13], [28, -20/39, 16/13]]
[[-13, 0, 0], [14, 1/13, 0], [182, -13, 0], [183, -168/13, 2]]
[[-13, 0, 0], [15, 2/13, 0], [98, -84/13, -1], [98, -84/13, 1]]
[[-13, 0, 0], [18, 5/13, 0], [47, -168/65, -2/5], [50, -153/65, 8/5]]
[[-13, 0, 0], [23, 10/13, 0], [30, -84/65, -1/5], [38, -44/65, 9/5]]
[[-14, 0, 0], [15, 1/14, 0], [210, -14, 0], [211, -195/14, 2]]
[[-14, 0, 0], [18, 2/7, 0], [63, -7/2, 0], [67, -45/14, 2]]
[[-14, 0, 0], [19, 5/14, 0], [54, -96/35, -4/5], [55, -187/70, 6/5]]
[[-14, 0, 0], [22, 4/7, 0], [39, -12/7, -1/2], [43, -10/7, 3/2]]
[[-14, 0, 0], [27, 13/14, 0], [31, -171/182, -10/13], [34, -66/91, 16/13]]
[[-15, 0, 0], [16, 1/15, 0], [240, -15, 0], [241, -224/15, 2]]
[[-15, 0, 0], [17, 2/15, 0], [128, -112/15, -1], [128, -112/15, 1]]
[[-15, 0, 0], [24, 3/5, 0], [40, -5/3, 0], [49, -16/15, 2]]
[[-15, 0, 0], [24, 3/5, 0], [41, -8/5, -2/3], [44, -7/5, 4/3]]
[[-15, 0, 0], [28, 13/15, 0], [33, -72/65, -6/13], [40, -25/39, 20/13]]
[[-15, 0, 0], [32, 17/15, 0], [32, -161/255, -16/17], [33, -48/85, 18/17]]

Örnek resminiz ilk operasyondan sonra yalnızca "iç" apollon çevrelerini içeriyor gibi görünüyor.
Sparr

@Sparr Ne demek istediğinden emin değilim. İlk operasyondan sonra iki Apollonian çemberinden biri zaten var (mevcut yineleme için seçmediğiniz orijinal ebeveyn çemberi) ve sadece diğer çözümü arıyorsunuz.
Martin Ender

Boşver, haklısın, yanlış okuyordum.
Sparr

Yanıtlar:


12

GolfScript (289 bayt vektör / 237 bayt raster)

289 baytta ve makul bir sürede çalıştırma:

'/'/n*','/']['*0,`1/*~1.$[]*(~-400*:&;{1+1=*}/:D;{{1+2<~D@*\/}%}%'<svg><g fill="none" stroke="red">'puts.{[[~@:b[D&*\abs]{@&*[b]+}2*]{'.0/'*'"#{
}"'n/*~}%'<circle r="
" cx="
" cy="
" />'n/\]zip puts}:|/[{.([.;]+}3*]{(:?zip{)\~++2*\-}%:c.|0=D&*<{?);[c]+[{([.;]+.}3*;]+}*.}do'</g></svg>'

Bu stdin üzerinde girdi alır ve stdout'a bir SVG dosyası oluşturur. Ne yazık ki, çevrimiçi bir demo için biraz uzun sürüyor, ancak erken bırakan ince bir sürüm size bir fikir verebilir.

Giriş Verilen çıkışı (Inkscape ile PNG dönüştürülür) olan[[-2, 0, 0], [3, 1/2, 0], [6, -2, 0], [7, -3/2, 2]]

Conta 2/3/6/7


237 baytta ve çok uzun sürüyor (bir bit siyah ve beyaz olmasına rağmen, yukarıdakilere benzer çıktılar üretmenin bir hafta kadar alacağını tahmin ediyorum):

'/'/n*','/']['*0,`1/*~1.$[]*(~-400*:&;{1+1=*}/:D;{{1+2<~D@*\/}%}%.[{.([.;]+}3*]{(:?[zip{)\~++2*\-}%:c]@+\0c=D&*<{?);[c]+[{([.;]+.}3*;]+}*.}do;:C;'P1 ''801 '2*.~:B*,{:P;C{:?[0=2/.D&*-.*\D&*+.*]{2,{P{B/}2$*B%400-?0=*\)?=&*-.*}/+<},,1=},!}/

Çıktı, yeni satırlar olmadan NetPBM formatıdır, bu nedenle GIMP yine de yükleyebilse de, kesinlikle teknik özelliklere uymuyor. Sıkı bir uyumluluk gerekiyorsa, sonuncudan nsonra bir tane ekleyin !.

Rasterleştirme, her pikseli her daireye karşı test ederek, bu nedenle geçen zaman, daire sayısının piksel sayısında, oldukça fazla doğrusaldır. Her şeyi 10 kat küçülterek,

'/'/n*','/']['*0,`1/*~1.$[]*(~-40*:&;{1+1=*}/:D;{{1+2<~D@*\/}%}%.[{.([.;]+}3*]{(:?[zip{)\~++2*\-}%:c]@+\0c=D&*<{?);[c]+[{([.;]+.}3*;]+}*.}do;:C;'P1 ''81 '2*.~:B*,{:P;C{:?[0=2/.D&*-.*\D&*+.*]{2,{P{B/}2$*B%40-?0=*\)?=&*-.*}/+<},,1=},!}/

10 dakika içinde koşacak ve üretecek

81x81 görüntü

(GIMP ile PNG'ye dönüştürülmüş). 36 saat göz önüne alındığında 401x401

401x401 görüntü


3
Golfscript ile grafik çıktı yapabileceğinizi hiç düşünmezdim ...
Beta Decay

12

JavaScript ( 418 410 bayt)

İşlev olarak uygulandı:

function A(s){P='<svg><g fill=none stroke=red transform=translate(400,400)>';Q=[];s=eval(s);S=-400*s[0][0];function d(c){P+='<circle r='+Math.abs(p=S/c[0])+' cx='+p*c[1]+' cy='+p*c[2]+' />'}for(c=4;c--;d(s[0]),s.push(s.shift()))Q.push(s.slice());for(;s=Q.shift();d(c)){c=[];for(i=4;i--;)c[i]=2*(s[0][i]+s[1][i]+s[2][i])-s[3][i];for(i=6;c[0]<S&&i;)Q.push([s[i--%3],s[i--%3],c,s[i%3]])}document.body.innerHTML=P}

Çevrimiçi demo (not: SVG spesifikasyonunun örtülü boyutlandırma ile ilgili gereksinimlerini yerine getirmeyen tarayıcılarda çalışmaz, bu nedenle bu hatanın etrafında çalışan biraz daha uzun bir sürüm sunarım; Her ne kadar Inkscape alıntı özellikleri üzerinde biraz daha katı olmasına rağmen).

8 bayt kullanılarak kaydedilebileceğini unutmayın document.write, ancak bu jsFiddle'ı ciddi şekilde borçluyor.


1
Fonksiyonu ES6 ile tanımlayarak ve örneğin S/c[0]bir değişkende saklayarak ve daha sonra Math.absüçlü bir operatörle vb. Kurtulmakla muhtemelen daha fazla tasarruf edebilirsiniz .
Ingo Bürk

@ IngoBürk, eğer ES6 güzergahına gidecektim, o zaman bunun yerine CoffeeScript'e yazardım.
Peter Taylor

c99.nl ana bilgisayarını kullanın. Document.write komutunu sağlar.
xem

2
Buna bir cevap görmek güzel :)
MickyT

@ IngoBürk'ün geçici bir değişken önerisi ile güncellendi. Ortadan kaldırılması Math.absaslında bir karaktere mal olur.
Peter Taylor

6

Mathematica 289 karakter

Bilinear sistemi http://arxiv.org/pdf/math/0101066v1.pdf Teorem 2.2'ye (yüksek verimsiz) göre çözerek .

Boşluklar gerekmiyor, hala golf oynuyor:

w = {k, x, y};
d = IdentityMatrix;
j = Join;
p_~f~h_ := If[#[[-1, 1]] < 6! h,
    q = 2 d@4 - 1;
    m = #~j~{w};
    r = Complement[w /. NSolve[ And @@ j @@ 
                        MapThread[Equal, {Thread@m.q.m, 4 d@3 {0, 1, 1}}, 2], w], a];
    If[r != {},
     a~AppendTo~# & @@ r;
     Function[x, x~j~{#}~f~h & /@ r]@#]] & /@ p~Subsets~{3}; 
Graphics[Circle @@@ ({{##2}, 1}/# & @@@ (f[a = #, -Tr@#]; a))] &

Girdili küçültülmüş boyutlu bir animasyon {{-13, 0, 0}, {23, 10/13, 0}, {30, -84/65, -1/5}, {38, -44/65, 9/5}}

görüntü tanımını buraya girin


Giriş nasıl yapılır?
Martin Ender

@ MartinBüttner fonksiyon argümanı @{{-1, 0, 0}, {2, 1, 0}, {2, -1, 0}, {3, 0, 2}}olarak, son satıra ekleyerek
Dr. belisarius

MartinBüttner @ bunu ilk denemek test etmek gidiyoruz 50/hyerine 400/h. Sonucu daha hızlı alacaksın. ayrıca, Dynamic@Length@aişlevi yerine getirmeden önce girerek ilerlemeyi izleyebilirsiniz
Dr. belisarius

Instructions for testing this answer (with a reduced number of circles) without Mathematica installed: 1) Bunu pastebin'den indirin ve * .CDF olarak kaydedin. 2) Ücretsiz CDF ortamını Wolfram Research'ten indirin ve kurun (küçük bir dosya değil). Keyfini çıkarın. Bana işe yarayıp yaramadığını söyle - Not: Hesaplamalar yavaş, grafiklerin çıkmasını bekleyin.
Doktor Belisarius

"Çok verimsiz" yorumunun anlamı nedir? Görünüşe göre çemberlerin çoğunu en az iki kere çiziyor musunuz? Bence karmaşık Descartes yaklaşımı kendiliğinden olabildiğince verimli.
Peter Taylor

4

Akçaağaç (960 bayt)

Apollonian Contayı üretmek için Descartes Theorem'i kullandım ve daha sonra Maple'nin komplo sistemini kullanarak çizdim. Zamanım varsa, bunu daha fazla golf oynamak ve Python olarak değiştirmek istiyorum (Akçaağaç kesinlikle fraktallar için en iyisi değildir). Kodumu çalıştırmak istiyorsanız, ücretsiz bir Maple oyuncusuna bir link .

X,Y,Z,S,N:=abs,evalf,member,sqrt,numelems;
f:=proc(J)
    L:=map((x)->[x[1],(x[2]+x[3]*I)/x[1]+50*(1+I)/X(J[1][2])],J);
    R:=Vector([L]);
    T,r:=X(L[1][3]),L[1][4];
    A(L[1][5],L[2][6],L[3][7],L[1][8],L[2][9],L[3][10],R,T,r);
    A(L[1][11],L[2][12],L[4][13],L[1][14],L[2][15],L[4][16],R,T,r);
    A(L[1][17],L[3][18],L[4][19],L[1][20],L[3][21],L[4][22],R,T,r);
    A(L[2][23],L[3][24],L[4][25],L[2][26],L[3][27],L[4][28],R,T,r);
    plots[display](seq(plottools[circle]([Re(R[i][29]),Im(R[i][30])],X(1/R[i][31])),i=1..N(R))):
end proc:
A:=proc(a,b,c,i,j,k,R,E,F)
    K:=i+k+j+2*S(i*k+i*j+k*j);
    if K>400*E then
    return;
    end if;
    C:=(a*i+c*k+b*j+2*S(a*c*i*k+b*c*j*k+a*b*i*j))/K;
    C2:=(a*i+c*k+b*j-2*S(a*c*i*k+b*c*j*k+a*b*i*j))/K;
    if Y(X(C-F))<1/E and not Z([K,C],R) then
    R(N(R)+1):=[K,C];
    A(a,b,C,i,j,K,R,E,F);
    A(a,c,C,i,k,K,R,E,F);
    A(b,c,C,j,k,K,R,E,F);
    end if:    
    if Y(X(C2-F))<1/E and not Z([K,C2],R) then
    R(N(R)+1):=[K,C2];
    A(a,b,C2,i,j,K,R,E,F);
    A(a,c,C2,i,k,K,R,E,F);
    A(b,c,C2,j,k,K,R,E,F);
    end if: 
end proc:

Bazı örnek contalar

f([[-1, 0, 0], [2, 1, 0], [2, -1, 0], [3, 0, 2]]);

görüntü tanımını buraya girin

f([[-9, 0, 0], [14, 5/9, 0], [26, -77/45, -4/5], [27, -8/5, 6/5]]);

görüntü tanımını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.