Seekor Anjing dengan Rantai

31

Saya melihat keluar dari jendela loteng ke halaman tetangga saya. Mereka memiliki seekor anjing yang dirantai ke sebuah pos di tengah halaman. Anjing berlari di sekitar halaman tetapi selalu berada di ujung rantai, sehingga akhirnya meninggalkan jejak di tanah. Biasanya lintasan ini akan melingkar sempurna, tetapi tetangga saya memiliki beberapa tiang lain di halaman mereka yang rantai anjingnya tertangkap. Setiap kali rantai anjing mengenai kutub, anjing mulai memutar tentang kutub baru dengan panjang rantai yang tersisa sejauh jari-jarinya. Karena kutub, anjing dan rantai semuanya memiliki lebar nol (tetangga saya adalah ahli matematika) rantai dapat berputar di sekitar kutub tanpa batas tanpa jari-jari lingkaran memendek. Anjing juga dapat melewati rantai (bukan kerahnya) jika rantai ada di jalurnya. Setelah mengamati keanehan ini untuk sementara waktu saya memutuskan saya akan menulis beberapa kode untuk mensimulasikan anjing tetangga saya. Kode akan mengambil lokasi kutub tengah, tempat anjing itu dirantai, lokasi kutub lain di halaman tetangga saya, panjang rantai, dan lokasi awal anjing, dan akan menampilkan diagram yang menunjukkan jalan di mana anjing telah memakai rumput. Anda dapat mengasumsikan bahwa kombinasi apa pun dari berikut ini konstan (dan karenanya tidak menjadikannya sebagai input):

  • Lokasi tiang tempat anjing itu dirantai

  • Panjang rantai

  • Lokasi awal anjing

Matahari terbit, jadi ruang di lantai loteng saya yang diterangi oleh jendela menyusut, memberi saya semakin sedikit ruang untuk menulis kode saya. Silakan coba untuk meminimalkan jumlah byte kode Anda sehingga saya memiliki ruang untuk menyusunnya di lantai loteng saya.

Uji kasus

Di sini saya berasumsi bahwa anjing mulai 3 unit selatan dari yang tiang itu dirantai (titik merah), terletak di 0,0. Saya telah menunjukkan di mana kutub dengan titik-titik untuk kejelasan, Anda tidak perlu memasukkannya dalam output Anda.

Poles at 1,2 -1,2

Tes 1

Poles at 0,.5

Tes 2

Poles at 0,1 1,1 -2,1 -1,-.5

Tes 3

Poles at 0,1 1,1

Tes 4

Wisaya Gandum
sumber
Untuk apa outputnya {0,-.5}?
Kritixi Lithos
@ KritixiLithos Ini adalah output {0,.5}membalik secara vertikal tanpa lingkaran terbesar. Anjing itu pada dasarnya mulai tertangkap di tiang kedua.
Wheat Wizard
Sebagai hasil dari masalah floating-point, program saya menggambar lingkaran di sekitar (1,1) di testcase terakhir (panjang string adalah 99,99999). Apakah ini baik?
Kritixi Lithos
Anjing berjalan searah jarum jam dan berlawanan arah jarum jam, tetapi dari titik tetap?
user202729
3
"Matahari terbit ruang di lantai loteng saya diterangi oleh jendela menyusut memberi saya semakin sedikit ruang untuk menulis kode saya" +1 hanya untuk ini
Leo

Jawaban:

11

Python 3 menggunakan matplotlib, 457 byte

from cmath import*
from matplotlib import pyplot as g,patches as i
def x(p):
 p+=[0];d=180/pi;a=2;h=g.gca();h.set_xlim(-5,5);h.set_ylim(-5,5)
 while a:
  a-=1;c=0;y=3;z=-pi/2
  while 1:
   s=[n for n in p if abs(n-c)<=y and n!=c]
   if not s:h.add_patch(i.Arc((c.real,c.imag),y*2,y*2));break
   n=[max,min][a](s,key=lambda n:(z-phase(n-c))%(2*pi));l,r=polar(n-c);h.add_patch(i.Arc((c.real,c.imag),y*2,y*2,[z,r][a]*d,0,[r-z,z-r][a]*d));y-=l;z=r;c=n
 g.show()

Karena tetangga Anda adalah ahli matematika, saya berasumsi bahwa taman tetangga Anda menempati domain kompleks dan karenanya koordinat objek di taman itu adalah bilangan kompleks. Untuk menggunakan fungsi ini, Anda harus memberikannya daftar bilangan kompleks yang menandakan lokasi kutub di taman tetangga Anda. Representasi sistem koordinat default telah dipilih, di sebelah kanan adalah bilangan real positif dan ke atas adalah bilangan imajiner positif. Ini berarti contohnya menjadi:

