Üçgen zırhlılar (Hesaplamalı geometri problemi)


18

Bir savaş gemisinin kaptanısın. Mühendislik departmanı bu yıl tasarımlarla köşeleri kesiyor, bu yüzden bulunduğunuz gemi basit bir üçgen şeklini alıyor.

Güvertede yürümek ve deniz meltemi tadını çıkarın ... ama uzun süre olmasa da. Bir düşman sana ateş etti! - ama atış vurulacak mı?

Giriş

Bu zorluk için bir işlev veya tam bir program yazabilirsiniz.

Programınız on tanesi eşleştirilmiş 11 tamsayı alacak:

  • İlk üç çift tam sayı (x 1 , y 1 ), (x 2 , y 2 ), (x 3 , y 3 ) geminizin köşe noktalarını belirtir. Oluşan üçgen sıfır olmayan bir alana sahip olacaktır.

  • Bir sonraki tamsayı çifti (e x , e y ) düşmanın topunun yerini belirtir. Düşman topu asla geminizin üzerinde veya geminizin sınırları içinde uzanmayacaktır. *

  • Bundan sonraki çift (a x , a y ) düşmanın nereye nişan aldığını belirtir. Bu (e x , e y ) ' den farklı olacaktır .

  • Son pozitif tamsayı R, düşmanın atış aralığını belirtir

* Bunun olduğunu fark etmemiş olsaydın korkunç bir kaptan olurdun!

Çıktı

Eğer zırhlıya çarpılacaksa , doğruluk değeri (örn. Doğru, 1) yazmalısınız / iade etmelisiniz , aksi takdirde sahte bir değer (örn. Yanlış, 0).

İsabet nedir?

Düşman atış, (e x , e y ) 'den (a x , a y ) yönünde R uzunluğunda düz bir çizgi segmentidir . Bu çizgi segmenti, üçgen savaş geminizin , bu bir isabet olarak sayılır. Aksi takdirde isabet değildir.

Üçgenin sınırına kadar otlayan veya sadece sınıra ulaşan atışlar isabet sayılmaz.

Örnekler

0 0 0 1 1 0
1 1
0 0
2

test1

Vuruş: Düşman geminizin ortasından ateş etti!


2 0 0 2 4 4
0 0
1 1
1

dnm2

İsabet yok: Düşmanın menzili çok kısa, güvendesiniz.


0 0 1 2 3 0
-4 0
0 0
8

test3

İsabet yok: Düşman geminizin yanını sıyırdı, bu yüzden bu bir isabet sayılmaz. Şanslı!


0 0 -1 3 4 -1
-3 -4
3 4
5

test4

İsabet yok: Düşman vuruşu geminin hemen önünde durur, böylece güvendesiniz. Düşmanın topu biraz daha iyi menzile sahip olsaydı, o zaman vurulurdunuz! Uf!


-2 -3 -3 6 7 -2
-6 2
1 -4
7

test5

İsabet: Atış diğer tarafa nüfuz etmese de, bu hala bir isabet.


-3 2 2 -4 7 -3
-3 -4
-3 0
10

test6

İsabet yok: Kayıt için bu başka bir yakın özledim.


Ek test senaryoları

0 0 6 0 6 8
-6 -8
6 8
20

test7

İsabet yok: Bu bir başka otlatmadır, ancak bir açıyla.


0 0 -2 -5 5 3
-3 4
0 0
6

test8

Hit: Atış geminin bir tepe noktası üzerinden girildi.

puanlama

Bu , bu yüzden bayttaki en kısa kod kazanır. Standart boşluklar geçerlidir.


Sadece yapamayacağımızdan emin olmak için: geminin dibine sahip olmadığını ve her iki taraf arasında küçük bir boşluk olduğunu varsayabilir miyiz, böylece atış gemiye köşesinden girmeyi başarırsa, onu bir bayan olarak sayabilir miyiz?
John Dvorak

