Wyzwanie to opiera się na wykrywaniu kolizji, które ostatnio musiałem napisać dla prostej gry.
Napisz program lub funkcję, która, biorąc pod uwagę dwa obiekty, zwraca wartość prawdy lub fałszu w zależności od tego, czy oba obiekty są w kolizji (tj. Przecinają się), czy nie.
Musisz obsługiwać trzy typy obiektów:
- Segmenty linii : reprezentowane przez 4 zmiennoprzecinkowe, wskazujące dwa punkty końcowe, tj. (X 1 , y 1 ) i (x 2 , y 2 ) . Możesz założyć, że punkty końcowe nie są identyczne (więc odcinek linii nie jest zdegenerowany).
- Tarcze : tzn. Wypełnione koła, reprezentowane przez 3 zmiennoprzecinkowe, dwie dla środka (x, y) i jedną (dodatnią) dla promienia r .
- Wnęki : są uzupełnieniem płyty. Oznacza to, że wnęka wypełnia całą przestrzeń 2D, z wyjątkiem okrągłego obszaru określonego przez środek i promień.
Twój program lub funkcja otrzyma dwa takie obiekty w postaci identyfikującej liczby całkowitej (do wyboru) i ich 3 lub 4 zmiennoprzecinkowe. Możesz przyjmować dane wejściowe za pomocą argumentu STDIN, ARGV lub funkcji. Możesz reprezentować dane wejściowe w dowolnej dogodnej formie, która nie jest wstępnie przetwarzana, np. Od 8 do 10 pojedynczych liczb, dwie listy wartości oddzielone przecinkami lub dwie listy. Wynik można zwrócić lub zapisać w STDOUT.
Możesz założyć, że obiekty są oddalone od siebie o co najmniej 10-10 jednostek lub przecinają się tak bardzo, więc nie musisz się martwić ograniczeniami typów zmiennoprzecinkowych.
To jest kod golfowy, więc wygrywa najkrótsza odpowiedź (w bajtach).
Przypadki testowe
Reprezentując segmenty linii 0
, dyski 1
i wnęki 2
, przy użyciu formatu wejściowego opartego na listach, poniższe elementy powinny generować prawdziwy wynik:
[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
podczas gdy poniższe powinny skutkować wynikiem fałszowania
[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
źródło
[0,[-2,0],[-1,0]], [0,[1,0],[2,0]]
Odpowiedzi:
APL,
279208206203Podziały linii w funkcji
f
służą przejrzystości. Powinny zostać zastąpione separatorem instrukcji⋄
Minęło tyle czasu, odkąd ostatnio stworzyłem tak złożony program APL. Myślę, że był to ostatni raz, ale nie jestem nawet pewien, czy to było tak złożone.
Format wejściowy
Zasadniczo taki sam jak OP, z wyjątkiem użycia
0
wnęki,1
dla dysku i2
dla segmentu linii.Ważna aktualizacja
Udało mi się zagrać w golfa wiele znaków przy użyciu innego algorytmu. Nigdy więcej
g
byków ** t !!Główna funkcja
f
jest podzielona na przypadki:2 2≡x
: Segment-segmentW takim przypadku obliczyć wektor z punktów końcowych każdej linii i rozwiązać układ równań liniowych, aby sprawdzić, czy przecięcie jest zawarte w wektorach.
Ostrzeżenia:
Przykłady: (Uwaga zastrzeżenie 1 w akcji na rysunku po prawej)
2≡2⌷x
: Inne segmentyW tym przypadku drugi obiekt jest okrągły. Sprawdź, czy punkty końcowe segmentu znajdują się w okręgu za pomocą kontroli odległości.
W przypadku dysku zbuduj również odcinek linii o średnicy prostopadłej do danego odcinka. Sprawdź, czy segmenty nie kolidują przez rekurencję.
W przypadku wnęki zakradnij się „razy 0” w konstrukcji wspomnianego segmentu, aby go zdegenerować. (Zobacz, dlaczego używam teraz
0
wnęki i1
dysku?) Ponieważ dany segment nie jest zdegenerowany, wykrywanie kolizji segmentu zawsze zwraca wartość false.Na koniec połącz wyniki kontroli odległości i wykrycia kolizji. W przypadku wnęki najpierw neguj wyniki kontroli odległości. Następnie (w obu przypadkach) LUB 3 wyniki razem.
Jeśli chodzi o zastrzeżenia dotyczące segmentów segmentów, numery 3 są adresowane (i wykorzystywane). Liczba 2 nie stanowi problemu, ponieważ przecinamy tutaj prostopadłe segmenty, które nigdy nie są równoległe, jeśli nie są zdegenerowane. Liczba 1 obowiązuje tylko w przypadku dysku, gdy jeden z podanych punktów końcowych znajduje się na skonstruowanej średnicy. Gdyby punkt końcowy znajdował się dobrze wewnątrz okręgu, zajęłyby go kontrole odległości. Jeśli punkt końcowy znajduje się na okręgu, ponieważ skonstruowana średnica jest równoległa do danego segmentu, ten ostatni musi być styczny do koła, a tylko jeden punkt dotyka dysku, co nie jest prawidłowym wprowadzeniem.
Przykłady:
Domyślny przypadek: inny-inny
Oblicz odległość między środkami. Zderzenie dysku z dyskiem występuje wtedy i tylko wtedy, gdy odległość jest mniejsza niż suma promieni. Zderzenie wnęki dysku następuje wtedy i tylko wtedy, gdy odległość jest większa niż różnica promieni.
Aby zająć się przypadkiem wnęka-wnęka, zaneguj wynik kontroli odległości ORAZ z każdą z liczb całkowitych identyfikujących, a następnie LUB razem. Używając pewnej logiki, można pokazać, że ten proces zwraca wartość true wtedy i tylko wtedy, gdy obie liczby całkowite identyfikujące są fałszem (przypadek wnęki-wnęki) lub jeśli sprawdzenie odległości zwróciło wartość prawda
źródło
JavaScript - 393 bajtów
Zminimalizowane:
Rozszerzony:
Uwagi:
F
która akceptuje wymagane argumenty i zwraca wymaganą wartośćF( 0,[[0,0],[2,2]], 0,[[1,0],[2,4]] )
lubF( 1,[[3,0],1], 2,[[0,0],1] )
.źródło
Python, 284
Używam dość algorytmu śmieciowego w porównaniu do wszystkich tych geometrycznych sztuczek, ale uzyskuje prawidłowe odpowiedzi, mimo że przejście przez przypadki testowe zajmuje więcej niż minutę. Dużą zaletą jest to, że muszę tylko napisać trzy funkcje oceniania, a wspinaczka górska zajmuje się wszystkimi przypadkami na krawędzi.
Gra w golfa:
Nie golfowany:
Na koniec skrypt testowy na wypadek, gdyby ktokolwiek chciał wypróbować to w Pythonie:
źródło