x([2j+1,2j-1])
x([.5j])
x([1j,1+1j,-2+1j,-1-.5j])
x([1j,1+1j])

Selanjutnya, program mengasumsikan hal-hal berikut: tali terikat ke titik 0, tali adalah 3 unit, dan area plot 10 oleh 10 berpusat di sekitar 0. Untuk parameter ini, hasilnya cocok persis dengan contoh, dan beginilah hasilnya (untuk contoh terakhir):

x ([1j, 1 + 1j])

Algoritma ini cukup sederhana, hanya membutuhkan satu syarat untuk membedakan searah jarum jam dan pencarian berlawanan arah jarum jam. Keadaan algoritma ditentukan oleh titik rotasi saat ini dan orientasi / panjang tali yang tersisa ketika mengenai titik rotasi saat ini. Ia bekerja sebagai berikut:

  • Saring titik keluar dari set tabrakan yang jauh dari titik rotasi saat ini daripada panjang tali penuntun yang tersisa, serta titik rotasi saat ini.
  • Jika set ini kosong, gambarkan lingkaran dengan jari-jari panjang sabuk yang tersisa di sekitar titik ini saat ujung lengan ini telah tercapai.
  • Tentukan titik di mana perbedaan fase antara vektor perbedaan dan orientasi tali adalah minimal / maksimal. Ini adalah titik berikutnya yang akan dipukul oleh leash searah jarum jam / berlawanan arah jarum jam.
  • Gambarlah busur berdasarkan vektor-vektor ini, ambil panjang tali penuntun, kurangi besarnya jarak dan atur orientasi tali penuntun ke orientasi vektor perbedaan. Perbarui titik rotasi dan lanjutkan dari awal.

Algoritma ini kemudian dilakukan pertama dalam arah searah jarum jam, setelah itu negara diatur ulang dan dijalankan dalam arah berlawanan arah jarum jam. Kesederhanaan algoritma berarti bahwa sekitar setengah dari program bytecount dihabiskan untuk fungsi menggambar. Jika rutinitas gambar dilucuti, itu akan menghapus 218 byte dari ukuran program.

Berikut ini adalah versi yang tidak dikenali yang juga berisi kode debug, yang juga menampilkan poin dan tabrakan tali:

from cmath import pi, rect, polar, phase
from matplotlib import pyplot, patches
def x_ungolfed(points):
    degrees = 180/pi # conversions

    # add the center point to the collision points
    points.append(0.0)

    # configure plot area
    axes=pyplot.gca()
    axes.set_xlim(-5,5)
    axes.set_ylim(-5,5)

    # plot the points
    x, y =zip(*((p.real, p.imag) for p in points))
    axes.scatter(x, y, 50, "b")

    # first iteration is clockwise, second counterclockwise
    clockwise = 2
    while clockwise:
        clockwise -= 1

        # initial conditions
        center = 0 + 0j;
        leash_size = 3
        leash_angle = -pi / 2

        # initial leash plot
        leash_start = rect(leash_size, leash_angle)
        axes.plot([center.real, leash_start.real], [center.imag, leash_start.imag], "r")

        # search loop
        while 1:
            # find possible collission candidates
            candidates = [n for n in points if abs(n - center) <= leash_size and n != center]
            # if we reached the end, draw a circle
            if not candidates:
                axes.add_patch(patches.Arc(
                    (center.real, center.imag), 
                    leash_size*2, leash_size*2
                ))
                break
            # find the actual collision by comparing the phase difference of the leash angle vs the difference between the candidate and the current node
            new = (min if clockwise else max)(candidates, key=lambda n: (leash_angle - phase(n - center)) % (2 * pi))

            # convert the difference to polar coordinates
            distance, new_angle = polar(new - center)
            # draw the arc
            if clockwise:
                axes.add_patch(patches.Arc(
                    (center.real, center.imag),
                    leash_size * 2, leash_size * 2,
                    new_angle * degrees,
                    0,
                    (leash_angle-new_angle) * degrees
                ))
            else:
                axes.add_patch(patches.Arc(
                    (center.real, center.imag),
                    leash_size * 2, leash_size * 2,
                    leash_angle * degrees,
                    0,
                    (new_angle - leash_angle) * degrees
                ))
            # draw intermediate lines
            edge = rect(leash_size, new_angle) + center
            axes.plot([center.real, edge.real], [center.imag, edge.imag], "g")

            # perform updates: decrease remaining leash size, set new leash angle, move rotation center to the collision
            leash_size -= distance
            leash_angle = new_angle
            center = new

    # show the graph
    pyplot.show()

Output yang dihasilkannya terlihat seperti ini:

Sama seperti gambar sebelumnya tetapi lebih banyak garis

