สุนัขในเครือ


31

ฉันมองออกไปนอกหน้าต่างห้องใต้หลังคาของฉันในบ้านของเพื่อนบ้าน พวกเขามีสุนัขถูกล่ามโซ่ไว้ที่เสากลางลาน สุนัขวิ่งไปรอบ ๆ สนาม แต่มักจะอยู่ที่ปลายโซ่ของมันดังนั้นมันจึงทิ้งรอยไว้ในดิน โดยปกติเพลงนี้จะเป็นวงกลมอย่างสมบูรณ์แบบ แต่เพื่อนบ้านของฉันมีเสาอื่น ๆ ในสนามของพวกเขาที่โซ่สุนัขถูกจับได้ ทุกครั้งที่โซ่สุนัขกระทบกับเสาสุนัขจะเริ่มหมุนรอบเสาใหม่โดยที่ความยาวของห่วงโซ่เหลือเท่ารัศมี ตั้งแต่เสาสุนัขและลูกโซ่ทุกคนมีความกว้างเป็นศูนย์ (เพื่อนบ้านของฉันเป็นนักคณิตศาสตร์) ลูกโซ่สามารถหมุนรอบเสาไปเรื่อย ๆ โดยไม่มีรัศมีของวงกลมที่สั้นลง สุนัขยังสามารถผ่านห่วงโซ่ (ไม่ใช่ปลอกคอ) ถ้าโซ่อยู่ในเส้นทาง หลังจากที่สังเกตสิ่งประหลาดนี้มาพักหนึ่งฉันก็ตัดสินใจว่าฉันจะเขียนรหัสเพื่อจำลองสุนัขเพื่อนบ้านของฉัน รหัสจะใช้สถานที่ของเสากลางซึ่งสุนัขถูกล่ามโซ่สถานที่ของเสาอื่น ๆ ในบ้านเพื่อนบ้านของฉันความยาวของห่วงโซ่และที่ตั้งเริ่มต้นของสุนัขและจะส่งออกแผนภาพแสดง เส้นทางที่สุนัขเสื่อมหญ้า คุณอาจสันนิษฐานว่าชุดค่าผสมใด ๆ ต่อไปนี้เป็นค่าคงที่ (และไม่ถือเป็นอินพุต):

  • ที่ตั้งของเสาที่สุนัขถูกล่ามโซ่

  • ความยาวของโซ่

  • ตำแหน่งเริ่มต้นของสุนัข

ดวงอาทิตย์กำลังสูงขึ้นดังนั้นพื้นที่บนพื้นห้องใต้หลังคาของฉันที่ส่องสว่างทางหน้าต่างลดลงทำให้ฉันมีพื้นที่น้อยลงในการเขียนโค้ดของฉัน โปรดพยายามลดจำนวนไบต์ของรหัสของคุณเพื่อให้ฉันมีพื้นที่ว่างที่จะร่างมันบนพื้นห้องใต้หลังคาของฉัน

กรณีทดสอบ

ที่นี่ผมคิดว่าสุนัขเริ่มต้น 3 หน่วยใต้จากที่เสามันจะถูกล่ามโซ่ (จุดสีแดง) 0,0ตั้งอยู่ที่ ฉันได้ระบุว่าเสาอยู่ที่จุดใดเพื่อความชัดเจนคุณไม่จำเป็นต้องรวมมันไว้ในเอาต์พุตของคุณ

Poles at 1,2 -1,2

ทดสอบ 1

Poles at 0,.5

ทดสอบ 2

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

ทดสอบ 3

Poles at 0,1 1,1

ทดสอบ 4


เอาท์พุท{0,-.5}คืออะไร?
Kritixi Lithos

@KritixiLithos เอาท์พุทของมัน{0,.5}พลิกในแนวตั้งโดยไม่ต้องวงกลมที่ใหญ่ที่สุด โดยพื้นฐานแล้วสุนัขจะเริ่มติดที่เสาที่สอง
ข้าวสาลีตัวช่วยสร้าง

เป็นผลมาจากปัญหาจุดลอยตัวโปรแกรมของฉันวาดวงกลมรอบ (1,1) ใน testcase ล่าสุด (ความยาวสตริงคือ 99.99999) ไม่เป็นไร
Kritixi Lithos

สุนัขวิ่งทั้งทวนเข็มนาฬิกาและทวนเข็มนาฬิกา แต่มาจากจุดคงที่หรือไม่
user202729

3
"ดวงอาทิตย์กำลังเพิ่มพื้นที่บนพื้นห้องใต้หลังคาของฉันที่มีแสงสว่างจากหน้าต่างกำลังหดตัวทำให้ฉันมีพื้นที่น้อยลงในการเขียนโค้ดของฉัน" +1 สำหรับสิ่งนี้
Leo

