Essa linha passa por esse quadrado?

19

Divida o primeiro quadrante (incluindo o eixo x positivo, o eixo y positivo e a origem) em grades 1x1, com cada grade rotulada pelas coordenadas do canto inferior esquerdo, conforme demonstrado abaixo:

Observe que cada grade contém seus limites e seus vértices. Usando símbolos matemáticos, a grade rotulada (m, n) representaria o quadrado {(x,y) | m ≤ x ≤ m+1, n ≤ y ≤ n+1}.


Dada uma linha recta, na forma de ax+by+c=0com números inteiros a, be c, e uma grade representada por (m,n), a saída se a linha passa através da grade, ou seja, se qualquer ponto da grelha é determinado na linha.


a  b  c m n output
1  1  0 0 0 true
1  1  0 1 1 false
1  1  0 0 2 false
1  1 -3 0 1 true
1  1 -3 0 0 false
2 -1  0 1 1 true
2 -1  0 1 0 false
2 -1  0 0 2 true
2 -1  0 0 1 true
2 -1  0 1 2 true
2  0 -1 0 0 true
2  0 -1 0 1 true
2  0 -1 0 2 true
2  0 -1 1 0 false
2  0 -1 1 1 false
0  2 -1 0 0 true
0  2 -1 1 0 true
0  2 -1 2 0 true
0  2 -1 0 1 false
0  2 -1 1 1 false
1  0 -1 0 0 true
1  0 -1 0 1 true
1  0 -1 0 2 true
1  0 -1 1 0 true
1  0 -1 1 1 true

Por favor, sugira mais casos de teste nos comentários.


Isso é . A resposta mais curta em bytes vence. Aplicam-se brechas padrão .

Freira Furada
fonte
1
É claro que devemos assumir que nem a e b são 0, pois, se c é zero, pode haver infinitas linhas, enquanto que c é diferente de zero, não pode haver nenhuma linha.
Erik the Outgolfer
Posso obter entrada como duas ou mais matrizes, digamos [a, b, c](a linha) e [m, n](o quadrado)?
Erik the Outgolfer
@EriktheOutgolfer Estou surpreso que não esteja na meta.
Leaky Nun
Related
Not a tree
Fortemente relacionado .
Olivier Grégoire

Respostas:

5

Python 3, 84 66 bytes

Primeiro golfe, primeiro fracasso (talvez).

Agradecimentos a Rod por remover 18 bytes usando uma função em vez de entrada direta.

def f(a,b,c,m,n):f=-(a*m+c)/b;g=f-a/b;print(min(f,g)<=n<=max(f,g))

Experimente online!

Explicação:

Basicamente, calculamos o valor da função de linha para m e m + 1, se n estiver entre os valores, a lista deve passar por ela em algum momento. Seria muito melhor se o idioma tivesse uma maneira mais simples de inserir vários números inteiros.

irapsaged
fonte
2
Bem-vindo ao PPCG!
betseg
1
Isso não precisa ser verificado contra n + 1 e m + 1?
Neil
3
Divisão por zero quando bé 0.
Olivier Grégoire
Além disso, ele não passa em vários casos de teste destacados por Leaky Nun.
Olivier Grégoire
5

Gelatina , 10 bytes

