점 목록이 주어진 정사각형 회전 결정


19

이 도전에서, 당신은 포인트 목록이 제공됩니다. 이 점들은 가상의 사각형 둘레에 있습니다. 당신의 목표는 :

  1. 가능한 경우 사각형의 회전을 인쇄합니다. [0, 90)의 값이됩니다. 여기서 0은 세로 및 가로 선이있는 사각형을 나타냅니다. 회전은 시계 반대 방향으로 계산됩니다.
  2. 정사각형 회전이 모호한 경우 (예 : 2 포인트 만 제공됨) "알 수 없음"을 인쇄하십시오.
  3. 포인트가 주어진 사각형을 만드는 것이 불가능한 경우 "불가능"을 인쇄하십시오

귀하가 제공 한 포인트는 고유하며 특정 순서가 아닙니다. 목록을 입력하려는 모든 형식을 사용할 수 있지만, 예를 들어, 내 포인트는 형식 x,y이며 공백으로 구분됩니다. 숫자는 부동 소수점 숫자이며 언어에서 처리 할 수있는 범위 내에 있다고 가정 할 수 있습니다. 출력은 소수점 이하 3 자리까지 정확해야하며 언어가 부동 소수점 숫자를 완벽하게 처리한다고 가정합니다.

다음은 몇 가지 테스트 사례입니다 (쉽게 시각화하기 위해 정수를 사용하여 대부분 만들었지 만 프로그램은 부동 소수점을 처리해야합니다).

알 수 없는:

0,0                      
0,0 1,0        
0,0 1,0 0,1              
0,0 1,0 0,1 1,1
0,1 0,2 1,0 1,3 2,0 2,3 3,1 3,2

불가능한:

0,0 1,0 2,0 3,1 4,2
0,0 1,0 2,0 1,1
0,1 0,2 1,0 1,3 2,0 2,3 3,1 3,2 2,2
2,0 0,1 2,2 0,3
0,0 2,1 0,2 2,2 -1,1

가능 (지정하지 않은 경우 0을 반환해야 함) :

0,0 1,0 2,0
0,0 0.3,0.3 0.6,0.6  (should return 45)
0,0 0.1,0.2 0.2,0.4  (should return appx 63.435 (the real value is arctan(2)))
0,0 0,1 2,1 2,2
0,1 0,2 1,0 1,4 2,0 2,4 4,1 4,3 

흥미로운 테스트 사례를 놓친 것 같습니다. 그렇다면 의견을 추가하여 추가하십시오.

이것은 코드 골프이므로 가장 짧은 코드가 승리합니다!


필요한 최소 정확도가 있습니까? 출력이 잘못 계산되기 전에 정답에서 얼마나 멀리 떨어져있을 수 있습니까?
trichoplax

@trichoplax는 언어의 부동 소수점 숫자 구현이 허용하는 한 정확해야합니다.
Nathan Merrill

이것은 가능한 두 가지 접근 방식이 있고 하나의 언어로 약간 더 정확한 결과를 제공한다면 가장 정확한 접근 방식을 사용해야합니까?
trichoplax

@trichoplax 예.
Nathan Merrill

2
@NathanMerrill보다 정확한 접근법이 존재하는지 어떻게 알 수 있습니까? 소수점 이하 4 자리 또는 6 자리와 같이 고정 된 최소 정확도 만 요구하는 것이 더 합리적이라고 생각합니다. 입력의 부동 소수점 표현의 부정확성으로 인해 많은 예제가 불가능한지 확실하지 않습니다. 아마 합리적 또는 정수 입력이 더 좋았을 것입니다.
Martin Ender

답변:


6

개정 1 : 루비, 354 바이트

blutorange 덕분에 더 많은 골프.

