เรือประจัญบานรูปสามเหลี่ยม (ปัญหาเรขาคณิตเชิงคำนวณ)


18

คุณเป็นกัปตันของเรือรบ แผนกวิศวกรรมได้ตัดมุมด้วยการออกแบบในปีนี้ดังนั้นเรือที่คุณไปจะมีรูปร่างเป็นรูปสามเหลี่ยมง่ายๆ

คุณเดินออกไปที่ดาดฟ้าและเพลิดเพลินไปกับลมทะเล ... แม้ว่าจะไม่นาน ศัตรูยิงคุณ! - แต่จะยิงโดนหรือไม่

อินพุต

คุณอาจจะเขียนฟังก์ชั่นหรือโปรแกรมเต็มรูปแบบสำหรับความท้าทายนี้

โปรแกรมของคุณจะมีจำนวนเต็ม 11 ตัวซึ่งสิบคู่จะถูกจับคู่:

  • จำนวนเต็มสามคู่แรก (x 1 , y 1 ), (x 2 , y 2 ), (x 3 , y 3 ) จะระบุจุดยอดของเรือของคุณ รูปสามเหลี่ยมที่เกิดขึ้นจะมีพื้นที่ที่ไม่ใช่ศูนย์

  • จำนวนเต็มคู่ต่อไป (e x , e y ) ระบุตำแหน่งของปืนใหญ่ของศัตรู ปืนใหญ่ของศัตรูจะไม่นอนหรืออยู่ในขอบเขตของเรือของคุณ *

  • คู่ (a x , a y ) หลังจากนั้นระบุตำแหน่งที่ศัตรูเล็ง สิ่งนี้จะแตกต่างจาก (e x , e y )

  • จำนวนเต็มบวกสุดท้ายขั้นสุดท้ายระบุช่วงของการยิงของศัตรู

* คุณจะเป็นกัปตันที่แย่มากถ้าคุณไม่สังเกตเห็นสิ่งนั้นเกิดขึ้น!

เอาท์พุต

คุณต้องพิมพ์ / กลับtruthyค่า (เช่นจริง 1) ถ้าเรือรบจะถูกตีมิฉะนั้นค่า falsy (เช่นเท็จ 0)

การตีคืออะไร

ยิงศัตรูเป็นส่วนของเส้นตรงที่มีความยาว R จาก (e x , e y ) ในทิศทางของ (a x , a y ) หากส่วนของเส้นนี้เหลื่อมทับส่วนใดส่วนหนึ่งของการตกแต่งภายในของเรือประจัญบานรูปสามเหลี่ยมของคุณการนับนี้จะถือว่าเป็น Hit ไม่อย่างนั้นมันจะไม่เป็นที่นิยม

ช็อตที่เล็มหญ้าไปตามหรือเอื้อมจนถึงขอบเขตของรูปสามเหลี่ยมจะไม่นับรวมถึงการเข้าตี

ตัวอย่าง

0 0 0 1 1 0
1 1
0 0
2

test1

Hit:ศัตรูยิงเข้าทางกลางเรือของคุณ!


2 0 0 2 4 4
0 0
1 1
1

test2

ไม่ตี:ระยะของศัตรูสั้นเกินไปดังนั้นคุณจึงปลอดภัย


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

test3

ไม่มีการตี:ศัตรูมีเล็มหญ้าด้านข้างของเรือดังนั้นสิ่งนี้จะไม่นับเป็นการโจมตี โชคดี!


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

test4

ไม่มีการตี:การยิงของข้าศึกจะหยุดลงที่เรือคุณจึงปลอดภัย หากปืนใหญ่ของศัตรูมีระยะที่ดีขึ้นเล็กน้อยคุณจะต้องถูกโจมตี! วุ้ย


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

test5

Hit:ถึงแม้ว่ากระสุนจะไม่พุ่งทะลุไปยังอีกด้านหนึ่ง


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

TEST6

ไม่มีการเข้าชม:สำหรับการบันทึกนี่เป็นอีกการพลาดอย่างหนึ่ง


กรณีทดสอบเพิ่มเติม

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

TEST7

ไม่ตี:นี่คือหญ้าอื่น แต่อยู่ในมุม


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

test8

การเข้าชม:การยิงเข้าสู่จุดสุดยอดของเรือ

เกณฑ์การให้คะแนน

นี่คือดังนั้นโค้ดที่สั้นที่สุดในหน่วยไบต์ชนะ ช่องโหว่มาตรฐานใช้


เพียงเพื่อให้แน่ใจว่าเราทำไม่ได้: เราสามารถสรุปได้ว่าเรือไม่มีก้นและมีช่องว่างเล็ก ๆ ระหว่างทั้งสองด้านดังนั้นถ้าช็อตจัดการเพื่อเข้าไปในเรือผ่านมุมของเรือ
John Dvorak

