Dibujar una línea recta

15

Dibuje una imagen de arte ASCII simple que contenga una línea recta. Es similar a esto y a esto pero con especificaciones diferentes.

Entrada

Puede modificar este formato de entrada para adaptarlo a su código.

  • entero width
  • entero height
  • entero x0
  • entero y0
  • entero x1
  • entero y1

Salida

Una imagen artística ASCII rellena del ancho y alto especificados que contiene una línea de píxel (x0, y0)a píxel (x1, y1).

Cualquier forma estándar de salida de texto es aceptable, pero no utilice funciones de dibujo de líneas integradas.

Detalles

La línea se debe dibujar con un solo carácter imprimible (como #), mientras que el fondo se rellena con un carácter diferente (como .). Debe imprimir los caracteres finales necesarios para que el tamaño de la imagen sea correcto.

Las coordenadas de píxel pueden estar indexadas a 0 o indexadas a 1 y pueden comenzar en cualquier esquina de la imagen. La línea debe dibujarse imaginando una línea de subpíxel de ancho 0 que conecta los centros de los píxeles inicial y final. Cada píxel que ingrese la línea debe completarse.

Victorioso

Reglas habituales de código de golf. El código más corto gana.

Ejemplos

IN: width, height, x0, y0, x1, y1

IN: 7, 6, 0, 0, 6, 5
OUT:
.....##
....##.
...##..
..##...
.##....
##.....

IN: 3, 3, 1, 1, 1, 1
OUT:
...
.#.
...

IN: 3, 3, 0, 2, 2, 0
OUT:
#..
.#.
..#

IN: 6, 3, 0, 0, 5, 2
OUT:
....##
.####.
##....

IN: 4, 4, -1, -1, 0, 3
OUT:
#...
#...
#...
....
Curtis Bechtel
fuente
44
Yo diría "Bienvenido a PPCG" pero has estado registrado aquí casi tanto tiempo como yo. :-) ¡Buen primer desafío!
AdmBorkBork
¿Podemos generar puntos reales en lugar de espacios? o cualquier otro personaje que no sean espacios? (suponiendo con todavía incluyendo el trailing <carácter> S)
Rɪᴋᴇʀ
¡Seguro! Haré las ediciones
Curtis Bechtel
1
@AlbertRenshaw En realidad, cuando miro Curve en Wikipedia dice: " En matemáticas, una curva (también llamada línea curva en textos antiguos) es, en general, un objeto similar a una línea pero que no necesita ser recta "; )
Kevin Cruijssen
1
@KevinCruijssen Implica que una línea debe ser recta , ¿no? ;)
Albert Renshaw

Respuestas:

2

Mathematica, 166137 bytes

