Thiết giáp hạm tam giác (Một bài toán hình học tính toán)


18

Bạn là thuyền trưởng của một tàu chiến. Bộ phận kỹ thuật đã cắt giảm các thiết kế trong năm nay, vì vậy con tàu bạn đang đi có hình tam giác đơn giản.

Bạn bước ra boong tàu và tận hưởng gió biển ... mặc dù không lâu. Một kẻ thù đã bắn vào bạn! - nhưng sẽ bắn trúng?

Đầu vào

Bạn có thể viết một chức năng hoặc một chương trình đầy đủ cho thử thách này.

Chương trình của bạn sẽ có 11 số nguyên, mười trong số đó được ghép nối:

  • Ba cặp số nguyên đầu tiên (x 1 , y 1 ), (x 2 , y 2 ), (x 3 , y 3 ) sẽ chỉ định các đỉnh của tàu của bạn. Các tam giác hình thành sẽ có diện tích khác.

  • Cặp số nguyên tiếp theo (e x , e y ) chỉ định vị trí của pháo của kẻ thù. Pháo của kẻ thù sẽ không bao giờ nằm ​​trên hoặc trong ranh giới tàu của bạn. *

  • Cặp (a x , a y ) sau đó xác định nơi kẻ thù nhắm đến. Điều này sẽ khác với (e x , e y ).

  • Số nguyên dương R cuối cùng chỉ định phạm vi phát bắn của kẻ thù

* Bạn sẽ là một đội trưởng khủng khiếp nếu bạn thậm chí không nhận thấy điều đó xảy ra!

Đầu ra

Bạn phải in / trả về một truthy giá trị (ví dụ thành sự thật, 1) nếu chiếc thiết giáp hạm sẽ bị ảnh hưởng, nếu không một giá trị falsy (ví dụ sai, 0).

Một hit là gì?

Kẻ địch bắn là một đoạn thẳng có độ dài R từ (e x , e y ) theo hướng (a x , a y ). Nếu đoạn đường này chồng lên bất kỳ phần nào trong phần bên trong của tàu chiến hình tam giác của bạn, thì đoạn này được tính là một điểm nhấn. Nếu không, nó không phải là một hit.

Những cú đánh gặm cỏ dọc theo hoặc chỉ chạm tới ranh giới của tam giác không được tính là một cú đánh.

Ví dụ

0 0 0 1 1 0
1 1
0 0
2

kiểm tra1

Trúng: Kẻ thù đã bắn ngay vào trung tâm con tàu của bạn!


2 0 0 2 4 4
0 0
1 1
1

kiểm tra2

Không đánh: Tầm bắn của kẻ thù quá ngắn, nên bạn an toàn.


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

kiểm tra3

Không đánh trúng: Kẻ thù đã sượt qua mạn tàu của bạn, vì vậy đây không được tính là một cú đánh. May mắn!


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

kiểm tra4

Không trúng: Kẻ địch chỉ dừng lại ở con tàu, nên bạn an toàn. Nếu pháo của kẻ thù có tầm bắn tốt hơn một chút, thì bạn đã bị bắn trúng! Phù!


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

kiểm tra5

Lượt truy cập: Mặc dù cú đánh không xuyên qua phía bên kia, đây vẫn là một cú đánh.


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

kiểm tra6

Không có hit: Đối với hồ sơ, đây là một bỏ lỡ gần.


Các trường hợp kiểm tra bổ sung

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

kiểm tra7

Không đánh: Đây là một gặm cỏ khác, nhưng ở một góc độ.


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

kiểm tra8

Lượt truy cập: Cú bắn vào qua một đỉnh của con tàu.

Chấm điểm

Đây là , vì vậy mã ngắn nhất tính bằng byte sẽ thắng. Tiêu chuẩn áp dụng.


