Apakah garis ini melewati kotak itu?

19

Membagi kuadran pertama (termasuk sumbu x positif, sumbu y positif, dan asal) menjadi kisi 1x1, dengan setiap kisi diberi label oleh koordinat sudut kiri bawahnya, seperti yang ditunjukkan di bawah ini:

Perhatikan bahwa setiap kisi berisi batas dan simpulnya. Menggunakan simbol matematika, kotak berlabel (m, n) akan mewakili kuadrat {(x,y) | m ≤ x ≤ m+1, n ≤ y ≤ n+1}.


Diberikan garis lurus dalam bentuk ax+by+c=0dengan bilangan bulat a,, bdan c, dan sebuah kisi yang diwakili oleh (m,n), output apakah garis tersebut melewati kisi, yaitu apakah ada titik pada kisi yang diberikan pada garis tersebut.


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

Harap sarankan lebih banyak testcases di komentar.


Ini adalah . Jawaban terpendek dalam byte menang. Celah standar berlaku.

Biarawati Bocor
sumber
1
Tentu saja kita harus dapat mengasumsikan bahwa bukan a dan b adalah 0, karena jika c adalah nol maka dapat ada garis yang tidak terbatas sedangkan jika c adalah bukan nol tidak ada garis sama sekali.
Erik the Outgolfer
Bisakah saya mendapatkan input sebagai dua atau lebih array, katakan [a, b, c](baris) dan [m, n](kotak)?
Erik the Outgolfer
@EriktheOutgolfer Saya terkejut bahwa tidak ada dalam meta.
Leaky Nun
Terkait
Bukan pohon
Sangat terkait .
Olivier Grégoire

Jawaban:

5

Python 3, 84 66 byte

Golf pertama, kegagalan pertama (mungkin).

Terima kasih kepada Rod untuk mencukur 18 byte dengan menggunakan fungsi alih-alih input langsung.

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

Cobalah online!

Penjelasan:

Pada dasarnya kita menghitung nilai fungsi garis untuk m dan m + 1, jika n adalah di antara nilai-nilai, maka daftar harus melewati itu di beberapa titik. Akan jauh lebih baik jika bahasa memiliki cara yang lebih sederhana untuk memasukkan banyak bilangan bulat.

rusak
sumber
2
Selamat datang di PPCG!
betseg
1
Tidakkah ini perlu diperiksa terhadap n +1 serta m +1?
Neil
3
Pembagian dengan nol saat bini 0.
Olivier Grégoire
Juga, tidak lulus beberapa kasus uji yang disorot oleh Leaky Nun.
Olivier Grégoire
5

Jelly , 10 byte

ż‘{Œpæ.ṠE¬

Cobalah online!

Latar Belakang

Seperti jawaban lain sebelum saya, ini bergantung pada kenyataan bahwa garis lurus membagi pesawat menjadi dua semi-pesawat. Persegi panjang terkandung dalam salah satu dari semi-pesawat ini (tidak ada persimpangan dengan garis) atau memotong kedua semiplane (dan dengan demikian garis yang memisahkannya).

Bagaimana itu bekerja

ż‘{Œ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
sumber
4

Python 2 , 59 byte

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

Cobalah online!

Kita dapat mengetahui sisi mana dari sebuah titik dengan tanda a*x+b*y+c. Garis melewati kotak (menghitung sentuhan) kecuali keempat simpul (m,n),(m,n+1),(m+1,n),(m+1,n+1)benar-benar di sisi yang sama dari garis. Kita bisa pasang nilai-nilai ini di ekstrak keluar konstanta a*m+b*n+cyang muncul di keempat:

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

Jadi, garis melewati kuadrat kecuali keempat nilai ini semuanya positif atau semuanya negatif. Jadi, cukup untuk minimum <=0dan maksimum >=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)

Mengurangi kesamaan a*m+b*n+cdari setiap bagian memberikan kode.

Pendekatan yang sedikit lebih lama adalah untuk memeriksa apakah set tanda (+, 0, -) memiliki panjang setidaknya 2.

Python 2 , 62 byte

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

Cobalah online!

Tidak
sumber
3

Mathematica, 60 55 byte

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

-5 byte byte ke @MartinEnder

formulir input

[a, b, c, m, n]

J42161217
sumber
2
Ah, saya berharap setiap bahasa memiliki Solvefungsi ...
Erik the Outgolfer
3

Batch, 66 byte

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

Penjelasan: Kami mempertimbangkan nilai-nilai yang diambil oleh persamaan di empat sudut sel. Jika garis tidak memotong sel, maka keempat nilai memiliki tanda yang sama, tetapi jika itu memotong sel, maka setidaknya satu nilai akan menjadi nol atau tanda yang berlawanan. Perbandingan disederhanakan dengan mengalikan pasangan sudut yang berlawanan, maka jika kedua nilai positif maka garis tidak memotong sel. Beberapa bit-twiddling kemudian mengubah perkalian menjadi hasil keseluruhan.

Neil
sumber
1

Mathematica, 50 byte

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

Cobalah online!

Diambil m, n, c, a, bsebagai input dalam urutan itu.

Penjelasan: Tuples@{{#,#+1},{#2,#2+1}}buatlah daftar koordinat dari empat sudut alun-alun, kemudian ambil produk titik dengan .{##4}(yang berarti {#4, #5}) dan tambahkan +#3perhitungan ax + by + cuntuk x,ydi setiap sudut. Jika garis melewati titik, ini nol; jika garis lebih jauh dari titik asal, itu negatif; dan jika garis lebih dekat ke titik asal, itu positif - karena itu kami memeriksa Signs dari empat nilai ini. Garis melewati di luar kotak jika dan hanya jika keempat nilai 1 atau keempat adalah -1, jadi kami memeriksa bahwa jumlah mereka benar-benar antara -4 dan 4.

(Jawaban ini agak terinspirasi oleh jawaban saya untuk pertanyaan ini .)

Bukan pohon
sumber
1

Python 2, 147 110 byte

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

Dan terima kasih banyak untuk Leaky Nun!

TIO.

Daniel
sumber
131 bytes
Leaky Nun
121 bytes
Leaky Nun
@ LeakyNun, wow, luar biasa!
Daniel
114 bytes
Leaky Nun
110 bytes
Leaky Nun
1

Python , 54 byte

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

Cobalah online!

(Terima kasih kepada xnor untuk skrip pengujian.)

Bagaimana itu bekerja

Garis melewati m + 1/2 + x , n + 1/2 + y jika dan hanya jika

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

Ini mungkin untuk beberapa | x |, | y | ≤ 1/2 jika dan hanya jika | 2⋅ ( am + bn + c ) + a + b | ≤ | a | + | b |.

Anders Kaseorg
sumber
1

Java (OpenJDK 8) , 71 byte

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

Cobalah online!

Port solusi Python xnor.

Solusi asli, menggunakan persimpangan bentuk / garis Java (108 byte)

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

Cobalah online!

Kredit

Olivier Grégoire
sumber