l:={i,j};s=Sign;f[p_,q_,h_,w_]:=Grid@Table[(1-Max[s[p-l]s[q-l],0])Boole[Abs@Mean[s@Det@{p-l+#,p-q}&/@Tuples[.5{1,-1},2]]<.6],{i,h},{j,w}]

Versión más legible:

l := {i, j}; s = Sign; 
f[p_, q_, h_, w_] := 
 Grid@Table[(1 - Max[s[p - l] s[q - l], 0]) Boole[
     Abs@Mean[
        s@Det@{p - l + #, p - q} & /@ 
         Tuples[.5 {1, -1}, 2]] < .6], {i, h}, {j, w}]

Esto define una función llamada f. Interpreté las especificaciones de entrada y salida de manera bastante liberal. La función ftoma la entrada en el formato f[{x0, y0}, {x1, y1}, height, width], y la cuadrícula está indexada en 1, comenzando en la esquina superior izquierda. Las salidas se ven como

Una salida de muestra

con la línea mostrada como 1 sy el fondo como 0s (se muestra aquí para f[{2, 6}, {4, 2}, 5, 7]). La tarea de convertir una matriz de 1s y 0s de Mathematica en una cadena de #s y. s ya ha sido desarrollada en muchos otros desafíos, por lo que podría usar un método estándar, pero no creo que eso agregue nada interesante.

Explicación:

La idea general es que si la línea pasa por algún píxel, entonces al menos una de las cuatro esquinas del píxel está por encima de la línea, y al menos una está por debajo. Verificamos si una esquina está arriba o debajo de la línea examinando el ángulo entre los vectores ( {x0,y0}a la esquina) y ( {x0,y0}a {x1,y1}): si este ángulo es positivo, la esquina está arriba, y si el ángulo es negativo, la esquina está abajo.

Si tenemos dos vectores {a1,b1}y {a2,b2}, podemos verificar si el ángulo entre ellos es positivo o negativo al encontrar el signo del determinante de la matriz {{a1,b1},{a2,b2}}. (Mi antiguo método de hacer esto usaba la aritmética de números complejos, que era demasiado ... bueno, complejo).

La forma en que esto funciona en el código es la siguiente:

  • {p-l+#,p-q}&/@Tuples[.5{1,-1},2]obtiene los cuatro vectores de {x0,y0}y las cuatro esquinas del píxel (con l:={i,j}, las coordenadas del píxel, definidas anteriormente), y también el vector entre {x0,y0}y {x1,y1}.
  • s@Det@...encuentra los signos de los ángulos entre la línea y las cuatro esquinas (usando s=Sign). Estos serán iguales a -1, 0 o 1.
  • Abs@Mean[...]<.6Comprueba que algunos de los ángulos son positivos y otros negativos. Las 4 tuplas de signos que tienen esta propiedad tienen medias entre -0.5 y 0.5 (inclusive), por lo que comparamos con 0.6 para guardar un byte usando< lugar de <=.

Todavía hay un problema: este código supone que la línea se extiende para siempre en ambas direcciones. Por lo tanto, necesitamos recortar la línea multiplicando por 1-Max[s[p-l]s[q-l],0](encontrado por prueba y error), que está 1dentro del rectángulo definido por los puntos finales de la línea, y 0fuera de ella.

Recortar una línea por un rectángulo

El resto del código forma una cuadrícula de estos píxeles.

(Como beneficio adicional, aquí hay un intento anterior con un método completamente diferente, para 181 bytes :)

Quiet@Grid@Table[(1-Max[Sign[{i,j}-#3]Sign[{i,j}-#4],0])Boole[#3==#4=={i,j}||2Abs@Tr[Cross@@Thread@{{i,j},#3,#4}]/Norm[d=#3-#4]<2^.5Cos@Abs[Pi/4-Mod[ArcTan@@d,Pi/2]]],{i,#},{j,#2}]&
No un arbol
fuente
1
Ahora que ha terminado, ¡hora de almorzar! (A las 6:30 pm ...)
No es un árbol
1

CJam, 122 bytes

{),V>{[I\]E.*A.+}/}:F;l~]2/~@:S~'.*f*\@:A.-_:g:E;:z:D[0=:B{D~I2*)*+:U(2/B/FU2/B/:V;}fID~\:I;F]{_Wf>\S.<+:*},{~_3$=@0tt}/N*

Pruébalo en línea

Básicamente, esto combina dos respuestas que escribí anteriormente para otros desafíos (principalmente los cálculos de la segunda función l).
(0, 0) es, naturalmente, la esquina superior izquierda, no inferior izquierda, como los ejemplos en la declaración.

Visión general:

{),V>{[I\]E.*A.+}/}:F;define función F que ayuda a generar todos los pixeles (pares de coordenadas) para un determinado coordenada x
l~]2/~@:S~'.*f*\@:A.-_:g:E;:z:Dlee y procesa la entrada, y se crea una matriz de puntos
0=:B{D~I2*)*+:U(2/B/FU2/B/:V;}fIitera sobre todas las coordenadas x, excepto la última, y genera todos los píxeles correspondientes
D~\:I;Fhace lo mismo para la última coordenada x
{_Wf>\S.<+:*},mantiene solo los píxeles que deberían aparecer dentro de la imagen
{~_3$=@0tt}/pone un 0 en la matriz para cada píxel se
N*une a la matriz con caracteres de nueva línea para mostrar

aditsu
fuente