->a{t=s=Math::PI/18E4
d=r=c=0
a=a.map{|e|e-a[0]}
0.upto(36E4){|i|b=a.map{|e|(e/Complex.polar(1,i*s)).rect}.transpose
m,n=b
if n.min>=f=0
l=[m.max-x=m.min,n.max].max
a.each_index{|j|f+=((l-w=n[j])*(x+l-v=m[j])*(x-v)*w)**2}
(1E-9>q=f/l**8)&&(c>0&&(i-d)%9E4%89E3>1E3?c=9E9:0;c+=1;d=i)
q<t&&(r=i)&&t=q;end}
c<101&&a[1]?c<1?'impossible':r%9E4/1.0E3:'unknown'}

루비, 392 바이트

->(a){
s=Math::PI/18E4
t=1
d=r=c=0
a=a.map{|e|e-a[0]}
(0..36E4).each{|i|
b=a.map{|e|(e/Complex.polar(1,i*s)).rect}.transpose
m=b[0]
n=b[1]
x=m.min
if n.min>=0
l=[m.max-x,n.max].max
f=0
a.each_index{|j|f+=((l-n[j])*(x+l-m[j])*(x-m[j])*n[j])**2}
q=f/l**8
if q<1E-9
c>0&&(i-d)%9E4%89E3>1E3?(c=9E9):0
c+=1
d=i
end
if q<t
r=i
t=q
end
end
}
c>100||a.size<2?'unknown':c<1? 'impossible':r%9E4/1.0E3
}

알고리즘은 다음과 같습니다.

-임의의 점 (첫 번째 점)을 선택하고 원점으로 이동합니다 (목록의 모든 점에서이 점의 좌표를 뺍니다.)

-원점에 대한 정사각형의 모든 회전을 360도를 통해 0.001 도씩 증가시켜보십시오.

-주어진 회전에서 모든 점이 y 축 위에 있으면 가장 낮은 점과 가장 왼쪽 점을 포함하여 모든 점 주위에 가능한 가장 작은 사각형을 그립니다.

-모든 점이 가장자리에 있는지 확인하십시오. 이것은 각 점을 취하고 모든 모서리에서 제곱 거리를 찾아 곱하는 부드러운 계산으로 수행됩니다. 이것은 예 / 아니오 답변이 아닌 적합합니다. 이 제품을 sidelength ^ 8 (으)로 나눈 값이 1E-9보다 작 으면 해가 발견되는 것으로 해석됩니다. 실제로 이것은 허용 오차 미만입니다.

-가장 잘 맞는 모드는 90도이며 올바른 각도로보고됩니다.

현재이 코드는 100 개가 넘는 솔루션이 발견되면 모호한 값을 반환합니다 (0.001도 분해능, 0.1도 허용 오차).

테스트 프로그램에서 최초의 완전 작동 기능

속도를 합리적으로 만들기 위해 필요한 해상도의 1/10로 해상도를 남겼습니다. 가장 마지막 테스트 사례에서 0.01 degress 오류가 있습니다.

g=->(a){
 s=Math::PI/18000
 t=1
 d=r=-1
 c=0
 a=a.map{|e| e-a[0]} 

 (0..36000).each{|i| 
    b=a.map{|e|(e/Complex.polar(1,i*s)).rect}.transpose

    m=b[0]
    n=b[1]
    x=m.min

    if n.min>=0

       l=[m.max-x,n.max].max
       f=0
       a.each_index{|j|f+=((l-n[j])*(x+l-m[j])*(x-m[j])*n[j])**2}
       q=f/l**8

       if q<1E-9

         j=(i-d)%9000
         c>0&&j>100&&j<8900?(c=9E9):0 
         c+=1
         d=i
       end  

       if q<t
         r=i
         t=q
       end

     end    
  }

 print "t=",t,"   r=",r,"     c=",c,"    d=",d,"\n"
 p c>100||a.size<2?'unknown':c<1? 'impossible':r%9000/100.0   
}


