A pergunta mudou, portanto, esta resposta contém versões diferentes, com e sem um caminho fechado.
Perl, caminho aberto, 69 bytes
print"@$_$/"for sort{$$a[0]<=>$$b[0]||$$a[1]<=>$$b[1]}map{[/\S+/g]}<>
Cada ponto é esperado em STDIN como linha, com as coordenadas separadas por espaço em branco.
Qualquer formato numérico é suportado pelo Perl como número (incluindo números de ponto flutuante).
Exemplo:
0 0
4 4
0 4
4 0
-2 1
2 -2
2 4
3.21 .56
.035e2 -7.8
0 2
Resultado:
-2 1
0 0
0 2
0 4
2 -2
2 4
3.21 .56
.035e2 -7.8
4 0
4 4
Ungolfed:
print "@$_$/" for # print output line
sort { # sort function for two points $a and $b
$$a[0] <=> $$b[0] # compare x part
|| $$a[1] <=> $$b[1] # compare y part, if x parts are identical
}
map { [/\S+/g] } # convert input line to point as array reference
<> # read input lines
Variantes de circuito
Na versão da primeira pergunta, havia uma conexão entre o último e o primeiro ponto para fazer um circuito.
Centro não existe ponto, 253 bytes
Essa variante pode falhar, se o centro for um dos pontos, veja o exemplo 3.
Editar% s:
Em sua resposta, swish notou que os pontos devem estar centrados em torno da origem para garantir um circuito sem cruzamentos:
- A classificação precisa de coordenadas transformadas.
- A representação original da sequência dos números precisa ser mantida para a saída.
Correção de bug: o caso especial do eixo x negativo incluía o eixo x positivo.
print"$$_[2] $$_[3]$/"for sort{($X,$Y)=@$a;($x,$y)=@$b;(!$X&&!$Y?-1:0)||!$x&&!$y||!$Y&&!$y&&$X<0&&$x<0&&$X<=>$x||atan2($Y,$X)<=>atan2($y,$x)||$X**2+$Y**2<=>$x**2+$y**2}map{[$$_[0]-$M/$n,$$_[1]-$N/$n,@$_]}map{$n++;$M+=$$_[0];$N+=$$_[1];$_}map{[/\S+/g]}<>
Exemplo 1:
4 4
-2 0
2 0
1 1
4 0
-2 -2
-3 -1
1 -2
3 0
2 -4
0 0
-1 -2
3 3
-3 0
2 3
-5 1
-6 -1
Saída 1:
0 0
-6 -1
-3 -1
-2 -2
-1 -2
1 -2
2 -4
2 0
3 0
4 0
1 1
3 3
4 4
2 3
-5 1
-3 0
-2 0
Exemplo 2:
Teste de representação numérica e transformação de coordenadas.
.9e1 9
7 7.0
8.5 06
7.77 9.45
Saída 2:
7 7.0
8.5 06
.9e1 9
7.77 9.45
Ungolfed:
print "$$_[2] $$_[3]$/" for sort { # print sorted points
($X, $Y) = @$a; # ($X, $Y) is first point $a
($x, $y) = @$b; # ($x, $y) is second point $b
(!$X && !$Y ? -1 : 0) || # origin comes first, test for $a
!$x && !$y || # origin comes first, test for $b
!$Y && !$y && $X < 0 && $x < 0 && $X <=> $x ||
# points on the negative x-axis are sorted in reverse order
atan2($Y, $X) <=> atan2($y, $x) ||
# sort by angles; the slope y/x would be an alternative,
# then the x-axis needs special treatment
$X**2 + $Y**2 <=> $x**2 + $y**2
# the (quadratic) length is the final sort criteria
}
map { [ # make tuple with transformed and original coordinates
# the center ($M/$n, $N/$n) is the new origin
$$_[0] - $M/$n, # transformed x value
$$_[1] - $N/$n, # transformed y value
@$_ # original coordinates
] }
map {
$n++; # $n is number of points
$M += $$_[0]; # $M is sum of x values
$N += $$_[1]; # $N is sum of y values
$_ # pass orignal coordinates through
}
map { # make tuple with point coordinates
[ /\S+/g ] # from non-whitespace in input line
}
<> # read input lines
Sem restrição, 325 bytes
print"$$_[2] $$_[3]$/"for sort{($X,$Y)=@$a;($x,$y)=@$b;atan2($Y,$X)<=>atan2($y,$x)||$X**2+$Y**2<=>$x**2+$y**2}map{[$$_[0]-$O/9,$$_[1]-$P/9,$$_[2],$$_[3]]}map{$O=$$_[0]if$$_[0]>0&&($O>$$_[0]||!$O);$P=$$_[1]if$$_[1]>0&&($P>$$_[1]||!$P);[@$_]}map{[$$_[0]-$M/$n,$$_[1]-$N/$n,@$_]}map{$n++;$M+=$$_[0];$N+=$$_[1];$_}map{[/\S+/g]}<>
Na versão anterior, o centro é colocado no início e os últimos pontos no eixo negativo são classificados na ordem inversa para obter novamente a cruz para o centro. No entanto, isso não é suficiente, porque os últimos pontos podem estar em uma linha diferente. Portanto, o exemplo 3 a seguir falharia.
Isso é corrigido movendo a origem centralizada um pouco para cima e para a direita. Por causa da centralização, deve haver pelo menos um ponto com valor x positivo e um ponto com valor y positivo. Assim, os mínimos dos valores positivos de x e y são tomados e reduzidos a um nono (metade ou terceiro pode ser suficiente). Este ponto não pode ser um dos pontos existentes e é feita a nova origem.
Os tratamentos especiais da origem e o eixo x negativo podem ser removidos, porque existe algum ponto na nova origem.
Exemplo 3:
-2 -2
-1 -1
-2 2
-1 1
2 -2
1 -1
2 2
1 1
0 0
Saída 3:
0 0
-1 -1
-2 -2
1 -1
2 -2
1 1
2 2
-2 2
-1 1
O exemplo 1 agora está classificado de maneira diferente:
Ungolfed:
print "$$_[2] $$_[3]$/" for sort { # print sorted points
($X, $Y) = @$a; # ($X, $Y) is first point $a
($x, $y) = @$b; # ($x, $y) is second point $b
atan2($Y, $X) <=> atan2($y, $x) ||
# sort by angles; the slope y/x would be an alternative,
# then the x-axis needs special treatment
$X**2 + $Y**2 <=> $x**2 + $y**2
# the (quadratic) length is the final sort criteria
}
map { [ # make tuple with transformed coordinates
$$_[0] - $O/9, $$_[1] - $P/9, # new transformed coordinate
$$_[2], $$_[3] # keep original coordinate
] }
map {
# get the minimum positive x and y values
$O = $$_[0] if $$_[0] > 0 && ($O > $$_[0] || !$O);
$P = $$_[1] if $$_[1] > 0 && ($P > $$_[1] || !$P);
[ @$_ ] # pass tuple through
}
map { [ # make tuple with transformed and original coordinates
# the center ($M/$n, $N/$n) is the new origin
$$_[0] - $M/$n, # transformed x value
$$_[1] - $N/$n, # transformed y value
@$_ # original coordinates
] }
map {
$n++; # $n is number of points
$M += $$_[0]; # $M is sum of x values
$N += $$_[1]; # $N is sum of y values
$_ # pass orignal coordinates through
}
map { # make tuple with point coordinates
[ /\S+/g ] # from non-whitespace in input line
}
<> # read input lines