Déterminer la rotation du carré à partir d'une liste de points

19

Dans ce défi, vous recevrez une liste de points. Ces points se situent sur le périmètre d'un carré imaginaire . Votre objectif est de:

  1. Si possible, imprimez la rotation du carré, qui sera une valeur de [0, 90) où 0 représente un carré avec des lignes verticales et horizontales. La rotation doit être donnée en degrés comptés dans le sens antihoraire.
  2. Si la rotation du carré est ambiguë (par exemple ne recevoir que 2 points), imprimez "Inconnu"
  3. Si la création d'un carré étant donné les points est impossible, imprimez "Impossible"

Les points qui vous sont attribués sont garantis uniques et sans ordre particulier. Vous pouvez utiliser n'importe quel format pour entrer la liste, mais pour mes exemples, mes points seront au format x,yet séparés par des espaces. Les nombres sont des nombres à virgule flottante, et vous pouvez supposer qu'ils se situent dans une plage que votre langue peut gérer. Votre sortie doit être précise à au moins 3 décimales et supposer que votre langue gère les nombres à virgule flottante avec une précision parfaite.

Voici quelques cas de test (j'ai fait la plupart de ceux-ci en utilisant des nombres entiers pour une visualisation facile, mais votre programme devrait gérer les virgules flottantes):

Inconnue:

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 (si non désigné, doit retourner 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 

J'ai peut-être raté des cas de test intéressants. Si oui, veuillez commenter pour les ajouter.

C'est le code-golf, donc le code le plus court gagne!

Nathan Merrill
la source
Existe-t-il une précision minimale requise? À quelle distance de la bonne réponse la sortie peut-elle être avant qu'elle ne soit considérée comme fausse?
trichoplax
@trichoplax être aussi précis que l'implémentation de votre nombre de virgule flottante dans votre langue.
Nathan Merrill
Est-ce à dire que s'il y a 2 approches possibles et que l'une donne un résultat légèrement plus précis dans votre langue, l'approche la plus précise doit être utilisée?
trichoplax
@trichoplax oui.
Nathan Merrill
2
@NathanMerrill Comment vais-je (ou quiconque) savoir s'il existe une approche plus précise? Je pense qu'il serait plus logique d'exiger simplement une précision minimale fixe, comme 4 ou 6 décimales. Bien que je ne sois même pas sûr que les inexactitudes de la représentation en virgule flottante de l'entrée rendent de nombreux exemples impossibles. Peut-être qu'une entrée rationnelle ou entière aurait été meilleure pour cela.
Martin Ender

Réponses:

6

Rév.1: Ruby, 354 octets

continuer à jouer au golf grâce à 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'}

Rubis, 392 octets

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

L'algorithme est le suivant:

-Choisissez un point arbitraire (le premier) et déplacez-le à l'origine (soustrayez les coordonnées de ce point de tous les points de la liste.)

-Essayez toutes les rotations du carré autour de l'origine par incréments de 0,001 degré, jusqu'à 360 degrés.

-Pour une rotation donnée, si tous les points sont au-dessus de l'axe y, dessinez le plus petit carré possible autour de tous les points, en incorporant le point le plus bas et le plus à gauche.

-Vérifiez si tous les points sont sur le bord. Cela se fait avec un calcul doux qui prend chaque point, trouve les distances au carré de tous les bords et les multiplie ensemble. Cela donne un bon ajustement plutôt qu'une réponse oui / non. Il est interprété qu'une solution est trouvée si ce produit divisé par la longueur latérale ^ 8 est inférieur à 1E-9. En pratique, c'est moins qu'un degré de tolérance.

-Le meilleur ajustement est pris à 90 degrés et indiqué comme l'angle correct.

Actuellement, le code renvoie une valeur ambiguë si plus de 100 solutions sont trouvées (à une résolution de 0,001 degré. C'est 0,1 degré de tolérance.)

première fonction pleinement opérationnelle, dans le programme de test

J'ai laissé la résolution au 1 / 10e de la résolution requise pour rendre la vitesse raisonnable. Il y a une erreur de 0,01 dégressivité sur le tout dernier cas de test.

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

la version golfée, résolution conforme aux spécifications, prend environ une minute par appel, dans le programme de test.

Il y a toujours une erreur embêtante de 0,001 degrés sur le dernier cas de test. Augmenter encore la résolution l'éliminerait probablement.

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

Notez que pour environ 30% de code en plus, cet algorithme pourrait être adapté pour fonctionner rapidement: il est évident que dans les cas avec un nombre fini de solutions, l'un des bords se trouve à plat le long d'un cube, donc tout ce que nous devons vraiment essayer est ces angles qui correspondent à chaque paire de sommets. Il serait également nécessaire de faire un peu de tortillement pour vérifier qu'il n'y a pas une infinité de solutions.

Level River St
la source
J'ai corrigé le deuxième cas de test, merci
Nathan Merrill
@NathanMerrill le cas révisé 0,0 1,0 2,0 1,2est toujours possible pour un carré de diagonale 0,0 ... 2,2. J'ai essayé cela, et aussi 0,0 1,0 2,0 1,1(ce dernier est en effet impossible.) Un autre point: considérez-vous acceptable ou inacceptable que mon code retourne impossible plutôt qu'inconnu quand un seul point est donné? J'apprécierais une réponse avant de commencer à jouer au golf.
Level River St
Je voulais faire 1,1. Je ne sais pas comment 1,2on y est arrivé. Ce n'est pas acceptable.
Nathan Merrill
Vous devriez pouvoir le réduire à au moins 354 octets comme ceci: pastebin.com/jsgwMKQF
blutorange
@blutorange merci pour les conseils! Je suis nouveau à Ruby et j'ai quelques difficultés à jouer au golf. J'ai laissé beaucoup de if..ends car j'ai de gros problèmes avec les opérateurs ternaires imbriqués dans Ruby. Je vois que vous avez contourné cela en utilisant &&.
Level River St
6

Perl

Bonjour, voici mon humble soution. Les cas de test sont placés dans le flux de données au bas du fichier. L'algorithme s'est développé grâce à une approche par erreur.
J'avoue que c'est une approche globalement heuristique, mais elle est vraiment rapide: elle résout tous les cas instantanément .
Je suis conscient qu'il y aura quelques bugs, mais jusqu'à présent, il donne des réponses correctes à tous les cas de test.
Je suis également conscient que le code le plus court l' emporte, mais je suis sûr que c'est l'un des plus courts au sens le plus rapide du terme.

Voici l'algorithme

  1. examiner les points et pour chaque segment entre deux points enregistrer la pente, la longueur, l'ordonnée à l'origine, l'ordonnée à l'origine

  2. trouver des lignes droites (c'est-à-dire trois points ou deux segments adjacents) et des pentes possibles distinctes (disons les rotations). Gardez une trace du segment le plus long disponible sur chaque ligne.

  3. trouver toutes les distances entre un segment et un troisième point (cela devrait être utilisé pour le point 4). Gardez une trace de la distance minimale non nulle.

  4. pour quatre points quelconques (grossièrement un rectangle) trouver des points intérieurs

Afficher les solutions:

A. Dites «impossible» s'il y a un ou plusieurs points intérieurs.

B. Une ligne:

  • Dans le cas de la plupart des points sur une seule ligne sans points intérieurs, dites "Possible"

  • En cas de points trop proches de la ligne, dites "Impossible"

    C. Deux lignes:

  • Dites «Possible» lorsqu'il n'y a qu'une seule rotation possible

  • Dites «impossible» lorsqu'il y a plus d'une rotation

    D. Pas de lignes: trouvez une rotation qui correspond à son segment de rotation à 90 °

  • Dites «Possible» si un seul ajustement ou autant de points conviennent.

  • Dites «impossible» si plus d'un correspond et pas autant que de points

  • Dites «inconnu» si le nombre de rotations convient.

Voici le code (tous les bugs connus sont résolus)

#!/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

Et voici son 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

Cordialement.

Matteo.

Mattsteel
la source
Voici le premier bug: votre cas 0,0 1,0 2,0 1,1 (Impossible) est dit "Possible. -> 0,000 deg" par mon script. Je dois réparer
Mattsteel
J'aime vraiment cette solution. Ne vous inquiétez pas trop du code golf, ce n'est pas vraiment le défi et ce n'est pas nécessairement la personne qui recevra la prime.
Nathan Merrill
Merci Nathan.La sortie montre beaucoup plus d'informations: ce sont à des fins de débogage et je les ai laissées intentionnellement pour pouvoir les corriger
Mattsteel
Deuxième bug: un faux "Impossible. (Pas de lignes) n = 8, m = 6, r = 0 c = 6" est écrit juste après la bonne réponse "0,1 0,2 1,0 1,3 2,0 2,3 3,1 3,2: Inconnu. (Pas de lignes) n = 8, m = 6, r = 0 c = 6 ".
Mattsteel
Deux bugs corrigés: tous les cas fonctionnent désormais correctement.
Mattsteel