#ambiguous
#g.call([Complex(0,0)])
#g.call([Complex(0,0),Complex(1,0)])
#g.call([Complex(0,0),Complex(1,0),Complex(0,1)])
#g.call([Complex(0,0),Complex(1,0),Complex(0,1),Complex(1,1)])
#g.call([Complex(0,1),Complex(0,2),Complex(1,0),Complex(1,3),Complex(2,0),Complex(2,3),Complex(3,1),Complex(3,2)])

#impossible
#g.call([Complex(0,0),Complex(1,0),Complex(2,0),Complex(3,1),Complex(4,2)])
#g.call([Complex(0,0),Complex(1,0),Complex(2,0),Complex(1,1)])
#g.call([Complex(0,1),Complex(0,2),Complex(1,0),Complex(1,3),Complex(2,0),Complex(2,3),Complex(3,1),Complex(3,2),Complex(2,2)])
#g.call([Complex(2,0),Complex(0,1),Complex(2,2),Complex(0,3)])
#g.call([Complex(0,0),Complex(2,1),Complex(0,2),Complex(2,2),Complex(-1,1)])

#possible
g.call([Complex(0,0),Complex(1,0),Complex(2,0)])
g.call([Complex(0,0),Complex(0.3,0.3),Complex(0.6,0.6)]) #(should return 45)
g.call([Complex(0,0),Complex(0.1,0.2),Complex(0.2,0.4)]) #(should return appx 63.435 (the real value is arctan(2)))
g.call([Complex(0,0),Complex(0,1),Complex(2,1),Complex(2,2)])
g.call([Complex(0,1),Complex(0,2),Complex(1,0),Complex(1,4),Complex(2,0),Complex(2,4),Complex(4,1),Complex(4,3)])

테스트 프로그램에서 사양을 준수하는 해상도의 골프 버전은 통화 당 약 1 분이 걸립니다.

마지막 테스트 사례에서 여전히 0.001 도의 성가신 오류가 있습니다. 해상도를 높이면 제거 할 수 있습니다.

g=->(a){                                                            #take an array of complex numbers as input
  s=Math::PI/18E4                                                   #step size PI/180000
  t=1                                                               #best fit found so far
  d=r=c=0                                                           #angles of (d) last valid result, (r) best fit; c= hit counter
  a=a.map{|e|e-a[0]}                                                #move shape so that first point coincides with origin
  (0..36E4).each{|i|                                                #0..360000
    b=a.map{|e|(e/Complex.polar(1,i*s)).rect}.transpose             #rotate each element by dividing by unit vector of angle i*s, convert to array... 
    m=b[0]                                                          #...transpose array [[x1,y1]..[xn,yn]] to [[x1..xn],[y1..yn]]...
    n=b[1]                                                          #...and assign to variables m and n 
    x=m.min                                                         #find leftmost point
    if n.min>=0                                                     #if all points are above x axis
       l=[m.max-x,n.max].max                                        #find the sidelength of smallest square in which they will fit
       f=0                                                          #f= accumulator for errors. For each point
       a.each_index{|j|f+=((l-n[j])*(x+l-m[j])*(x-m[j])*n[j])**2}   #...add to f the product of the squared distances from each side of the smallest square containing all points
       q=f/l**8                                                     #q= f normalized with respect to the sidelength.
       if q<1E-9                                                    #consider a hit if <1E-9
         c>0&&(i-d)%9E4%89E3>1E3?(c=9E9):0                          #if at least one point is already found, and the difference between this hit and the last exceeds+/-1 deg (mod 90), set c to a high value
         c+=1                                                       #increment hit count by 1 (this catches infinitely varible cases)
         d=i                                                        #store the current hit in d
       end  
       if q<t                                                       #if current fit is better than previous one
        r=i                                                         #store the new angle
        t=q                                                         #and revise t to the new best fit.
       end             
    end
  }
  c>100||a.size<2?'unknown':c<1? 'impossible':r%9E4/1.0E3           #calculate and return value, taking special care of case where single point given.
}
#ambiguous
puts g.call([Complex(0,0)])
puts g.call([Complex(0,0),Complex(1,0)])
puts g.call([Complex(0,0),Complex(1,0),Complex(0,1)])
puts g.call([Complex(0,0),Complex(1,0),Complex(0,1),Complex(1,1)])
puts g.call([Complex(0,1),Complex(0,2),Complex(1,0),Complex(1,3),Complex(2,0),Complex(2,3),Complex(3,1),Complex(3,2)])

