Desenhar uma linha reta

15

Desenhe uma imagem artística ASCII simples que contenha uma linha reta. É semelhante a isso e isso, mas com especificações diferentes.

Entrada

Você pode modificar esse formato de entrada para se adequar ao seu código.

  • inteiro width
  • inteiro height
  • inteiro x0
  • inteiro y0
  • inteiro x1
  • inteiro y1

Resultado

Uma imagem de arte ASCII preenchida da largura e altura especificadas contendo uma linha de pixel (x0, y0)a pixel (x1, y1).

Qualquer forma padrão de saída de texto é aceitável, mas não use funções de desenho de linha integradas.

Detalhes

A linha deve ser desenhada usando um único caractere imprimível (como #), enquanto o fundo é preenchido com um caractere diferente (como .). Você deve imprimir os caracteres finais necessários para que o tamanho da imagem esteja correto.

As coordenadas de pixel podem ser indexadas em 0 ou 1 e podem começar em qualquer canto da imagem. A linha deve ser desenhada imaginando uma linha de sub-pixel de largura 0 conectando os centros dos pixels inicial e final. Todo pixel inserido pela linha deve ser preenchido.

Ganhando

Regras usuais de código-golfe. O menor código vence.

Exemplos

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
fonte
4
Eu diria "Bem-vindo ao PPCG", mas você está registrado aqui há quase tanto tempo quanto eu. :-) Bom primeiro desafio!
AdmBorkBork
Podemos produzir pontos reais em vez de espaços? ou qualquer outro personagem além de espaços? (supondo que ainda inclua os <caractere) à direita)
#
Certo! Vou fazer as edições
Curtis Bechtel
1
@AlbertRenshaw Na verdade, quando olho para o Curve na Wikipedia, ele afirma: " Em matemática, uma curva (também chamada de linha curva em textos antigos) é, em geral, um objeto semelhante a uma linha, mas que não precisa ser reto. "; )
Kevin Cruijssen
1
@KevinCruijssen Implica que uma linha precisa ser reta , não? ;)
Albert Renshaw

Respostas:

2

Mathematica, 166 137 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}]

Versão mais legível:

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

Isso define uma função chamada f. Interpretei as especificações de entrada e saída de maneira bastante liberal. A função frecebe entrada no formato f[{x0, y0}, {x1, y1}, height, width]e a grade é indexada em 1, começando no canto superior esquerdo. As saídas parecem

Uma saída de amostra

com a linha exibida como se 1o fundo como 0s (mostrado aqui para f[{2, 6}, {4, 2}, 5, 7]). A tarefa de transformar uma matriz de 1s e 0s do Mathematica em uma série de #s e .s foi disputada em muitos outros desafios antes, então eu poderia apenas usar um método padrão, mas acho que isso não acrescenta nada de interessante.

Explicação:

A ideia geral é que, se a linha passar por algum pixel, pelo menos um dos quatro cantos do pixel estará acima da linha e pelo menos um estará abaixo. Verificamos se um canto está acima ou abaixo da linha, examinando o ângulo entre os vetores ( {x0,y0}para o canto) e ( {x0,y0}para {x1,y1}): se esse ângulo é positivo, o canto está acima e se o ângulo é negativo, o canto está abaixo.

Se temos dois vetores {a1,b1}e {a2,b2}, podemos verificar se o ângulo entre eles é positivo ou negativo, encontrando o sinal do determinante da matriz {{a1,b1},{a2,b2}}. (Meu antigo método de fazer isso usava aritmética de números complexos, o que era muito ... bem, complexo.)

A maneira como isso funciona no código é a seguinte:

  • {p-l+#,p-q}&/@Tuples[.5{1,-1},2]obtém os quatro vetores {x0,y0}e os quatro cantos do pixel (com l:={i,j}, as coordenadas do pixel, definidas anteriormente) e também o vetor entre {x0,y0}e {x1,y1}.
  • s@Det@...encontra os sinais dos ângulos entre a linha e os quatro cantos (usando s=Sign). Estes serão iguais a -1, 0 ou 1.
  • Abs@Mean[...]<.6verifica se alguns dos ângulos são positivos e outros negativos. As quatro tuplas de sinais que possuem essa propriedade têm médias entre -0,5 e 0,5 (inclusive), portanto, comparamos com 0,6 para salvar um byte usando em <vez de <=.

Ainda existe um problema: esse código pressupõe que a linha se estenda para sempre nas duas direções. Portanto, precisamos cortar a linha multiplicando por 1-Max[s[p-l]s[q-l],0](encontrada por tentativa e erro), que está 1dentro do retângulo definido pelos pontos finais da linha e 0fora dela.

Cortando uma linha por um retângulo

O restante do código cria uma grade desses pixels.

(Como bônus, eis uma tentativa anterior com um 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}]&
Não é uma árvore
fonte
1
Agora que terminou, hora do almoço! (Às 18:30…)
Não é uma árvore
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*

Experimente online

Isso basicamente combina duas respostas que eu escrevi anteriormente para outros desafios (principalmente os cálculos do segundo - funçãol ).
(0, 0) é, naturalmente, o canto superior esquerdo, não o inferior esquerdo, como nos exemplos da declaração.

Visão geral:

{),V>{[I\]E.*A.+}/}:F;define a função F que ajuda a gerar todos os pixels (pares de coordenadas) para uma determinada coordenada x
l~]2/~@:S~'.*f*\@:A.-_:g:E;:z:Dlê e processa a entrada, e cria uma matriz de pontos que
0=:B{D~I2*)*+:U(2/B/FU2/B/:V;}fIitera sobre todas as coordenadas x, exceto a última, e gera todos os pixels correspondentes
D~\:I;Ffaz o mesmo para a última coordenada x
{_Wf>\S.<+:*},mantém apenas os pixels que devem aparecer dentro da imagem
{~_3$=@0tt}/coloca um 0 na matriz para cada pixel que
N*se une à matriz com caracteres de nova linha para exibição

aditsu
fonte