체인에 개


31

다락방 창문에서 이웃 마당을 찾고 있습니다. 그들은 마당 중앙에있는 기둥에 묶인 개가 있습니다. 개는 마당을 돌아 다니지 만 항상 체인의 끝 부분에 있으므로 흙에 흔적이 남습니다. 일반적으로이 트랙은 완벽하게 원형이지만 내 이웃은 마당에 개 사슬이 걸리는 다른 기둥이 있습니다. 개 체인이 기둥에 부딪 칠 때마다 개는 체인 길이가 반지름으로 남으면서 새 기둥을 중심으로 회전하기 시작합니다. 기둥, 개 및 체인은 모두 너비가 0이므로 (내 이웃은 수학자) 체인은 원의 반지름이 짧아지지 않고 무한히 극 주위를 감을 수 있습니다. 체인이 경로에 있으면 개가 체인을 통과 할 수도 있습니다 (칼라가 아님). 이 이상한 점을 잠시 관찰 한 후 이웃의 개를 시뮬레이트하는 코드를 작성하기로 결정했습니다. 이 코드는 개가 묶여있는 중심 극의 위치, 이웃 마당에있는 다른 극의 위치, 체인의 길이 및 개의 시작 위치를 가져 와서 개가 잔디를 닳은 경로. 다음의 조합은 일정하다고 가정 할 수 있으므로 입력으로 사용하지 마십시오.

  • 개가 묶여있는 극의 위치

  • 체인 길이

  • 개의 시작 위치

태양이 떠오르 기 때문에 창문으로 비춰지는 다락방 바닥의 공간이 줄어들어 코드를 작성할 공간이 점점 줄어 듭니다. 다락방 바닥에 코드를 작성할 공간이 있도록 코드의 바이트 수를 최소화하십시오.

테스트 사례

여기서 나는 개가 체인이 달린 극점 (빨간색 점)에서 남쪽으로 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 2016

@KritixiLithos {0,.5}가장 큰 원없이 세로 로 뒤집힌 출력입니다 . 개는 본질적으로 두 번째 기둥에 걸리기 시작합니다.
밀 마법사

부동 소수점 문제의 결과로, 프로그램은 마지막 테스트 케이스에서 (1,1) 주위에 원을 그립니다 (문자열 길이는 99.99999입니다). 괜찮습니까?
Kritixi Lithos

개는 시계 방향과 시계 반대 방향으로 실행되지만 고정 지점에서 실행됩니까?
user202729

3
"창이 비추는 다락방 바닥의 공간이 점점 커지고 있습니다. 코드를 작성할 공간이 줄어들고 있습니다."+1
Leo

답변:


11

matplotlib를 사용하는 Python 3, 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 x 10입니다. 이러한 매개 변수의 경우 결과는 예제와 정확히 일치합니다. 결과는 다음과 같습니다 (최종 예).

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

알고리즘은 매우 간단하며 시계 방향과 반 시계 방향 검색을 구분하기 위해 하나의 조건 만 필요합니다. 알고리즘의 상태는 현재 회전 지점과 현재 회전 지점에 도달했을 때의 가죽 끈 방향 / 남은 길이로 정의됩니다. 다음과 같이 작동합니다.

  • 충돌 세트에서 현재 회전 지점뿐만 아니라 나머지 가죽 끈 길이보다 현재 회전 지점에서 더 멀리 떨어진 지점을 필터링합니다.
  • 이 세트가 비어 있으면이 암의 끝에 도달했을 때이 지점을 중심으로 나머지 벨트 길이의 반경을 가진 원을 그립니다.
  • 차이 벡터와 가죽 끈 방향 사이의 위상차가 최소 / 최대 인 지점을 결정하십시오. 이것은 가죽 끈이 시계 방향 / 반 시계 방향으로 각각 타격하는 다음 지점입니다.
  • 이 벡터를 기반으로 호를 그리고 가죽 끈 길이를 취하고 거리의 크기를 빼고 가죽 끈 방향을 차이 벡터의 방향으로 설정하십시오. 회전 점을 업데이트하고 시작부터 계속하십시오.

이 알고리즘은 시계 방향으로 먼저 수행 된 후 상태가 재설정되고 시계 반대 방향으로 실행됩니다. 알고리즘의 단순성은 프로그램 바이트 수의 약 절반이 드로잉 함수에 사용됨을 의미합니다. 그리기 루틴이 제거 된 경우 프로그램 크기에서 218 바이트가 제거됩니다.

다음은 점과 가죽 끈 충돌을 표시하는 디버그 코드를 포함하는 ungolfed 버전입니다.

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 덕분에 2 바이트를 절약했습니다.

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[][]). 이것은 기본적으로 테스트 케이스 # 3이지만 창에 맞추기 위해 100을 곱합니다.

몇 가지 참고할 사항 :

  • 이 프로그램은 극을 그리지 않습니다
  • Processing의 좌표계에서 양의 y 축이 내려 가기 때문에 이미지가 거꾸로 뒤집힌 것처럼 보입니다.
  • Processing은 float를 사용하기 때문에 계산이 정확하지 않으므로 이미지에서이를 확인할 수 있습니다. 이러한 부동 소수점 오류가 문제인지 OP에 문의했습니다.
  • 창의 크기는 600 x 600 픽셀입니다.
  • 스택 pushMatrix()popMatrix()연산이 32 개의 행렬 만 보유 할 수 있기 때문에 매우 작은 입력 좌표는 프로그램을 중단시킵니다.
  • 개는 (0, -300)에서 시작하고 체인은 300 픽셀 길이에서 시작합니다.
  • 아래 이미지는 편의를 위해 축소되었습니다.

위 테스트 케이스의 샘플 출력.

여기에 이미지 설명을 입력하십시오

사전 출력을 보려면 translate(w,w);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);

그리고 이것은 우리에게이 결과를줍니다 :

원

언 골프 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(로 정의)를 정의합니다 ( ddraw [[0 100] [100 100] [-200 100] [-100 -50][0 0]]: 결과를 화면에 표시).

요구 사항 :

  1. 초기 로프 길이 = 300 픽셀. (3 픽셀이 너무 작으므로)
  2. [0 0]극 목록에 포함되어야합니다. 디버그 코드 (드로우 폴)가 켜져 [0 0]있으면 마지막 항목이어야합니다.
  3. 개가 좌표에서 시작합니다 x=0, y=-300(문제 설명에서와 같이).

가능한 최적화 :

  1. 예외적 인 경우 (개가 극으로 튀어 나온 경우) >=>

골프 코드 :

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

Ungolfed 코드 ( ;인라인 주석 (설명에 사용)을 :시작하고 변수 이름을 시작) :

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

파이썬 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.