การพิจารณาการหมุนของสแควร์ให้รายการของคะแนน


19

ในการท้าทายนี้คุณจะได้รับรายการคะแนน จุดเหล่านี้อยู่ในปริมณฑลของตารางจินตนาการ เป้าหมายของคุณคือ:

  1. ถ้าเป็นไปได้ให้พิมพ์การหมุนของสแควร์ซึ่งจะเป็นค่าจาก [0, 90) โดยที่ 0 หมายถึงสแควร์ที่มีเส้นแนวตั้งและแนวนอน การหมุนจะถูกกำหนดเป็นองศานับทวนเข็มนาฬิกา
  2. หากการหมุนของจตุรัสไม่ชัดเจน (เช่นได้รับ 2 คะแนนเท่านั้น) ให้พิมพ์ "ไม่ทราบ"
  3. หากการสร้างตารางที่กำหนดจุดเป็นไปไม่ได้ให้พิมพ์ "Impossible"

คะแนนที่คุณได้รับนั้นรับประกันว่าจะไม่ซ้ำกันและไม่ได้อยู่ในลำดับเฉพาะ คุณสามารถใช้รูปแบบใดก็ได้ที่คุณต้องการป้อนรายการ แต่สำหรับตัวอย่างของฉันคะแนนของฉันจะอยู่ในรูปแบบ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

นี่หมายความว่าหากมีวิธีการที่เป็นไปได้ 2 วิธีและวิธีหนึ่งให้ผลลัพธ์ที่แม่นยำยิ่งขึ้นในภาษาของคุณจะต้องใช้วิธีการที่แม่นยำที่สุดใช่หรือไม่
trichoplax

@trichoplax ใช่
Nathan Merrill

2
@NathanMerrill ฉันจะรู้ได้อย่างไรว่ามีวิธีการที่แม่นยำกว่านี้อีกหรือไม่ ฉันคิดว่ามันจะสมเหตุสมผลมากกว่าที่จะต้องมีความแม่นยำขั้นต่ำคงที่เช่นตำแหน่งทศนิยม 4 หรือ 6 ตำแหน่ง แม้ว่าฉันจะไม่แน่ใจว่าหากความไม่ถูกต้องของการแสดงจุดลอยตัวของอินพุตทำให้ตัวอย่างเป็นไปไม่ได้มากมาย บางทีอินพุต rational หรือ integer น่าจะดีกว่าสำหรับเรื่องนั้น
Martin Ender

คำตอบ:


6

Rev 1: Ruby, 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
}

อัลกอริทึมมีดังนี้:

- เลือกจุดโดยพลการ (จุดแรก) และย้ายไปยังจุดกำเนิด (ลบพิกัดของจุดนี้จากจุดทั้งหมดในรายการ)

- ลองการหมุนทั้งหมดของสแควร์เกี่ยวกับจุดกำเนิดในการเพิ่มขึ้น 0.001 องศาผ่าน 360 องศา

- สำหรับการหมุนที่กำหนดหากทุกจุดอยู่เหนือแกน y ให้วาดสี่เหลี่ยมจัตุรัสที่เล็กที่สุดเท่าที่เป็นไปได้รอบจุดทั้งหมดโดยรวมจุดต่ำสุดและซ้ายสุดไว้ด้วย

- ตรวจสอบว่าทุกจุดอยู่บนขอบ สิ่งนี้ทำด้วยการคำนวณแบบนุ่มนวลที่แต่ละจุดหาระยะทางยกกำลังสองจากขอบทั้งหมดแล้วคูณเข้าด้วยกัน สิ่งนี้ให้แบบที่ดีมากกว่าคำตอบใช่ / ไม่ใช่ ถูกตีความว่าพบวิธีแก้ปัญหาหากผลิตภัณฑ์นี้หารด้วย sidelength ^ 8 น้อยกว่า 1E-9 ในทางปฏิบัติมันน้อยกว่าระดับของความอดทน

- แบบที่ดีที่สุดถูกนำ mod 90 องศาและรายงานว่าเป็นมุมที่ถูกต้อง

ในปัจจุบันโค้ดส่งคืนค่าที่ไม่ชัดเจนหากพบโซลูชันมากกว่า 100 รายการ (ที่ความละเอียด 0.001 องศานั่นคือค่าเผื่อ 0.1 องศา)