คำตอบ:


11

Python 3 ใช้ matplotlib, 457 ไบต์

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()

เพราะเพื่อนบ้านของคุณเป็นนักคณิตศาสตร์ฉันคิดว่าสวนเพื่อนบ้านของคุณมีโดเมนที่ซับซ้อนและพิกัดของวัตถุในสวนจึงเป็นจำนวนเชิงซ้อน ในการใช้ฟังก์ชั่นนี้คุณควรส่งรายการหมายเลขที่ซับซ้อนที่บ่งบอกถึงตำแหน่งของเสาในสวนเพื่อนบ้านของคุณ การเลือกตัวแทนระบบพิกัดเริ่มต้นได้รับการคัดเลือกโดยที่ด้านขวาเป็นจำนวนจริงบวกและขึ้นไปเป็นจำนวนจินตภาพบวก นี่หมายความว่าตัวอย่างกลายเป็น:

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

นอกจากนี้โปรแกรมจะสมมติสิ่งต่าง ๆ ต่อไปนี้: การผูกติดกับจุด 0, การบังคับใช้คือ 3 หน่วย, และพื้นที่การพล็อตคือ 10 คูณ 10 โดยมีศูนย์กลางอยู่ที่ 0 ศูนย์. สำหรับพารามิเตอร์เหล่านี้, ผลลัพธ์ที่ตรงกับตัวอย่างทั้งหมด, และนี่คือลักษณะที่ปรากฏของผลลัพธ์ (สำหรับตัวอย่างสุดท้าย):

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

อัลกอริทึมนั้นค่อนข้างง่ายเพียงต้องการเงื่อนไขเดียวเพื่อแยกความแตกต่างของทวนเข็มนาฬิกาและทวนเข็มนาฬิกา สถานะของอัลกอริทึมถูกกำหนดโดยจุดหมุนปัจจุบันและความยาวของทิศทาง / ส่วนที่เหลือของสายจูงเมื่อถึงจุดหมุนปัจจุบัน มันทำงานได้ดังต่อไปนี้:

  • กรองจุดออกจากชุดการชนที่อยู่ห่างจากจุดหมุนปัจจุบันมากกว่าความยาวสายจูงที่เหลือรวมถึงจุดหมุนปัจจุบัน
  • หากชุดนี้ว่างเปล่าวาดวงกลมด้วยรัศมีของความยาวสายพานที่เหลืออยู่รอบจุดนี้เมื่อถึงจุดสิ้นสุดของแขนนี้
  • กำหนดจุดที่ความแตกต่างของเฟสระหว่างเวกเตอร์ที่แตกต่างและการวางแนว leash นั้นน้อยที่สุด / สูงสุด นี่คือจุดต่อไปที่การบังคับจะตีตามเข็มนาฬิกา / ทวนเข็มนาฬิกาตามลำดับ
  • วาดส่วนโค้งโดยใช้เวกเตอร์เหล่านี้ใช้ความยาวสายจูงลบขนาดของระยะทางและตั้งค่าทิศทางการบังคับทิศทางของทิศทางเวกเตอร์ที่ต่างกัน อัพเดตจุดหมุนและดำเนินการต่อตั้งแต่ต้น

อัลกอริทึมนี้จะถูกดำเนินการก่อนในทิศทางตามเข็มนาฬิกาหลังจากนั้นสถานะจะถูกรีเซ็ตและถูกดำเนินการในทิศทางทวนเข็มนาฬิกา ความเรียบง่ายของอัลกอริทึมหมายความว่าประมาณครึ่งหนึ่งของโปรแกรมโดยใช้จำนวนเงินในฟังก์ชั่นการวาดภาพ หากรูทีนการวาดถูกดึงออกมามันจะลบ 218 ไบต์ออกจากขนาดโปรแกรม

ต่อไปนี้เป็นรุ่นที่ยังไม่ได้แก้ไขซึ่งมีรหัสการดีบักซึ่งแสดงจุดและการชนกันของสายอักขระด้วย:

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()

ผลลัพธ์ที่ออกมาจะเป็นดังนี้:

เหมือนกับภาพก่อนหน้า แต่มีเส้นมากกว่า


+1 สำหรับคำอธิบายที่ดีมากและทำให้ฉันเล่นกอล์ฟได้มากถึงสองเท่า! <s> เอ้ยฉันอิจฉาตัวอาคารเหล่านั้น </s>
Kritixi Lithos

7

กำลังดำเนินการ 3, 815 833 835 876 879ไบต์

บันทึกสองไบต์ด้วย @ZacharyT โดยลบวงเล็บที่ไม่จำเป็นออก

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

เรียกใช้โปรแกรมเช่นนี้:

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