@ JanDvorak Eğer bir atış bir tepe noktasından girerek gemiyi keserse, o zaman bu isabet olurdu çünkü hat segmenti geminin içiyle örtüşüyor. Dördüncü örnekte, aralık 5'ten büyük olsaydı, bu bir hit olurdu.
Sp3000

Argümanlarla ne kadar oynamamıza izin verilir? Onları gruplandırmamıza, sıralamayı değiştirmemize veya yüzdürülmelerini istememize izin var mı?
FryAmTheEggman

@FryAmTheEggman Argümanları gerektiği gibi gruplandırabilir veya yeniden sıralayabilirsiniz. Şamandıralar kullanabilirsiniz, ancak programın hassasiyet konusunda endişelenmeden küçük ızgaralar (örneğin 20x20'ye kadar) için doğru çalışması gerekir.
Sp3000

Örneklerin, amaçlanan çözümümü başarısız kılan önemli bir vakası eksik olduğunu düşünüyorum: örneğin geminin bir köşeden içeri girmesi 0 0 -1 3 4 -1 -3 -4 3 4 6.
nutki

Yanıtlar:


3

Python 3, 252 bayt

Bu kesinlikle kod golf hiç kullandığım en değişkenleri. : ^ P

from math import*;A=atan2
def h(a,b,c,d,e,f,g,h,i,j,R):
 r=R;_=0
 while r>0:Q=A(j-h,i-g);k,l=g+r*cos(Q),h+r*sin(Q);D=A(d-b,c-a);E=A(f-b,e-a);F=A(l-b,k-a);G=A(b-d,a-c);H=A(f-d,e-c);I=A(l-d,k-c);_=_ or(D<F<E or E<F<D)and(G<I<H or H<I<G);r-=.001
 return _

Hafifçe ungolfed, yorumlarla:

from math import*
# Parameters:
#  (a,b) (c,d) (e,f) - vertices of the triangle
#  (g,h) - location of cannon
#  (i,j) - aim of cannon
#  R - range of cannon
# Variables within function:
#  _ - was this shot a hit?
#  r - distance 0 < r <= R that we're testing
#  Q - angle between cannon source and destination
#  (k,l) - point that we're testing
#  D,E,F - angles between point 1 and 2,3,test
#  G,H,I - angles between point 2 and 1,3,test
def h(a,b,c,d,e,f,g,h,i,j,R):
    r=R;_=0
    while r>0:
        Q=atan2(j-h,i-g)
        k,l=g+r*cos(Q),h+r*sin(Q)
        D=atan2(d-b,c-a)
        E=atan2(f-b,e-a)
        F=atan2(l-b,k-a)
        G=atan2(b-d,a-c)
        H=atan2(f-d,e-c)
        I=atan2(l-d,k-c)
        _=_ or(D<F<E or E<F<D)and(G<I<H or H<I<G)
        r-=.001
    return _

Nasıl çalışır:

  • Çekimin bitiş noktasını hesaplayın.
  • Uç noktadan top konumuna kadar çok sayıda noktayı test edin:
    • Tepe 1'den diğer iki köşeye ve test noktasına açıları hesaplayın;
    • Tepe 2'den diğer iki köşeye ve test noktasına açıları hesaplayın;
    • Test noktası açısı diğer iki açı arasındaysa, her iki durumda da, test noktası üçgenin içindedir ve gemi vurulmuştur.

Örnek çalışmalar:

>>> h(0,0,0,1,1,0,1,1,0,0,2)
True
>>> h(0,0,1,2,3,0,-4,0,0,0,8)
False
>>> h(0,0,-1,3,4,-1,-3,-4,3,4,5)
False
>>> h(-2,-3,-3,6,7,-2,-6,2,1,-4,7)
True

2

Python 2.7, 235 bayt

from numpy import*
X=cross
h=lambda q,w,a,s,y,x,c,v,d,f,r:max([(X([a-q,s-w],[c+k*(d-c)-q,v+k*(f-v)-w])>0)==(X([y-a,x-s],[c+k*(d-c)-a,v+k*(f-v)-s])>0)==(X([q-y,w-x],[c+k*(d-c)-y,v+k*(f-v)-x])>0)for k in arange(0,r/hypot(d-c,f-v),1e-4)])

Çapraz ürünü AB x APA, B köşeleri ve P noktası arasında hesaplar. Üçü de aynı işarete sahipse, nokta üçgenin içindedir.

Ungolfed:

from numpy import *
def i(q,w,a,s,y,x,e,r): # helper-function, checks whether ER is inside the triangle QW-AS-YX
  t=cross([a-q,s-w],[e-q,r-w])>0
  g=cross([y-a,x-s],[e-a,r-s])>0
  b=cross([q-y,w-x],[e-y,r-x])>0
  return t==g==b

def h(q,w,a,s,y,x,c,v,d,f,r):
  R=arange(0,r/hypot(d-c,f-v),1e-3)
  return max([i(q,w,a,s,y,x,c+k*(d-c),v+k*(f-v)) for k in R])

Testler:

In : h(0,0,0,1,1,0,1,1,0,0,2)
Out: True

In : h(-3,2,2,-4,7,-3,-3,-4,-3,0,10)
Out: False

In : h(0,0,1,2,3,0,-4,0,0,0,8)
Out: True
     Grazes may count as hits...
In : h(1,2,0,0,3,0,-4,0,0,0,8)
Out: False
     ...or not, depending on the order of edges

1

C, 247 bayt

Kesinlikle oldukça golfed değil.

#include<math.h>
int z(float*k){float s=1e-3,t=s,p=k[8]-k[6],q=k[9]-k[7],r=k[10]/hypot(p,q);int w=0;for(;t<1;t+=s){float x=k[6]-k[0]+p*r*t,y=k[7]-k[1]+q*r*t,b=k[2]*k[5]-k[3]*k[4],d=(x*k[5]-y*k[4])/b,e=(x*k[3]-y*k[2])/b;w|=d>0&e<0&d-e<1;}return w;}

Şu anda bu, DLosc'un çözümüne benzer bir yaklaşım kullanır, yani üçgenle kesişip kesişmediğini belirlemek için çizgi segmentindeki olası tüm koordinatları yineler. (Bu nedenle aralık 1000'in üzerindeyse başarısız olur) Ancak, bir noktanın üçgen içinde olup olmadığını belirlemek için http://mathworld.wolfram.com/TriangleInterior.html formülünü kullanır . Bu, bir grup trigonometrik işlevi önler.