@JanDvorak หากการยิงถูกตัดผ่านเรือรบโดยการเข้าไปในจุดสุดยอดนี่จะเป็นที่นิยมเพราะส่วนของเส้นตรงข้ามกับการตกแต่งภายในของเรือ ดังนั้นในตัวอย่างที่ 4 ถ้าช่วงนั้นมากกว่า 5 แล้วนี่จะเป็น Hit
Sp3000

เราได้รับอนุญาตให้เล่นกับข้อโต้แย้งมากแค่ไหน? เราได้รับอนุญาตให้จัดกลุ่มเปลี่ยนลำดับหรือกำหนดให้ลอยหรือไม่
FryAmTheEggman

@FryAmTheEggman คุณสามารถจัดกลุ่มหรือเรียงลำดับอาร์กิวเมนต์ตามที่จำเป็น คุณสามารถใช้โฟลตได้ แต่โปรแกรมจำเป็นต้องทำงานอย่างถูกต้องสำหรับกริดขนาดเล็ก (พูดได้ถึง 20x20) โดยไม่ต้องกังวลเกี่ยวกับความแม่นยำ
Sp3000

ฉันคิดว่าตัวอย่างจะหายไปหนึ่งกรณีที่สำคัญที่ทำให้การแก้ปัญหาที่ฉันตั้งใจล้มเหลว: เมื่อเรือถูกเจาะผ่านมุม0 0 -1 3 4 -1 -3 -4 3 4 6หนึ่ง
nutki

คำตอบ:


3

Python 3, 252 ไบต์

นี่คือตัวแปรส่วนใหญ่ที่ฉันเคยใช้ในการตีกอล์ฟ : ^ 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 _

ungolfed เล็กน้อยพร้อมความคิดเห็น:

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 _

มันทำงานอย่างไร:

  • คำนวณจุดสิ้นสุดของการยิง
  • ทดสอบจุดจำนวนมากตามแนวจากจุดสิ้นสุดไปยังตำแหน่งของปืนใหญ่:
    • คำนวณมุมจากจุดยอด 1 ไปยังอีกสองจุดยอดและเพื่อทดสอบจุด
    • คำนวณมุมจากจุดยอด 2 ไปยังอีกสองจุดยอดและเพื่อทดสอบจุด
    • หากมุมของจุดทดสอบอยู่ระหว่างมุมอีกสองมุมในทั้งสองกรณีจุดทดสอบจะอยู่ในรูปสามเหลี่ยมและเรือถูกตี

ตัวอย่างการวิ่ง:

>>> 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 ไบต์

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

คำนวณครอสโปรดัคAB x APระหว่างมุม A, B และจุด P หากทั้งสามมีเครื่องหมายเหมือนกันดังนั้นจุดนั้นจะอยู่ภายในรูปสามเหลี่ยม

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

แบบทดสอบ:

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 ไบต์

แน่นอนว่ายังไม่ค่อยได้เล่นกอล์ฟ

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

ในปัจจุบันสิ่งนี้ใช้วิธีการคล้ายกับวิธีแก้ปัญหาของ DLosc เช่นทำซ้ำผ่านพิกัดที่เป็นไปได้ทั้งหมดในส่วนของเส้นเพื่อตรวจสอบว่ามันตัดกับสามเหลี่ยมหรือไม่ (ดังนั้นมันจะล้มเหลวถ้าช่วงมีค่ามากกว่า 1,000) อย่างไรก็ตามจะใช้สูตรจากhttp://mathworld.wolfram.com/TriangleInterior.htmlเพื่อตรวจสอบว่าจุดอยู่ภายในรูปสามเหลี่ยมหรือไม่ นี่เป็นการหลีกเลี่ยงฟังก์ชันตรีโกณมิติ


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

(สามารถเล่นกอล์ฟได้มากกว่านี้หรือไม่)

ขั้นตอน:

  1. ค้นหาเป้าหมายการยิงที่แท้จริง (ชี้ไปที่ระยะทาง r บนเส้นจากศัตรูไปยังจุดมุ่งหมาย)
  2. Hit: หากส่วนจากศัตรูไปยังเป้าหมายจะตัดกันด้านใดด้านหนึ่งของเรือ แต่ไม่ใช่ที่จุดสิ้นสุด
  3. ยิงด้วย: ถ้าเป้าหมายอยู่ในเรือ - แม้ว่าจะยิงเข้าสู่จุดยอด - กรณีทดสอบ 8

การอ้างอิง:
จุดตัดการแบ่งกลุ่ม
ภายในจุดสามเหลี่ยม
ในส่วนที่มีระยะทาง

ทดสอบใน 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>

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);
}  
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.