(ฟังก์ชั่นsใช้เวลาในfloat[][]) นี่คือ testcase # 3 เป็นหลัก แต่คูณด้วย 100 เพื่อให้พอดีกับหน้าต่าง

หลายสิ่งที่ควรทราบ:

  • โปรแกรมไม่ได้วาดเสา
  • ภาพปรากฏพลิกคว่ำเนื่องจากในระบบพิกัดของการประมวลผลแกน y บวกจะลดลง
  • เนื่องจากการประมวลผลใช้ลอยการคำนวณจึงไม่แม่นยำมากดังนั้นคุณอาจเห็นสิ่งนี้ในภาพ ฉันได้ถาม OP ว่าข้อผิดพลาดจุดลอยตัวเหล่านี้มีความสำคัญหรือไม่
  • ขนาดของหน้าต่างคือ 600 พิกเซลคูณ 600 พิกเซล
  • อินพุทที่มีขนาดเล็กมากจะทำให้โปรแกรมไม่ทำงานเนื่องจากสแต็กpushMatrix()และการpopMatrix()ดำเนินการสามารถเก็บ 32 เมทริกซ์ได้
  • สุนัขเริ่มต้นที่ (0, -300) และโซ่เริ่มที่ความยาว 300 พิกเซล
  • รูปภาพด้านล่างนี้ถูกย่อขนาดเพื่อความสะดวก

ตัวอย่างผลลัพธ์สำหรับการทดสอบข้างต้น

ป้อนคำอธิบายรูปภาพที่นี่

หากคุณต้องการที่จะเห็นการส่งออก prettified เพิ่มบรรทัดนี้ได้หลังจากที่ในการทำงานtranslate(w,w);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);

และนี่ทำให้เราได้ผลลัพธ์นี้:

วงกลม

Ungolfed f()และคำอธิบาย

(มีรหัสการแก้ปัญหาเช่นกัน)

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

เมื่อต้องการวางไว้ในไม่ช้าโปรแกรมจะส่ง "ผู้ค้นหา" สองคนหนึ่งคนไปตามเข็มนาฬิกาและอีกคนตามเข็มนาฬิกา ผู้ค้นหาเหล่านี้แต่ละคนค้นหาเสาที่อยู่ใกล้ที่สุดและดึงส่วนโค้งไปหามันถ้าโซ่นั้นยาวพอตัวอื่น ๆ ก็จะวาดวงกลม เมื่อมันดึงส่วนโค้งมันจะส่งผู้ค้นหาอีกคนไปยังเสานั้นและกระบวนการจะดำเนินต่อไป f()มีกระบวนการของผู้สมัครแต่ละคน คำอธิบายที่ละเอียดยิ่งขึ้นจะเกิดขึ้นทันทีที่ฉันตีกอล์ฟให้มากขึ้น


คุณต้องการ parens รอบสุดท้ายL-dหรือไม่?
Zacharý

@ ZacharyT ฉันไม่รู้ว่าฉันทำยังไงขอบคุณ
Kritixi Lithos

5

โลโก้, 305 298 297 293 ไบต์

ลองรหัสใน FMSLogo

กำหนดฟังก์ชั่นdraw(golfed เป็นd) ที่ได้รับการป้อนข้อมูลเป็นรายการของการประสานงานเสา (ตัวอย่างเช่นdraw [[0 100] [100 100] [-200 100] [-100 -50][0 0]]จะวาดบนหน้าจอผล

ที่ต้องการ:

  1. ความยาวเชือกเริ่มต้น = 300 พิกเซล (เนื่องจาก 3 พิกเซลเล็กเกินไป)
  2. [0 0]จะต้องรวมอยู่ในรายการเสา หากเปิดใช้งานรหัสการแก้ปัญหา (วาดเสา) แล้ว[0 0]จะต้องเป็นรายการสุดท้าย
  3. สุนัขเริ่มต้นที่พิกัดx=0, y=-300(เหมือนในคำอธิบายปัญหา)

การเพิ่มประสิทธิภาพที่เป็นไปได้:

  1. -1 ไบต์ถ้ากรณีพิเศษ (สุนัขวิ่งเข้าไปในเสา) ไม่จำเป็นต้องถูกต้องทางคณิตศาสตร์โดยการแทนที่>=ด้วย>

รหัส Golfed:

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

โค้ดที่ไม่ได้รับการตอบกลับ ( ;เริ่มความคิดเห็นแบบอินไลน์ (ใช้สำหรับคำอธิบาย) และ:เริ่มชื่อตัวแปร):

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

1

Python 2 + PIL, 310 ไบต์

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()

สคริปต์จะอ่านรายการคะแนนจาก stdin เป็นรายการของจำนวนเชิงซ้อน

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

ป้อนคำอธิบายรูปภาพที่นี่

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

ป้อนคำอธิบายรูปภาพที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.