이 도전은 최근 간단한 게임을 위해 작성해야했던 실제 충돌 감지를 기반으로합니다.
두 개의 객체가 주어지면 두 객체 가 충돌하는지 (즉, 교차하는지)에 따라 참 또는 거짓 값을 반환하는 프로그램이나 함수를 작성하십시오 .
세 가지 유형의 객체를 지원해야합니다.
- 선분 : 4로 표시되는 플로트 즉 두 종점을 나타내는 (X 1 , Y 1 ) 및 (X 2 , Y 2 ) . 끝 점이 동일하지 않다고 가정 할 수 있습니다 (따라서 선분이 축퇴되지 않음).
- 디스크 : 즉 채워진 원은 3 개의 플로트로 표시되며, 2 개는 중심 (x, y )에 대해 2 개, 반경 ( r )에 대해 1 (양)입니다 .
- 공동 : 이것들은 디스크의 보완입니다. 즉, 캐비티는 중심과 반경으로 지정된 원형 영역을 제외한 모든 2D 공간을 채 웁니다 .
프로그램이나 함수는 식별 정수 (선택한 정수)와 3 개 또는 4 개의 부동 소수점 형식으로 이러한 두 개의 객체를받습니다. STDIN, ARGV 또는 함수 인수를 통해 입력을받을 수 있습니다. 사전 처리되지 않은 편리한 형식 (예 : 8-10 개의 개별 숫자, 쉼표로 구분 된 두 개의 값 목록 또는 두 개의 목록)으로 입력을 나타낼 수 있습니다. 결과는 STDOUT에 리턴되거나 기록 될 수 있습니다.
객체가 최소 10 -10 길이 단위 떨어져 있거나 그와 많이 교차 한다고 가정 할 수 있으므로 부동 소수점 유형의 제한에 대해 걱정할 필요가 없습니다.
이것은 코드 골프이므로 가장 짧은 대답 (바이트)이 이깁니다.
테스트 사례
목록 기반 입력 형식을 사용하여 0
, 디스크 1
및 캐비티가있는 선 세그먼트를 2
표시하면 다음과 같은 결과가 모두 출력됩니다.
[0,[0,0],[2,2]], [0,[1,0],[2,4]] # Crossing line segments
[0,[0.5,0],[-0.5,0]], [1,[0,0],1] # Line contained in a disc
[0,[0.5,0],[1.5,0]], [1,[0,0],1] # Line partially within disc
[0,[-1.5,0.5],[1.5,0.5]], [1,[0,0],1] # Line cutting through disc
[0,[0.5,2],[-0.5,2]], [2,[0,0],1] # Line outside cavity
[0,[0.5,0],[1.5,0]], [2,[0,0],1] # Line partially outside cavity
[0,[-1.5,0.5],[1.5,0.5]], [2,[0,0],1] # Line cutting through cavity
[1,[0,0],1], [1,[0,0],2] # Disc contained within another
[1,[0,0],1.1], [1,[2,0],1.1] # Intersecting discs
[1,[3,0],1], [2,[0,0],1] # Disc outside cavity
[1,[1,0],0.1], [2,[0,0],1] # Disc partially outside cavity
[1,[0,0],2], [2,[0,0],1] # Disc encircling cavity
[2,[0,0],1], [2,[0,0],1] # Any two cavities intersect
[2,[-1,0],1], [2,[1,0],1] # Any two cavities intersect
다음은 모두 잘못된 결과를 초래합니다.
[0,[0,0],[1,0]], [0,[0,1],[1,1]] # Parallel lines
[0,[-2,0],[-1,0]], [0,[1,0],[2,0]] # Collinear non-overlapping lines
[0,[0,0],[2,0]], [0,[1,1],[1,2]] # Intersection outside one segment
[0,[0,0],[1,0]], [0,[2,1],[2,3]] # Intersection outside both segments
[0,[-1,2],[1,2]], [1,[0,0],1] # Line passes outside disc
[0,[2,0],[3,0]], [1,[0,0],1] # Circle lies outside segment
[0,[-0.5,0.5],[0.5,-0.5]], [2,[0,0],1] # Line inside cavity
[1,[-1,0],1], [1,[1,1],0.5] # Non-intersecting circles
[1,[0.5,0],0.1], [2,[0,0],1] # Circle contained within cavity
답변
APL, 279 208 206 203
s←1 ¯1
f←{x←⊣/¨z←⍺⍵[⍋⊣/¨⍺⍵]
2 2≡x:∧/0∧.=⌊(2⊃-⌿↑z)⌹⍣(≠.×∘⌽/x)⍉↑x←s×-/2⊢/↑z
2≡2⌷x:∨/((2⊃z)∇2,x[1]×(2⌷⊃z)+,∘-⍨⊂y÷.5*⍨+.×⍨y←⌽s×⊃-/y),x[1]=(×⍨3⊃⊃z)>+.×⍨¨y←(s↓⌽↑z)-2⌷⊃z
~x∨.∧x[1]≠(.5*⍨+.×⍨2⊃-⌿↑z)<-/⊢/¨z×s*1⌷x}
함수의 줄 바꿈은 f
명확성을위한 것입니다. 명령문 구분 기호로 바꿔야합니다.⋄
마지막으로 복잡한 APL 프로그램을 만든 지 오래되었습니다. 나는 마지막으로는 생각 이 있지만 복잡했다 심지어 확실하지 않다.
입력 형식 캐비티, 디스크 및 선분에 대한
사용 0
을 제외하고는 기본적으로 OP와 동일 합니다.1
2
주요 업데이트
나는 다른 알고리즘을 사용하여 많은 캐릭터를 골프로 쳤습니다. 더 이상 g
황소가 없습니다 !
주요 기능 f
은 다음과 같은 경우로 나뉩니다.
2 2≡x
: 세그먼트 세그먼트
이 경우 각 선의 끝점에서 벡터를 계산하고 선형 방정식 시스템을 풀어 교차가 벡터 내에 포함되어 있는지 확인하십시오.
주의 사항 :
- 벡터의 끝점은 벡터의 일부로 간주되지 않습니다 (원점이있는 동안). 그러나 벡터의 끝만 다른쪽에 있으면 입력에 따라 입력이 유효하지 않습니다.
- 축퇴하지 않은 병렬 세그먼트는 공선 성과 상관없이 항상 false를 반환합니다.
- 세그먼트 중 하나가 축퇴되면 항상 false를 리턴하십시오. 두 세그먼트가 모두 퇴화되면 항상 true를 리턴하십시오.
예 : (오른쪽 그림의주의 사항 1 참고)
2≡2⌷x
: 세그먼트 기타
이 경우 다른 개체는 원형 개체입니다. 거리 확인을 사용하여 세그먼트의 끝 점이 원 안에 있는지 확인하십시오.
디스크 케이스에서, 주어진 세그먼트에 수직 인 직경의 선 세그먼트를 구성하십시오. 세그먼트가 재귀에 의해 충돌하는지 확인하십시오.
공동의 경우, 상기 세그먼트의 구성에서 “시간 0″으로 몰래 축퇴되도록한다. ( 현재 0
캐비티와 1
디스크에 사용 하는 이유를 참조하십시오 .) 주어진 세그먼트가 퇴화되지 않기 때문에 세그먼트 세그먼트 충돌 감지는 항상 false를 반환합니다.
마지막으로 거리 확인 결과와 충돌 감지 결과를 결합합니다. 캐비티 케이스의 경우 먼저 거리 점검 결과를 무효화하십시오. 그런 다음 (두 경우 모두) 또는 3 개의 결과가 함께 있습니다.
세그먼트 세그먼트주의 사항과 관련하여, 숫자 3이 다루어지고 활용됩니다. 우리가 여기서 수직 세그먼트를 교차 할 때 숫자 2는 문제가되지 않습니다. 숫자 1은 주어진 끝점 중 하나가 구성된 직경에있을 때 디스크 케이스에서만 적용됩니다. 끝 점이 원 안에 있으면 거리 점검으로 처리됩니다. 종점이 원에있는 경우, 구성된 직경이 주어진 세그먼트와 평행하기 때문에, 원점은 원점에 접해야합니다. 한 점만 디스크에 닿아 유효하지 않습니다.
예 :
기본 사례 : 기타
중심 사이의 거리를 계산하십시오. 거리가 반지름의 합보다 작은 경우에만 디스크 디스크 충돌이 발생합니다. 거리가 반경 차이보다 큰 경우에만 디스크 캐비티 충돌이 발생합니다.
캐비티-캐비티 케이스를 처리하려면 거리 확인 결과를 무효화하고 각각의 식별 정수를 사용한 다음 함께 OR하십시오. 일부 논리를 사용하면 식별하는 두 정수가 모두 잘못된 경우 (Cavity-cavity case) 또는 거리 확인이 true를 반환 한 경우에만이 프로세스가 true를 반환 함을 알 수 있습니다.
답변
자바 스크립트-393 바이트
축소 :
F=(s,a,t,b,e,x)=>(x=e||F(t,b,s,a,1),[A,B]=a,[C,D]=b,r=(p,l)=>([g,h]=l,[f,i]=y(h,g),[j,k]=y(p,g),m=Math.sqrt(f*f+i*i),[(f*j+i*k)/m,(f*k-i*j)/m]),u=(p,c)=>([f,g]=c,[i,j]=y(p,f),i*i+j*j<g*g),y=(p,c)=>[p[0]-c[0],p[1]-c[1]],[n,o]=r(C,a),[q,v]=r(D,a),w=(v*n-o*q)/(v-o),z=r(B,a)[0],Y=u(A,b),Z=u(B,b),[v*o<0&&w*(w-z)<0,Y||Z||o<D&&o>-D&&n*(n-z)<0,!Y||!Z,x,u(A,[C,D+B]),B>D||!u(A,[C,D-B]),x,x,1][s*3+t])
넓히는:
F = (s,a,t,b,e,x) => (
x = e || F(t,b,s,a,1),
[A,B] = a,
[C,D] = b,
r = (p,l) => (
[g,h] = l,
[f,i] = y(h,g),
[j,k] = y(p,g),
m = Math.sqrt( f*f + i*i ),
[(f*j + i*k)/m, (f*k - i*j)/m] ),
u = (p,c) => (
[f,g] = c,
[i,j] = y(p,f),
i*i + j*j < g*g ),
y = (p,c) => [p[0] - c[0], p[1] - c[1]],
[n,o] = r(C,a),
[q,v] = r(D,a),
w = (v*n - o*q)/(v - o),
z = r(B,a)[0],
Y = u(A,b), Z = u(B,b),
[ v*o < 0 && w*(w-z) < 0,
Y || Z || o < D && o > -D && n*(n-z) < 0,
!Y || !Z,
x,
u(A,[C,D+B]),
B > D || !u(A,[C,D-B]),
x,
x,
1
][s*3+t]);
노트:
- 기능을 정의
F
필수 인수를 허용하고 필수 값을 리턴하는 를 합니다. - 입력 형식은 각 기본 요소의 정수 유형 코드가 튜플과 분리된다는 점을 제외하고 OP의 형식과 동일합니다. 예를 들어
F( 0,[[0,0],[2,2]], 0,[[1,0],[2,4]] )
또는F( 1,[[3,0],1], 2,[[0,0],1] )
. - OP에 제공된 모든 테스트 사례에서 코드 검증
- 길이가 0 인 선 세그먼트 및 반지름이없는 원을 포함하여 모든 모서리 및 모서리 케이스를 처리해야합니다.
답변
파이썬, 284
나는이 모든 기하학적 트릭에 비해 예쁜 가비지 알고리즘을 사용하고 있지만 테스트 사례를 통과하는 데 1 분 이상이 걸리더라도 올바른 답변을 얻습니다. 가장 큰 장점은 세 가지 점수 함수 만 작성하면되고 언덕 등반은 모든 에지 사례를 처리한다는 것입니다.
골프 :
import math,random as r
n=lambda(a,c),(b,d):math.sqrt((a-b)**2+(c-d)**2)
x=lambda(t,a,b),p:max(eval(["n(b,p)-n(a,b)+","-b+","b-"][t]+'n(a,p)'),0)
def F(t,j):
q=0,0;w=1e9
for i in q*9000:
y=x(t,q)+x(j,q)
if y<w:p,w=q,y
q=(r.random()-.5)*w+p[0],(r.random()-.5)*w+p[1]
return w<.0001
언 골프 드 :
import math
import random as r
def norm(a, b):
return math.sqrt((a[0] - b[0])**2 + (a[1] - b[1])**2)
def lineWeight(a, b, p):
l1 = norm(a, p)
l2 = norm(b, p)
return min(l1, l2, l1 + l2 - norm(a, b))
def circleWeight(a, r, p):
return max(0, norm(a, p) - r)
def voidWeight(a, r, p):
return max(0, r - norm(a, p))
def weight(f1, f2, s1, s2, p):
return f1(s1[1], s1[2], p) + f2(s2[1], s2[2], p)
def checkCollision(s1, s2):
a = [lineWeight, circleWeight, voidWeight]
f1 = a[s1[0]]
f2 = a[s2[0]]
p = (0.0, 0.0)
w = 0
for i in a*1000:
w = weight(f1, f2, s1, s2, p)
p2 = ((r.random()-.5)*w + p[0], (r.random()-.5)*w + p[1])
if(weight(f1, f2, s1, s2, p2) < w):
p = p2
if w < .0001:
return True
return False
그리고 마지막으로, 다른 누군가가 파이썬에서 이것을 시도하려는 경우의 테스트 스크립트 :
import collisiongolfedbak
reload(collisiongolfedbak)
tests = [
[0,[0,0],[2,2]], [0,[1,0],[2,4]], # Crossing line segments
[0,[0.5,0],[-0.5,0]], [1,[0,0],1], # Line contained in a disc
[0,[0.5,0],[1.5,0]], [1,[0,0],1], # Line partially within disc
[0,[-1.5,0.5],[1.5,0.5]], [1,[0,0],1], # Line cutting through disc
[0,[0.5,2],[-0.5,2]], [2,[0,0],1], # Line outside cavity
[0,[0.5,0],[1.5,0]], [2,[0,0],1], # Line partially outside cavity
[0,[-1.5,0.5],[1.5,0.5]], [2,[0,0],1], # Line cutting through cavity
[1,[0,0],1], [1,[0,0],2], # Disc contained within another
[1,[0,0],1.1], [1,[2,0],1.1], # Intersecting discs
[1,[3,0],1], [2,[0,0],1], # Disc outside cavity
[1,[1,0],0.1], [2,[0,0],1], # Disc partially outside cavity
[1,[0,0],2], [2,[0,0],1], # Disc encircling cavity
[2,[0,0],1], [2,[0,0],1] , # Any two cavities intersect
[2,[-1,0],1], [2,[1,0],1] , # Any two cavities intersect
[0,[0,0],[1,0]], [0,[0,1],[1,1]] , # Parallel lines
[0,[-2,0],[-1,0]], [0,[1,0],[2,0]], # Collinear non-overlapping lines
[0,[0,0],[2,0]], [0,[1,1],[1,2]], # Intersection outside one segment
[0,[0,0],[1,0]], [0,[2,1],[2,3]], # Intersection outside both segments
[0,[-1,2],[1,2]], [1,[0,0],1], # Line passes outside disc
[0,[2,0],[3,0]], [1,[0,0],1], # Circle lies outside segment
[0,[-0.5,0.5],[0.5,-0.5]], [2,[0,0],1], # Line inside cavity
[1,[-1,0],1], [1,[1,1],0.5], # Non-intersecting circles
[1,[0.5,0],0.1], [2,[0,0],1] # Circle contained within cavity
]
for a, b in zip(tests[0::2], tests[1::2]):
print collisiongolfedbak.F(a,b)