#impossible
puts g.call([Complex(0,0),Complex(1,0),Complex(2,0),Complex(3,1),Complex(4,2)])
puts g.call([Complex(0,0),Complex(1,0),Complex(2,0),Complex(1,1)])
puts g.call([Complex(0,1),Complex(0,2),Complex(1,0),Complex(1,3),Complex(2,0),Complex(2,3),Complex(3,1),Complex(3,2),Complex(2,2)])
puts g.call([Complex(2,0),Complex(0,1),Complex(2,2),Complex(0,3)])
puts g.call([Complex(0,0),Complex(2,1),Complex(0,2),Complex(2,2),Complex(-1,1)])

#possible
puts g.call([Complex(0,0),Complex(1,0),Complex(2,0)])
puts g.call([Complex(0,0),Complex(0.3,0.3),Complex(0.6,0.6)]) #(should return 45)
puts g.call([Complex(0,0),Complex(0.1,0.2),Complex(0.2,0.4)]) #(should return appx 63.435 (the real value is arctan(2)))
puts g.call([Complex(0,0),Complex(0,1),Complex(2,1),Complex(2,2)])
puts g.call([Complex(0,1),Complex(0,2),Complex(1,0),Complex(1,4),Complex(2,0),Complex(2,4),Complex(4,1),Complex(4,3)])

약 30 % 더 많은 코드에 대해이 알고리즘은 빠르게 작동하도록 조정할 수 있습니다. 유한 한 수의 솔루션을 사용하는 경우 모서리 중 하나가 큐브를 따라 평평하게 놓여 있기 때문에 실제로 시도해야 할 모든 각도는 각 정점 쌍에 해당합니다. 또한 무한히 많은 솔루션이 없는지 확인하기 위해 약간의 흔들림이 필요합니다.


두 번째 테스트 사례를 수정했습니다. 감사합니다
Nathan Merrill

@NathanMerrill 수정 된 사례 0,0 1,0 2,0 1,2는 대각선 0,0 ... 2,2의 경우 에도 여전히 가능합니다. 나는 그것을 시도했고 또한 0,0 1,0 2,0 1,1(후자는 실제로 불가능하다.) 또 다른 요점 : 당신은 단일 포인트가 주어 졌을 때 내 코드가 알 수없는 것이 아니라 불가능한 것을 반환하는 것이 용납 가능하거나 용납 할 수 없다고 생각합니까? 골프를 시작하기 전에 답을 부탁드립니다.
Level River St

나는하려고했다 1,1. 어떻게 1,2도착 했는지 잘 모르겠습니다 . 허용되지 않습니다.
Nathan Merrill

:이 같은 적어도 354 바이트로 내려받을 수 있어야 pastebin.com/jsgwMKQF
blutorange

@blutorange 팁 주셔서 감사합니다! 루비를 처음 사용하고 골프를 치는 데 어려움이 있습니다. if..endRuby의 중첩 삼항 연산자에 끔찍한 문제가 있기 때문에 많은 것을 남겼습니다 . 나는 당신이을 사용하여 그 것을 알았습니다 &&.
Level River St

6

안녕하세요, 여기 겸손한 물약이 있습니다. 테스트 케이스는 파일 맨 아래의 DATA 스트림에 배치 됩니다. 알고리즘은 try-error 접근 방식으로 발전했습니다.
나는 이것이 광범위하게 휴리스틱 접근법이라고 인정하지만 실제로 빠르다. 모든 경우를 즉시 해결한다 .
몇 가지 버그가 있음을 알고 있지만 지금까지는 모든 테스트 사례에 대한 올바른 답변을 제공합니다.
또한 가장 짧은 코드가 승리 한다는 것을 알고 있지만 이것이 용어 의 가장 빠른 의미 에서 가장 짧습니다 .