Nama Pengguna yang Disensor
sumber
Beri +1 untuk penjelasan yang sangat bagus dan karena telah bermain golf dengan saya hampir dua kali lipat! <s> ya ampun, aku iri dengan orang-orang builtin itu </s>
Kritixi Lithos
7

Memproses 3, 815 833 835 876 879 byte

Disimpan dua byte berkat @ZacharyT dengan menghapus tanda kurung yang tidak perlu

void settings(){size(600,600);}int i,w,x,n;float l,d,t,a,f,g,m,R,U;float[][]N,T;float[]S,p;void s(float[][]t){N=new float[t.length+1][2];N[0][0]=N[0][1]=i=0;for(float[]q:t)N[++i]=q;translate(w=300,w);noFill();pushMatrix();f(N,0,-w,w,1,0);popMatrix();f(N,0,-w,w,0,0);}float p(float a,float b){for(a+=PI*4;a>b;)a-=PI*2;return a;}void f(float[][]P,float x,float y,float L,int c,int I){l=2*PI;d=i=0;S=null;for(;i<P.length;i++){float[]p=P[i];g=atan2(y,x);m=atan2(p[1],p[0]);if(p(f=(c*2-1)*(g-m),0)<l&(t=dist(0,0,p[0],p[1]))<=L&I!=i){l=p(f,0);S=new float[]{g,m};d=t;n=i;}}if(S==null)ellipse(0,0,2*(L-d),2*(L-d));else{arc(0,0,L*2,L*2,p(S[c],S[1-c]),S[1-c]);R=cos(a=S[1]);U=sin(a);translate(d*R,d*U);T=new float[P.length][2];for(int i=0;i<T.length;T[i][1]=P[i][1]-d*U,i++)T[i][0]=P[i][0]-d*R;f(T,(L-d)*R,(L-d)*U,L-d,c,n);}}

Jalankan program ini seperti ini:

void setup() {
    s(new float[][]{{0,100},{100,100},{-200,100},{-100,-50}});
}

(fungsi smengambil a float[][]). Ini pada dasarnya adalah testcase # 3, tetapi dikalikan dengan 100 agar sesuai dengan jendela.

Beberapa hal yang perlu diperhatikan:

  • program TIDAK menggambar kutub
  • gambar tampak terbalik karena dalam sistem koordinat Processing, sumbu y positif turun
  • karena Memproses menggunakan float, perhitungannya tidak terlalu akurat, jadi Anda mungkin melihat ini dalam gambar. Saya telah bertanya kepada OP apakah ini kesalahan titik-mengambang.
  • ukuran jendela adalah 600 piksel kali 600 piksel
  • input koordinat yang sangat kecil akan merusak program karena stack pushMatrix()dan popMatrix()beroperasi hanya dapat menampung 32 matriks.
  • anjing mulai pada (0, -300) dan rantai dimulai pada 300 piksel
  • gambar di bawah ini telah diperkecil untuk kenyamanan

Contoh output untuk testcase di atas.

masukkan deskripsi gambar di sini

Jika Anda ingin melihat output yang sudah diprogram, tambahkan baris ini tepat setelah translate(w,w);fungsi in s.

background(-1);scale(1,-1);fill(255,0,0);ellipse(0,0,25,25);fill(0);for(float[]q:N)ellipse(q[0],q[1],25,25);

Dan ini memberi kita hasil ini:

lingkaran

Tanpa f()penjelasan dan penjelasan

(mengandung kode debug juga)

void f(float[][]points, float x, float y, float len, int c, int pindex) {
    print(asd+++")");
    float closest = 2*PI;
    float d=0,t;
    float[]stuff = null;
    int index = 0;
    for(int i=0;i<points.length;i++) {
        if(pindex != i) {
            float[]p = points[i];
            float originAngle = atan2(y, x);
            float tempAngle = atan2(p[1], p[0]);
            //println(x,y,p[0],p[1]);
            float diff = c<1?tempAngle-originAngle:originAngle-tempAngle;
            println("@\t"+i+"; x=\t"+x+"; y=\t"+y+"; tx=\t"+p[0]+"; ty=\t",p[1], diff, originAngle, tempAngle);
            if(p(diff) < closest && (t=dist(0,0,p[0],p[1])) < len) {
                println("+1");
                closest = p(diff);
                stuff = new float[]{originAngle, tempAngle};
                d=t;
                index = i;
            }
        }
    }
    if(stuff == null) {
        ellipse(0,0,2*(len-d),2*(len-d));
        println("mayday");
    } else {
        println("d angles",d,p(stuff[c],stuff[1-c],c), stuff[1-c]);
        //println(points[0]);
        arc(0, 0, len*2, len*2, p(stuff[c],stuff[1-c],c), stuff[1-c]);
        float angle = stuff[1];
        translate(d*cos(angle), d*sin(angle));
        println("Translated", d*cos(angle), d*sin(angle));
        println("angle",angle);
        float[][]temp=new float[points.length][2];
        for(int i=0;i<temp.length;i++){
            temp[i][0]=points[i][0]-d*cos(angle);
            temp[i][1]=points[i][1]-d*sin(angle);
            println(temp[i]);
        }
        println(d*sin(angle));
        pushMatrix();
        println();
        f(temp, (len-d)*cos(angle), (len-d)*sin(angle), (len-d), c, index);
        popMatrix();
        //f(temp, (len-d)*cos(angle), (len-d)*sin(angle), (len-d), 0, index);
    }
}