Để chắc chắn rằng chúng ta không thể: chúng ta có thể cho rằng con tàu không có đáy và có một khoảng cách nhỏ giữa hai bên, để nếu cú ​​bắn có thể đi vào con tàu qua góc của nó, chúng ta có coi đó là một sự bỏ lỡ không?
John Dvorak

@JanDvorak Nếu một phát bắn xuyên qua con tàu bằng cách đi qua một đỉnh, thì đây sẽ là một cú đánh vì đoạn đường chồng lên bên trong con tàu. Vì vậy, trong ví dụ thứ 4, nếu phạm vi lớn hơn 5, thì đây sẽ là một điểm nhấn.
Sp3000

Bao nhiêu chúng ta được phép chơi với các đối số? Chúng tôi có được phép nhóm chúng, thay đổi thứ tự hoặc yêu cầu chúng phải nổi không?
FryAmTheEggman

@FryAmTheEggman Bạn có thể nhóm hoặc sắp xếp lại các đối số nếu cần. Bạn có thể sử dụng phao, nhưng chương trình cần hoạt động chính xác cho các lưới nhỏ (có thể lên đến 20x20) mà không phải lo lắng về độ chính xác.
Sp3000

Tôi nghĩ rằng các ví dụ đang thiếu một trường hợp quan trọng khiến giải pháp dự định của tôi thất bại: chẳng hạn khi con tàu bị xuyên thủng qua một góc 0 0 -1 3 4 -1 -3 -4 3 4 6.
nutki

Câu trả lời:


3

Python 3, 252 byte

Đây chắc chắn là biến số nhiều nhất tôi từng sử dụng trong mã golf. : ^ 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 _

Hơi vô dụng, với ý kiến:

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 _

Làm thế nào nó hoạt động:

  • Tính điểm cuối của cú đánh.
  • Kiểm tra rất nhiều điểm dọc theo đường thẳng từ điểm cuối đến vị trí của pháo:
    • Tính các góc từ đỉnh 1 đến hai đỉnh khác và đến điểm kiểm tra;
    • Tính các góc từ đỉnh 2 đến hai đỉnh khác và đến điểm kiểm tra;
    • Nếu góc điểm kiểm tra nằm giữa hai góc còn lại, trong cả hai trường hợp, thì điểm kiểm tra nằm trong tam giác và con tàu đã bị bắn trúng.

Chạy mẫu:

>>> 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 byte

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

Tính tích chéo AB x APgiữa các góc A, B và điểm P. Nếu cả ba đều có cùng dấu thì điểm nằm trong tam giác.

Ung dung:

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

Các xét nghiệm:

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 byte

Chắc chắn là không chơi golf được.

#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;}

Hiện tại phương pháp này sử dụng một cách tiếp cận tương tự như giải pháp của DLosc, tức là lặp qua tất cả các tọa độ có thể có trên đoạn đường để xác định xem nó có giao nhau với tam giác hay không. (Vì vậy, nó sẽ thất bại nếu phạm vi trên 1000) Tuy nhiên, nó sử dụng công thức từ http://mathworld.wolfram.com/TriginInterior.html để xác định xem một điểm có nằm trong tam giác hay không. Điều này tránh một loạt các hàm lượng giác.


Ví dụ kiểm tra, nên in 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

(Vẫn có thể chơi gôn nhiều hơn?)

Các bước:

  1. Tìm mục tiêu trúng đích thực tế (điểm ở khoảng cách r trên đường từ kẻ thù đến mục tiêu)
  2. Lượt truy cập: nếu đoạn từ kẻ thù đến mục tiêu giao nhau với bất kỳ cạnh nào của con tàu, nhưng không ở điểm cuối
  3. Đánh quá: nếu mục tiêu ở trong tàu - ngay cả khi phát bắn vào một đỉnh - trường hợp thử nghiệm 8

Tham chiếu:
Giao
điểm phân đoạn Điểm trong tam giác
Điểm trong một phân đoạn cho một khoảng cách

Kiểm tra trong Firefox

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>

Ung dung

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);
}  
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.