Örnek kontrol, yazdırmalıdır 1 0 0 0 1 0.

#include <stdio.h>
int main() {
    {
        float arr[] = {0,0,0,1,1,0,1,1,0,0,2};
        printf("%d\n", z(arr));
    }

    {
        float arr[] = {2,0,0,2,4,4,0,0,1,1,1};
        printf("%d\n", z(arr));
    }

    {
        float arr[] = {0,0,1,2,3,0,-4,0,0,0,8};
        printf("%d\n", z(arr));
    }

    {
        float arr[] = {0,0,-1,3,4,-1,-3,-4,3,4,5};
        printf("%d\n", z(arr));
    }

    {
        float arr[] = {-2,-3,-3,6,7,-2,-6,2,1,-4,7};
        printf("%d\n", z(arr));
    }

    {
        float arr[] = {-3,2,2,-4,7,-3,-3,-4,-3,0,10};
        printf("%d\n", z(arr));
    }
}

1

JavaScript (ES6) 320 448 522 627

(Yine de daha fazla golf olabilir mi?)

Adımlar:

  1. Gerçek isabet hedefini bulun (düşmandan nişan almak için çizgide r mesafesini işaretleyin)
  2. Vurmak: Düşmandan hedefe olan segment geminin yanlarından herhangi biriyle kesişiyorsa, ancak uç noktalarda değil
  3. Çok vurun: hedef geminin içindeyse - atış bir tepe noktasına girmiş olsa bile - test örneği 8