ż‘{Œpæ.ṠE¬

Experimente online!

fundo

Como outras respostas anteriores às minhas, isso se baseia no fato de que uma linha reta divide o plano em dois semiplanos. O retângulo está contido em um desses semiplanos (sem interseção com a linha) ou cruza os dois semiplanos (e, portanto, a linha que os separa).

Como funciona

ż‘{Œpæ.ṠE¬  Main link. Left argument: [m, n]. Right argument: [a, b, c]

 ‘{         Increment left; yield [m+1, n+1].
ż           Zipwith; yield [[m, m+1], [n, n+1]].
   Œp       Cartesian product; yield [[m, n], [m, n+1], [m+1, n], [m+1, n+1]].
     æ.     Take the dot products with [a, b, c], mapping each [x, y] to ax+by+c.
       Ṡ    Take the signs.
        E   Test the signs for equality.
         ¬  Logical NOT.
Dennis
fonte
4

Python 2 , 59 bytes

lambda a,b,c,m,n:min(0,a,b,a+b)<=-a*m-b*n-c<=max(0,a,b,a+b)

Experimente online!

Podemos dizer de que lado da linha um ponto está pelo sinal de a*x+b*y+c. A linha passa pelo quadrado (contando com o toque), a menos que todos os quatro vértices (m,n),(m,n+1),(m+1,n),(m+1,n+1)estejam estritamente no mesmo lado da linha. Podemos inserir esses valores em um extrato da constante a*m+b*n+cque aparece nos quatro:

a*m+b*n+c
a*m+b*n+c+a
a*m+b*n+c+b
a*m+b*n+c+a+b

Portanto, a linha passa pelo quadrado, a menos que esses quatro valores sejam todos positivos ou negativos. Portanto, basta que o mínimo seja <=0e o máximo seja >=0.

min(a*m+b*n+c,a*m+b*n+c+a,a*m+b*n+c+b,a*m+b*n+c+a+b)<=0<=max(a*m+b*n+c,a*m+b*n+c+a,a*m+b*n+c+b,a*m+b*n+c+a+b)

Subtrair o comum a*m+b*n+cde cada parte fornece o código.

Uma abordagem um pouco mais longa é verificar se o conjunto de sinais (+, 0, -) tem comprimento pelo menos 2.

Python 2 , 62 bytes

lambda a,b,c,m,n:len({cmp(a*m+b*n+c,-d)for d in(0,a,b,a+b)})>1

Experimente online!

xnor
fonte
3

Mathematica, 60 55 bytes

Solve[m#+n#2==-#3&&#4<=m<=#4+1&&#5<=n<=#5+1,{m,n}]!={}&

-5 bytes thanx a @MartinEnder

formulário de entrada

[a, b, c, m, n]

J42161217
fonte
2
Ah, eu gostaria que todos os idiomas tivessem uma Solvefunção ...
Erik the Outgolfer
3

Lote, 66 bytes

@cmd/cset/a"q=%1*%4+%2*%5+%3,((-(q+%1)*(q+%2)&-q*(q+%1+%2))>>31)+1

Explicação: Consideramos os valores tomados pela equação nos quatro cantos da célula. Se a linha não cruzar a célula, todos os quatro valores terão o mesmo sinal, mas se cruzar a célula, pelo menos um valor será zero ou o sinal oposto. A comparação é simplificada multiplicando pares de cantos opostos; se ambos os valores forem positivos, a linha não cruza a célula. Alguns ajustes de bits convertem as multiplicações em um resultado geral.

Neil
fonte
1

Mathematica, 50 bytes

-4<Tr@Sign[Tuples@{{#,#+1},{#2,#2+1}}.{##4}+#3]<4&

Experimente online!

Toma m, n, c, a, bcomo entrada nessa ordem.

Explicação: Tuples@{{#,#+1},{#2,#2+1}}faz uma lista das coordenadas dos quatro cantos do quadrado e, em seguida, pega o produto escalar com .{##4}(o que significa {#4, #5}) e adiciona os +#3cálculos ax + by + cpara x,ycada canto. Se a linha passa pelo ponto, é zero; se a linha está mais distante da origem, é negativa; e se a linha estiver mais próxima da origem, é positivo - portanto, verificamos os Signs desses quatro valores. A linha passa para fora do quadrado se e somente se todos os quatro valores forem 1 ou todos os quatro forem -1, então verificamos se a soma deles é estritamente entre -4 e 4.

(Esta resposta é vagamente inspirada pela minha resposta a esta pergunta .)

Não é uma árvore
fonte
1

Python 2, 147 110 bytes

def f(a,b,c,m,n):
 if b:d=sorted((-a*x-c)/float(b)for x in(m,m+1));return d[0]-1<=n<=d[1]
 return m<=-c/a<=m+1

E um enorme agradecimento à Leaky Nun!

TIO.

Daniel
fonte
131 bytes
Freira vazada
121 bytes
Freira vazada
@LeakyNun, uau incrível!
Daniel
114 bytes
Freira vazada
110 bytes
Freira vazada
1

Python , 54 bytes

lambda a,b,c,m,n:abs(2*(a*m+b*n+c)+a+b)<=abs(a)+abs(b)

Experimente online!

(Obrigado ao xnor pelo script de teste.)

Como funciona

A linha passa por m + 1/2 + x , n + 1/2 + y se e somente se

a ⋅ ( m + 1/2 + x ) + b ⋅ ( n + 1/2 + y ) + c = 0
⇔ 2⋅ ( am + bn + c ) + a + b = −2⋅ ax - 2⋅ by .

Isso é possível para alguns | x |, | y | ≤ 1/2 se e somente se | 2⋅ ( am + bn + c ) + a + b | ≤ | a | + | b |.

Anders Kaseorg
fonte
1

Java (OpenJDK 8) , 71 bytes

(a,b,c,x,y)->(0<a?0:a)+(0<b?0:b)<=(x=-a*x-b*y-c)&x<=(0>a?0:a)+(0>b?0:b)

Experimente online!

Porta da solução Python do xnor.

Solução original, usando a interseção de forma / linha de Java incorporada (108 bytes)

(a,b,c,x,y)->b==0?x<=-c/a&-c/a<=x+1:new java.awt.Rectangle(x,y,1,1).intersectsLine(x,c=(c+a*x)/-b,x+1,c-a/b)

Experimente online!

Créditos

Olivier Grégoire
fonte