Singkatnya, program mengirim dua "pencari", satu berjalan berlawanan arah jarum jam dan yang lainnya searah jarum jam. Masing-masing pencari menemukan kutub terdekat dan menggambar busur ke sana jika rantai cukup panjang, jika tidak, ia menggambar lingkaran. Setelah menggambar busur, ia mengirimkan pencari lain ke kutub itu dan proses berlanjut. f()berisi proses setiap pencari. Penjelasan yang lebih rinci akan datang segera setelah saya bermain golf ini lagi.

Kritixi Lithos
sumber
Apakah Anda membutuhkan orangtua di masa lalu L-d?
Zacharý
@ Zakary Saya tidak tahu bagaimana saya melewatkannya, terima kasih.
Kritixi Lithos
5

LOGO, 305 298 297 293 byte

Coba kodenya di FMSLogo.

Tentukan fungsi draw(golfed as d) yang, diberikan input sebagai daftar koordinat kutub (misalnya draw [[0 100] [100 100] [-200 100] [-100 -50][0 0]], akan menggambar pada layar hasilnya.

Persyaratan:

  1. Panjang tali awal = 300 piksel. (karena 3 piksel terlalu kecil)
  2. [0 0]harus dimasukkan dalam daftar kutub. Jika kode debug (draw pole) dihidupkan, maka [0 0]harus menjadi item terakhir.
  3. Anjing mulai di koordinat x=0, y=-300(seperti dalam deskripsi masalah)

Kemungkinan pengoptimalan:

  1. -1 byte jika kasus luar biasa (anjing lari ke tiang) tidak diperlukan untuk matematis benar dengan mengganti >=dengan>

Kode golf:

to f
op(if ?=pos 360 modulo :m*(180+heading-towards ?)360)
end
to x :m[:1 300]
home
forever[make 2 filter[:1>=u ?](sort :p[(u ?)<u ?2])invoke[pd
arc -:m*f :1
pu
if 360=f[stop]make 1 :1-u ?
lt :m*f
setpos ?]reduce[if f<invoke[f]?2[?][?2]]:2]
end
to d :p
copydef "u "distance
foreach[1 -1]"x
end

Kode tidak digabung ( ;memulai komentar sebaris (digunakan untuk penjelasan), dan :memulai nama variabel):

to f
    op ifelse ? = pos 360 modulo :m*(180 + heading - towards ?) 360
end

to x
    home
    foreach :poles [pu setpos ? pd circle 5] ; debug code
    make "length 300 ; initial length of rope
    forever [
        make "tmp filter [:length >= distance ?] ; floating point error makes > and >= similar,  ~
            ; but >= is correct mathematically ~
            (sort :poles [(distance ?) < distance ?2])
         ; the last = longest element will be rotated
        invoke [
            pd
            arc -:m*f :length
            pu
            if 360=f [stop]
            make "length :length - distance ?
            lt :m*f
            setpos ?
        ] reduce [
            if f < invoke[f]?2 [?] [?2]
        ] :tmp ; apply to use ? instead of :pos
    ]
end

to draw :poles
    foreach [1 -1] [[m]
        x
    ]
end
pengguna202729
sumber
1

Python 2 + PIL, 310 byte

from PIL import Image
from cmath import*
I,_,X,P=Image.new('1',(300,300),'white'),abs,polar,input()
def r(s):
 a,C,l=0,0,3
 while _(a)<99:
  c=C+l*exp(1j*a);I.load()[c.real*30+150,150-c.imag*30]=0
  for p in P+[0]:
   N,E=X(C-c);n,e=X(C-p)
   if n<=N and _(E-e)<.1:l-=_(p-C);C=p
  a+=s
r(.01)
r(-.01)
I.show()

Script membaca daftar poin dari stdin sebagai daftar bilangan kompleks.

printf '[complex(0,0.5)]' | python2 snippet.py

masukkan deskripsi gambar di sini

printf '[complex(0,1), complex(1,1)]' | python2 snippet.py

masukkan deskripsi gambar di sini

pelaku diet
sumber