Ref:
Kesişim
noktası Üçgenin içindeki
nokta Mesafe verilen bir segmentteki nokta

Firefox'ta test edin

C=(i,j,k,l,m,n,g,h,a,b,r,
  d=a-g,e=b-h,f=r/Math.sqrt(d*d+e*e),
  p=g+f*d,q=h+f*e,
  z=j*(m-k)+i*(l-n)+k*n-l*m,
  s=(j*m-i*n+(n-j)*p+(i-m)*q)/z,
  t=(i*l-j*k+(j-l)*p+(k-i)*q)/z,
  S=(i,j,k,l,
     a=k-i,b=l-j,c=p-g,d=q-h,e=i-g,f=j-h,
     s=a*f-b*e,t=c*f-d*e,m=a*d-c*b)=>
     m&&((s/=m)>0&s<1&(t/=m)>0&t<1)
)=>s>0&t>0&s+t<1|S(i,j,k,l)|S(i,j,m,n)|S(m,n,k,l)

// Test
MyOutput.innerHTML = ['Test1', C(0,0, 0,1, 1,0, 1,1, 0,0, 2),
'<br>Test2', C(2,0, 0,2, 4,4, 0,0, 1,1, 1),
'<br>Test3', C(0,0, 1,2, 3,0, -4,0, 0,0, 8),
'<br>Test4', C(0,0, -1,3, 4,-1, -3,-4, 3,4, 5),
'<br>Test5', C(-2,-3, -3,6, 7,-2, -6,2, 1,-4, 7),
'<br>Test6', C(-3,2, 2,-4, 7,-3, -3,-4, -3,0 ,10),
'<br>Test7', C(0,0, 6,0, 6,8, -6,-8, 6,8, 20),
'<br>Test8', C(0,0,-2,-5, 5,3, -3,4, 0,0, 6)];
<div id="MyOutput"></div>

Ungolfed

function check(p0x, p0y, p1x, p1y, p2x, p2y, ex, ey, ax, xy, r)
{
  var sec = function(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y)
  {
      var s10x = p1x - p0x, s10y = p1y - p0y, 
          s32x = p3x - p2x, s32y = p3y - p2y,
          s02x = p0x - p2x, s02y = p0y - p2y,
          s = s10x * s02y - s10y * s02x, t = s32x * s02y - s32y * s02x,
          d = s10x * s32y - s32x * s10y;
      return d && (s/=d) > 0 && s<1 && (t/=d) > 0 && t < 1 && [p0x + (t * s10x), p0y + (t * s10y)];
  }
  var pr = function(p0x, p0y, p1x, p1y, r)
  {
      var dx = (p1x-p0x), dy = (p1y-p0y), f = r/Math.sqrt(dx*dx+dy*dy);
      return [p0x + f*dx, p0y+f*dy];
  }
  var inside = function(p0x, p0y, p1x, p1y, p2x, p2y, px, py)
  {
      var area2 = (-p1y*p2x + p0y*(-p1x + p2x) + p0x*(p1y - p2y) + p1x*p2y),
          s = (p0y*p2x - p0x*p2y + (p2y - p0y)*px + (p0x - p2x)*py)/area2,
          t = (p0x*p1y - p0y*p1x + (p0y - p1y)*px + (p1x - p0x)*py)/area2;
      return s > 0 && t > 0 && s+t < 1;
  }
  var tx, xy;
  [tx, ty] = pr(ex, ey, ax, ay, r);

  return inside(p0x, p0y, p1x, p1y, p2x, p2y, tx,ty)
  || sec(p0x, p0y, p1x, p1y, ex, ey, tx, ty)
  || sec(p0x, p0y, p2x, p2y, ex, ey, tx, ty)
  || sec(p2x, p2y, p1x, p1y, ex, ey, tx, ty);
}  
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.