알고리즘은 다음과 같습니다

  1. 점을 조사하고 두 점 사이의 각 세그먼트에 대해 기록 경사, 길이, x 절편, y 절편

  2. 직선 (즉, 3 개의 점 또는 2 개의 인접한 세그먼트)과 뚜렷한 가능한 경사 (회전)를 찾습니다. 각 라인에서 사용 가능한 가장 긴 세그먼트를 추적하십시오.

  3. 세그먼트와 세 번째 점 사이의 모든 거리를 찾으십시오 (이 점은 점 4에 사용되어야 함). 0이 아닌 최소 거리를 추적하십시오.

  4. 4 개의 점 (일반적으로 직사각형)의 경우 내부 점을 찾습니다.

솔루션 표시 :

A. 하나 이상의 내부 점이 있으면 "불가능"이라고 말합니다.

B. 한 줄 :

  • 내부 점이없는 단일 선에있는 대부분의 점의 경우 "가능한"이라고 말합니다.

  • 점이 선에 너무 가까이있는 경우 "불가능"이라고 말합니다.

    C. 두 줄 :

  • 회전이 하나만있을 때 "가능"이라고 말하십시오.

  • 둘 이상의 회전이있을 때 "불가능"이라고 말하십시오.

    D. 선 없음 : 90 ° 회전 세그먼트에 맞는 회전을 찾습니다.

  • 하나만 적합하거나 많은 수만큼 적합하면 "가능한"이라고 말합니다.

  • 하나 이상의 점에 맞지 않으면 "불가능"이라고 말하십시오.

  • 회전이 맞는 경우 "알 수 없음"이라고 말합니다.

다음은 코드입니다 (알려진 모든 버그가 해결되었습니다)