ฟังก์ชั่นการทำงานอย่างเต็มที่ครั้งแรกในโปรแกรมทดสอบ

ฉันออกความละเอียดไว้ที่ 1 / 10th ของความละเอียดที่กำหนดเพื่อให้ความเร็วเหมาะสม มีข้อผิดพลาด 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)])

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

ยังคงมีข้อผิดพลาดที่น่ารำคาญของ 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(อันหลังนั้นเป็นไปไม่ได้แน่นอน) อีกประเด็นหนึ่ง: คุณคิดว่ามันเป็นที่ยอมรับหรือยอมรับไม่ได้ว่าโค้ดของฉันกลับมาเป็นไปไม่ได้มากกว่าที่จะไม่รู้เมื่อมีเพียงจุดเดียว ฉันขอขอบคุณคำตอบก่อนเริ่มเล่นกอล์ฟ
เลเวลริเวอร์เซนต์

1,1ผมหมายถึงการทำ ไม่แน่ใจว่าไป1,2ถึงที่นั่นได้อย่างไร มันไม่เป็นที่ยอมรับ
นาธานเมอร์ริลล์

คุณควรจะสามารถรับได้อย่างน้อย 354 ไบต์เช่นนี้: pastebin.com/jsgwMKQF
blutorange

@ blutorange ขอบคุณสำหรับเคล็ดลับ! ฉันใหม่กับรูบี้และมีปัญหากับการเล่นกอล์ฟ ฉันออกไปเยอะif..endเพราะฉันมีปัญหาอย่างมากกับผู้ประกอบการประกอบไปด้วยสามในทับทิม &&ผมเห็นคุณมีรอบว่าด้วยการใช้
เลเวลริเวอร์เซนต์

6

Perl

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

นี่คืออัลกอริทึม

  1. ตรวจสอบจุดและสำหรับแต่ละเซ็กเมนต์ระหว่างจุดสองจุดที่บันทึกความชันความยาว x- จุดตัดแกนจุดตัดแกน y

  2. ค้นหาเส้นตรง (เช่นจุดสามจุดหรือสองส่วนที่อยู่ติดกัน) และความลาดชันที่เป็นไปได้ (บอกว่าการหมุน) ติดตามเซ็กเมนต์ที่ยาวที่สุดที่มีอยู่ในแต่ละบรรทัด

  3. ค้นหาระยะทางทั้งหมดระหว่างส่วนและจุดที่สาม (ควรใช้กับจุดที่ 4) ติดตามระยะทางขั้นต่ำที่ไม่เป็นศูนย์

  4. สำหรับจุดสี่จุดใด ๆ (สี่เหลี่ยมจัตุรัสหยาบ) จะค้นหาจุดภายใน

แสดงโซลูชั่น:

A. พูดว่า "Impossible" ถ้ามีจุดภายในหนึ่งจุดขึ้นไป

B. หนึ่งบรรทัด:

  • ในกรณีส่วนใหญ่ของจุดในบรรทัดเดียวโดยไม่มีจุดด้านในให้พูดว่า "เป็นไปได้"

  • ในกรณีที่มีจุดใกล้กับบรรทัดมากเกินไปให้พูดว่า "เป็นไปไม่ได้"

    C. สองบรรทัด:

  • พูดว่า "Possible" เมื่อมีการหมุนเพียงครั้งเดียวที่เป็นไปได้

  • พูดว่า "เป็นไปไม่ได้" เมื่อมีการหมุนมากกว่าหนึ่งครั้ง

    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 (Impossible) ถูกกล่าวว่า "เป็นไปได้ -> 0.000 องศา" โดยสคริปต์ของฉัน ฉันต้องแก้ไข
Mattsteel

ฉันชอบวิธีนี้มาก ไม่ต้องกังวลกับรหัสกอล์ฟมากเกินไปนั่นไม่ใช่ความท้าทายที่แท้จริงและไม่จำเป็นต้องเป็นคนที่จะได้รับรางวัล
Nathan Merrill

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

ข้อผิดพลาดที่สอง: ปลอม "เป็นไปไม่ได้ (ไม่มีบรรทัด) n = 8, m = 6, r = 0 c = 6" ถูกเขียนหลังจากคำตอบที่ถูกต้อง "0,1 0,2 1,0 1,3 2,0 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.