#!/usr/bin/perl
use strict ;
use warnings ;
my $PI = 4*atan2( 1, 1 ) ;
my $EPS = 0.000001 ;
while ( <DATA> ) {
    if ( /^\s*#/ ) { print ; next } # print comments
    chomp ;
    my @dot = split /\s+/ ;
    my $n = scalar @dot || next ; # skip empty lines

    # too few dots
    if ( $n < 3 ) {
        print "@dot : Unknown.\n" ;
        next
    }

    my %slop = () ; # segment --> its slope
    my %leng = () ; # segment --> its length
    my %x0   = () ; # segment --> its line's x-intercept
    my %y0   = () ; # segment --> its line's y-intercept
    my %side = () ; # slope   --> list of segments (with duplicates)

    # 1. examine dots
    for my $p (@dot) {
        my ($px,$py) = split /,/, $p ;
        for my $q (@dot) {
            next if $p eq $q ;
            next if defined ( $slop{ "$q $p" } ) ;
            my $segment_name = "$p $q" ;
            my ($qx,$qy) = split /,/, $q ;
            my $dx = $px - $qx ;
            my $dy = $py - $qy ;
            my $slope = "inf" ; $slope = $dy / $dx if abs($dx) > 0 ;
            my $sd = $dx*$dx+$dy*$dy ;
            my $x0 = ( $slope eq 'inf' ? $px : "nan" ) ;
            my $y0 = ( abs($slope) > 0 ? $px : "nan" ) ;
            $x0 = $qx - $qy / $slope if abs($slope) > 0 ;
            $y0 = $qy - $qx * $slope if $slope ne "inf" ;
            push @{ $side{ $slope } }, $segment_name ;
            $slop{ $segment_name } = $slope ;
            $leng{ $segment_name } = sqrt( $sd ) ;
            $x0{ $segment_name } = $x0 ;
            $y0{ $segment_name } = $y0 ;
        }
    }

    # 2. find straight lines and distinct possible slopes (rotation)
    my %line = () ;     # slope --> segment name
    my %rotation = () ; # slope --> slope itself
    my $a_rotation ;
    for my $slope ( keys %side ) {
        my %distinct = () ;
        for my $segment_name ( @{ $side{ $slope } } ) {
            $distinct{ $segment_name } = $slope ; 
            my $rot = $slope eq 'inf' ? '0' : abs( $slope < 0 ? 1/$slope : $slope ) ;
            $rotation{ $rot } = $rot ;
            $a_rotation = $rot ;
        }
        for my $a_segm ( keys %distinct ) {
            for my $b_segm ( keys %distinct ) {
                next if $a_segm eq $b_segm ;
                # the two segment has to be adjacent
                my ($a1,$a2) = split / /, $a_segm;
                my ($b1,$b2) = split / /, $b_segm;
                next unless $a1 eq $b1 || $a1 eq $b2 || $a2 eq $b1 || $a2 eq $b2 ;
                # the two segment has to have same intercepts
                my $x0a = $x0{ $a_segm } ;
                my $x0b = $x0{ $b_segm } ;
                my $y0a = $y0{ $a_segm } ;
                my $y0b = $y0{ $b_segm } ;
                next unless $x0a eq $x0b && $y0a eq $y0b ;
                # keep the longest segment
                my $a_len = 0 ;
                $a_len = $leng{ $line{ $slope } } if defined( $line{ $slope } ) && defined( $leng{ $line{ $slope } } ) ;
                for my $segm ("$a1 $b1", "$a1 $b2", "$a2 $b1", "$a2 $b2",
                              "$b1 $a1", "$b2 $a1", "$b1 $a2", "$b2 $a2" ) {
                    next unless defined ( $leng{ $segm } ) ;
                    if ( $a_len < $leng{ $segm } ) {
                        $a_len = $leng{ $segm } ;
                        $line{ $slope } = $segm ;
                    }
                }
            }
        }
    }

    # 3. find distance between a segment and a third point
    my %distance = () ;            # segment-point --> distance
    my %distance_mani = () ;       # distance --> array of segment-point
    my %min_distance = () ;        # segment --> min distance to other dots
    for my $segment_name ( keys %slop ) {
        my $a = $slop{ $segment_name } ;
        my $b = -1 ;
        my $c = $y0{ $segment_name } ;
        my $z = $x0{ $segment_name } ;
        for my $p (@dot) {
            next if $segment_name =~ /$p/ ; # skip dots that are in the segment
            my ($px,$py) = split /,/, $p ;
            my $d = 0 ;
            if ( $a ne 'inf' ) {
                my $num = ($b * $py) + ($a * $px) + $c ;
                my $den = sqrt( $a*$a + $b*$b ) ;
                $d = abs( $num ) / $den ;
            }
            else {
                $d = abs( $px - $z );
            }
            $distance{ "$segment_name $p" } = $d ;
            push @{ $distance_mani{ $d } }, "$segment_name $p" ;
            if ( $d > 0 ) {
                $min_distance{ $segment_name } = $d if !defined ( $min_distance{ $segment_name } ) or $d < $min_distance{ $segment_name }
            }
        }
    }

    # 4. find inner dots: pick 4 dots to form a well shaped pseudo-rectangle
    #    and check for any other dot that is too close to all the 4 sides.
    my $fail = 0 ;
    RECTANGLE:
    for my $a ( @dot ) {
        for my $b ( @dot ) {
            next if $a eq $b ;
            my ($ax,$ay) = split /,/, $a ;
            my ($bx,$by) = split /,/, $b ;
            next if $ax > $bx || $ay > $by ;
            for my $c ( @dot ) {
                next if $c eq $a or $c eq $b ;
                my ($cx,$cy) = split /,/, $c ;
                next if $bx < $cx || $by > $cy ;
                for my $d ( @dot ) {
                    next if $d eq $a or $d eq $b or $d eq $c ;
                    my ($dx,$dy) = split /,/, $d ;
                    next if $cx < $dx || $cy < $dy  ;
                    next if $dx > $ax || $dy < $ay  ;
                    for my $e ( @dot ) {
                        next if $e eq $a or $e eq $b or $e eq $c or $e eq $d ;

                        my $abe = $distance{ "$a $b $e" } || $distance{ "$b $a $e" } || next ;
                        my $bce = $distance{ "$b $c $e" } || $distance{ "$c $b $e" } || next ;
                        my $cde = $distance{ "$c $d $e" } || $distance{ "$d $c $e" } || next ;
                        my $dae = $distance{ "$d $a $e" } || $distance{ "$a $d $e" } || next ;

                        my $abd = $distance{ "$a $b $d" } || $distance{ "$b $a $d" } || next ;
                        my $abc = $distance{ "$a $b $c" } || $distance{ "$b $a $c" } || next ;
                        my $bca = $distance{ "$b $c $a" } || $distance{ "$c $b $a" } || next ;
                        my $bcd = $distance{ "$b $c $d" } || $distance{ "$c $b $d" } || next ;
                        my $cdb = $distance{ "$c $d $b" } || $distance{ "$d $c $b" } || next ;
                        my $cda = $distance{ "$c $d $a" } || $distance{ "$d $c $a" } || next ;
                        my $dac = $distance{ "$d $a $c" } || $distance{ "$a $d $c" } || next ; 
                        my $dab = $distance{ "$d $a $b" } || $distance{ "$a $d $b" } || next ; 

                        if ( $abd > $abe && $abc > $abe && 
                             $bca > $bce && $bcd > $bce &&
                             $cdb > $cde && $cda > $cde &&
                             $dac > $dae && $dab > $dae) {
                            ## print "     $a $b $c $d --> $e\n";
                            $fail ++ ;
                            last RECTANGLE ;
                        }
                    }
                }
            }
        }
    }
    if ( $fail ) {
        print "@dot : Impossible.\n" ;
        next # DATA 
    }

    my $m = scalar keys %rotation ; # how many distinct slopes
    my $r = scalar keys %line ; # how many lines i.e. >3 dots in a straight line

    print "@dot : " ;
    # most of dots lie in single line without inner dots
    if ( $r == 1 ) {
        $a_rotation = (keys %line)[0] ;
        my $a_segment = $line{ $a_rotation } ;
        my $a_dist = $min_distance{ $a_segment } || 0 ;
        if ( $a_dist && $a_dist < $leng{ $a_segment } ) {
            print "Impossible.\n"  ;
        }
        else {
            print "Possible. --> " . sprintf("%.3f deg", 180 / $PI * atan2( $a_rotation, 1 ) ) . "\n" ;
        }
        next # DATA
    }
    # two lines
    if ( $r == 2 ) {
        print "Impossible.\n" if $m > 1 ;
        print "Possible. --> " .
            sprintf("%.3f deg", 180 / $PI * atan2( $a_rotation, 1 ) ) . "\n" if $m == 1 ;  # never?
        next ; # DATA
    }
    # no lines
    if ( $r == 0 ) {
        # match between segment rotation and other side
        my $count = 0 ;
        my $numeros = 0 ;
        for my $slope ( keys %rotation ) {
            my $rot = $slope eq '0' ? 'inf' : -1/$slope ;
            if ( exists $side{ $rot } ) {
                $count++ ;
                my $u = scalar @{ $side{ $rot } } ;
                if ( $numeros < $u ) {
                    $numeros = $u ;
                    $a_rotation = $slope ;
                }
            }
        }
        print "Possible. --> " .
            sprintf("%.3f deg", 180 / $PI * atan2( $a_rotation, 1 ) ) . "\n" if $count < 2 or $count == $n ;
        print "Unknown.\n"    if $count == $m ;
        print "Impossible.\n"    if $count > 2 && $count != $n && $count != $m;
        next # DATA
    }
    # there are lines
    print "lines $r " ;
    my $shorter = 0 ;
    my $longer = 0 ;
    for my $slope ( keys %line ) {
        for my $dis ( keys %distance_mani ) {
            $shorter++ ;
            $longer++ ;
        }
    }
    print "ACK! WHAT IS THIS CASE! n=$n, m=$m, r=$r\n" ;
    1 ;
}

1;

__DATA__
# Unknown:

0,0
0,0 1,0
0,0 1,0 0,1
0,0 1,0 0,1 1,1
0,1 0,2 1,0 1,3 2,0 2,3 3,1 3,2

# Impossible:

0,0 1,0 2,0 3,1 4,2
0,0 1,0 2,0 1,1
0,1 0,2 1,0 1,3 2,0 2,3 3,1 3,2 2,2
2,0 0,1 2,2 0,3
0,0 2,1 0,2 2,2 -1,1

# Possible (if not designated, should return 0):

0,0 1,0 2,0 1,2
0,0 1,0 2,0 0.5,2.1

0,0 1,0 2,0
0,0 1,0 2,0 1,2
0,0 0.3,0.3 0.6,0.6
0,0 0.1,0.2 0.2,0.4
0,0 0,1 2,1 2,2
0,1 0,2 1,0 1,4 2,0 2,4 4,1 4,3

그리고 여기는 ouptut입니다

# Unknown:
0,0 : Unknown.
0,0 1,0 : Unknown.
0,0 1,0 0,1 : Unknown.
0,0 1,0 0,1 1,1 : Unknown.
0,1 0,2 1,0 1,3 2,0 2,3 3,1 3,2 : Unknown.
# Impossible:
0,0 1,0 2,0 3,1 4,2 : Impossible.
0,0 1,0 2,0 1,1 : Impossible.
0,1 0,2 1,0 1,3 2,0 2,3 3,1 3,2 2,2 : Impossible.
2,0 0,1 2,2 0,3 : Impossible.
0,0 2,1 0,2 2,2 -1,1 : Impossible.
# Possible (if not designated, should return 0):
0,0 1,0 2,0 1,2 : Possible. --> 0.000 deg
0,0 1,0 2,0 0.5,2.1 : Possible. --> 0.000 deg
0,0 1,0 2,0 : Possible. --> 0.000 deg
0,0 1,0 2,0 1,2 : Possible. --> 0.000 deg
0,0 0.3,0.3 0.6,0.6 : Possible. --> 45.000 deg
0,0 0.1,0.2 0.2,0.4 : Possible. --> 63.435 deg
0,0 0,1 2,1 2,2 : Possible. --> 0.000 deg
0,1 0,2 1,0 1,4 2,0 2,4 4,1 4,3 : Possible. --> 0.000 deg

문안 인사.

마테오.


첫 번째 버그는 다음과 같습니다. 귀하의 사례 0,0 1,0 2,0 1,1 (불가능)은 내 스크립트에 의해 "가능한.-> 0.000도"라고 말합니다. 수정해야합니다
Mattsteel

나는이 솔루션을 정말 좋아한다. 코드 골프에 대해 너무 걱정하지 마십시오. 그것은 도전이 실제로하는 것이 아니며 반드시 현상금을받는 사람이 아닙니다.
나단 메릴

Nathan에게 감사합니다. 결과는 훨씬 더 많은 정보를 보여줍니다. 이것들은 디버그 용이며 의도적으로 고칠 수 있도록 남겨 두었습니다
Mattsteel

두 번째 버그 : "답이 불가능합니다. (줄 없음) n = 8, m = 6, r = 0 c = 6"은 정답 "0,1 0,2 1,0 1,3 2,0 바로 뒤에 쓰여집니다. 2,3 3,1 3,2 : 불명. (라인 없음) n = 8, m = 6, r = 0 c = 6 ".
Mattsteel

두 가지 버그 수정 : 모든 경우가 정상적으로 실행됩니다.
Mattsteel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.