GRATULACJE dla @kuroineko. Wygrywa nagrodę za doskonałą prędkość (672 ruchy) na torze Rękawicy.
LIDER: * Nimi zdobył lekką 2129. Inne wpisy są większe, ale wykazują pewną poważną prędkość.
* Lider może ulec zmianie z powodu późniejszych wpisów.
Twoim zadaniem jest napisanie małego programu, który może szybko prowadzić samochód wyścigowy.
Zasady
Twój program odczyta obraz z toru. Możesz uruchomić samochód na dowolnym żółtym pikselu i musisz zakończyć, przekraczając dowolny czarny piksel. Ścieżka samochodu musi znajdować się tylko na szarym ((c, c, c), gdzie 30 <= c <= 220).
Twój samochód będzie poruszał się w linii prostej w każdym zakręcie z prędkością v składającą się z liczb całkowitych vx i vy (zaczynając od (0,0)). Na początku każdej tury twój program może zmieniać vx i vy w taki sposób, że:
abs(vx2-vx1) + abs(vy2-vy1) <= 15
Aktualizacja: Zwiększono maksymalne przyspieszenie do 15.
Następnie program wykreśli prostą linię z bieżącej lokalizacji do (lokalizacja + v) w kolorze białym z niebieską kropką na początku. Jeśli piksel pod tą linią jest czarny, ukończyłeś wyścig. W przeciwnym razie, jeśli wszystkie piksele pod tą linią są szare lub żółte, możesz przejść do następnej tury.
Twój program musi wyświetlać obraz ścieżki z dodaną ścieżką w kolorze białym i niebieskim.
Dodatkowe wyniki (dodano 15.01.2015):
Jeśli chcesz rywalizować o zwycięstwo lub bonus , Twój program powinien również wypisać listę punktów (niebieskie kropki) odpowiednio dla Miasta lub Rękawicy. Dołącz listę punktów do swojej odpowiedzi (do weryfikacji). Punkty powinny wyglądać następująco: (x0,y0), (x1,y1), ... (xn,yn)
. Możesz swobodnie używać białych '\n'
znaków, w tym znaków, aby dopasować dane do strony.
Możesz używać zewnętrznych bibliotek do odczytu i zapisu obrazów, rysowania linii i dostępu do pikseli. Nie można używać bibliotek wyszukiwania ścieżek. Jeśli chcesz, możesz przekonwertować obrazy PNG na inne formaty graficzne (takie jak GIF, JPG, BMP).
Kilka torów do jazdy
Prosta ścieżka na początek:
Tor wyścigowy:
Bieg z przeszkodami:
Miasto:
Nightmare Track: The Gauntlet (jeśli inne są zbyt łatwe)
Punktacja
Twój wynik będzie oparty na twoim wyniku na torze miejskim. Punkty są równe długości programu w bajtach plus 10 punktów za każdy zakręt, który zakończył Twój samochód wyścigowy. Najniższy wynik wygrywa. Dołącz do swojej odpowiedzi zdjęcie trasy biegowej po mieście - chcielibyśmy poznać Twój styl jazdy.
Proszę podać tytuł odpowiedzi w formacie:
<Racing Driver or Team Name> <Language> <Score>
np .: Slowpoke Perl 5329
Twój program musi być w stanie prowadzić na dowolnym obrazie ścieżki zgodnie z powyższymi zasadami. Nie wolno kodować na stałe optymalnej ścieżki ani żadnych parametrów ścieżek testowych. Obowiązują inne standardowe luki.
Podobne wyzwania
To podobna łamigłówka do tej zadanej przez Martina: To Vectory! - Grand Prix wyścigów wektorowych . Ta łamigłówka ma wiele różnic:
- Przejazd przez ściany jest niedozwolony.
- Możesz korzystać z nieograniczonej pamięci i czasu.
- Nie musisz uruchamiać cudzego kodu na swoim komputerze.
- Nie musisz pobierać niczego oprócz jednego obrazu.
- Rozmiar twojego kodu liczy się w punktacji. Mniejszy jest lepszy.
- Tworzysz rozwiązanie na obrazie toru.
- Możesz łatwo tworzyć własne ścieżki za pomocą pakietu farb.
- Wyższa rozdzielczość zachęca do bardziej realistycznego hamowania i pokonywania zakrętów.
- Przyspieszenie 15 stwarza około 450 możliwości na turę. To sprawia, że BFS jest mniej wykonalny i zachęca do nowych interesujących algorytmów.
Ta łamigłówka powinna zainspirować nową rundę programistów do wypróbowania rozwiązań i pozwolić programistom ze starych rozwiązań na przemyślenie ich w nowym środowisku.
źródło
Odpowiedzi:
TS # 1 - Haskell - 1699 + 430 = 2129
Rodzeństwo Tutu # 1
Bardzo podobny do oryginalnego wyścigowca Tutu, z tą różnicą, że używa grubości 3 dla rozdętej ścieżki, a druga A * (przestrzeń prędkości-pos) idzie ze stałą heurystyką
1
. Obraz wejściowy nie jest już przekazywany jako argument wiersza poleceń, musi zostać nazwanyi
. Nazwa obrazu wyjściowego too
. Program drukuje obliczone punkty na ścieżce jako listę par x, y (oryginalne wyjście to pojedynczy wiersz):Mógłbym zaoszczędzić wiele bajtów, kiedy zaczynam usuwać całą mapę i ustawiać struktury danych i zastępować je prostymi połączonymi listami. Tylko dwie instrukcje importu pozwoliłyby zaoszczędzić 60 bajtów. Spowolniłoby to program, tak że oczekiwanie na wynik jest czystym bólem. Ta wersja zajmuje ponad 45 minut dla The City, w porównaniu z 7s oryginału. Przestanę tutaj wymieniać bajty na szybkość wykonywania.
Kod wymaga flagi -XNoMonomorphismRestriction do skompilowania.
Miasto - TS # 1 - 43 kroki
źródło
FirstRacer Java (5825 + 305 * 10 = 8875)
Po prostu na początek. Potrzebuje 305 segmentów w mieście.
Ten program Java wykonuje potok:
Myślę, że tor wyścigowy daje lepsze wrażenie, jak działa FirstRacer.
źródło
pighead PHP (5950 + 470 = 6420)
Kolejna odmiana BFS (z główkami), z pewnym wstępnym przetwarzaniem w celu zmniejszenia przestrzeni poszukiwań.
Wybór języka
PHP jest całkiem dobry w obsłudze obrazów.
Ma również natywną pamięć asocjacyjną, dzięki czemu programowanie wyszukiwania węzłów BFS jest dziecinnie proste.
Minusem jest to, że haszowanie identyfikatorów węzłów nie jest strasznie czasochłonne, więc wynik jest szybki.
Z moich eksperymentów z poprzednim wyzwaniem wyścigowym nie mam wątpliwości, że C ++ 11 i jego tablice skrótów działałyby znacznie lepiej, ale kod źródłowy przynajmniej by się podwoił, plus potrzeba jakiejkolwiek zewnętrznej biblioteki png (nawet LodePNG) zrobić niechlujną wersję.
Perl i jego bardziej zaawansowane potomstwo prawdopodobnie pozwoliłyby na bardziej zwarty i wydajny kod (ze względu na lepszą wydajność mieszania), ale nie znam się na żadnym z nich, aby wypróbować port.
Rdzeń BFS
Wyszukiwanie działa na pozycji + przestrzeń prędkości, tzn. Węzeł reprezentuje daną lokalizację odwiedzaną z określoną prędkością.
To oczywiście zapewnia dość dużą przestrzeń wyszukiwania, ale daje optymalne wyniki, pod warunkiem, że zbadane zostaną wszystkie możliwe lokalizacje torów.
Oczywiście, biorąc pod uwagę liczbę pikseli nawet na małym obrazie, wyczerpujące wyszukiwanie nie wchodzi w rachubę.
Kawałki
Wybrałem przecięcie przestrzeni pozycji, wybierając tylko podzbiór pikseli ścieżki.
Solver weźmie pod uwagę wszystkie pozycje w zasięgu, ograniczone tylko przyspieszeniem.
Ścieżka jest wyłożona kwadratami, których maksymalny rozmiar jest obliczany, dzięki czemu można uzyskać dwa sąsiednie kwadraty z maksymalnym dozwolonym przyspieszeniem (tj. 14 x 14 pikseli przy aktualnym ograniczeniu prędkości).
Po zapakowaniu toru dużymi kwadratami, do wypełnienia pozostałej przestrzeni używa się coraz mniejszych płytek.
Tylko środek każdej płytki jest uważany za możliwy cel.
Oto przykład:
Ten heurystyczny wybór wystarczy, aby solver zawiódł na mapie koszmaru. Przypuszczam, że można spróbować zmniejszyć maksymalny rozmiar kafelka, dopóki nie zostanie znalezione jakieś rozwiązanie, ale przy obecnych ustawieniach solver działa przez około godzinę i używa 600 Mb, więc dokładniejsze wyniki wymagałyby nieuzasadnionego czasu i pamięci.
Jako drugie cięcie można pominąć kwadraty o wielkości zaledwie 1 piksela.
To oczywiście pogorszy rozwiązanie, a nawet uniemożliwi znalezienie solwera, ale znacznie skraca czas obliczeń i zwykle daje całkiem bliskie wyniki na „prostych” mapach.
Na przykład w mieście pominięcie kwadratów piksela 1 x 1 zmniejsza zbadane węzły drzewa BFS z 660 K do około 90 K dla rozwiązań 47 vs 53 ruchów.
BFS vs A *
* Wymaga więcej kodu i nie ma nawet gwarancji, że przyniesie szybsze wyniki w przestrzeni pozycji / prędkości, ponieważ ocena najlepszego następnego kandydata nie jest tak prosta, jak w klasycznej spacji tylko dla pozycji (którą można łatwo pokonać dzięki celowo opracowanemu kulturowi w każdym razie de-sacs).
Poza tym, chociaż PHP ma pewne priorytetowe kolejki, które, nawiasem mówiąc, obsługują dynamiczne zmienianie kolejności kont w swoich kuzynach C ++, wątpię, czy wystarczyłyby do wydajnej implementacji A * i przepisania stosu binarnego lub innej dedykowanej struktury kolejki A * wymagają o wiele za dużo linii kodu.
Kontrola ściany
Nie użyłem algorytmu Bresenhama do sprawdzania kolizji na ścianie, więc trajektoria może obciąć nieparzysty piksel na ścianie. Nie powinno jednak pozwolić na przejście przez ścianę.
Występy
Ten solver na pewno nie ma sześcionożnego jackrabbit.
Bez dodatkowego cięcia mapa może zająć ponad 10 minut na rozwiązaniu na moim komputerze średniego zasięgu.
Sugeruję ustawienie minimalnego rozmiaru kafelka na 2 lub 3, jeśli chcesz bawić się kodem bez spędzania wieków na oczekiwaniu na wynik.
Zużycie pamięci jest rozsądne dla tego rodzaju algorytmu i języka: około 100 Mb lub mniej, z wyjątkiem koszmaru o wartości szczytowej powyżej 600 Mb.
Wyniki i punktacja
Wyniki są podawane bez cięcia „minimalnego rozmiaru płytki”.
Jak uważny czytelnik może wywnioskować z moich ogólnych komentarzy, nie dbam o golfową część tego wyzwania. Nie rozumiem, jak uruchomienie mojego kodu przez obfuscator lub usunięcie niektórych optymalizacji i / lub procedur debugowania w celu zmniejszenia źródła sprawiłoby, że byłoby to jeszcze przyjemniejsze.
Niech na razie rozmiar S będzie bajtem źródłowym:
ścieżka S + 1020
miasto S + 470
przeszkody S + 280
koszmar -> kończy się niepowodzeniem
źródło
SecondRacer Java (1788 + 72 * 10 = 2508)
(2708) (2887) (3088) (3382) (4109 + 72 * 10 = 4839) (4290 + 86 * 10 = 5150)Podobne do FirstRacer. Różni się to jednak w krokach 2.2 i 3., co prowadzi do dalekowzroczności i używania sprzętu.
Wydajność
Żadna z tych ścieżek nie stanowi problemu dla A *. Zaledwie kilka sekund (<10) do rozwiązania (nawet „Nightmare Track: The Gauntlet”) na moim komputerze średniego zasięgu.
Styl ścieżki
Nazywam to ośmiornicą. Zdecydowanie nie tak elegancki, jak rozwiązanie dla świni (od kuroi neko).
Styl kodu
Przeszedłem do umiarkowanego trybu walki, zachowując czytelność. Ale dodano wersję golfową.
golfed -> OSTRZEŻENIE: zastępuje oryginalny plik!
Wszystkie obrazy są wyświetlane na krajobrazie gradientowym A *. Począwszy od jasnożółtego do brązowego (= ciemnożółty). Podczas gdy - zgodnie z A * - uzyskana ścieżka jest śledzona do tyłu (tutaj od brązowego do jasnożółtego).
Tor wyścigowy S + 175
Tor przeszkód S + 47
Miasto S + 72
Rękawica S + 1133
źródło
Tutu - Haskell - (
3460265424762221206019921900 + 50x10 = 2400)Strategia:
Golf:
Nie jestem golfistą Haskell, więc nie wiem, ile jeszcze można zaoszczędzić (edycja: okazało się, że to całkiem sporo).
Wydajność:
Gauntlet działa w 9: 21min na moim 1,7 GHz Core i5 od 2011 roku. Miasto zajmuje 7,2 sekundy. (użyte -O1 z ghc, -O2 powoduje, że program jest strasznie wolny)
Opcje przeróbki to grubość rozdętej ścieżki. Dla mniejszych map odległość 3 oszczędza jeden lub dwa kroki, ale Rękawica działa zbyt długo, więc pozostaję z odległością 2. Wyścig rozpoczyna się zawsze od pierwszego (tj. Lewego górnego) żółtego piksela, optymalizacja ręcznie powinna zaoszczędzić dodatkowy krok.
Zgodność reguł:
„Nie możesz używać bibliotek wyszukiwania ścieżek.” - Tak, ale źródło jest włączone. Funkcje wyszukiwania A * są
niecomocno golfowymi wersjami biblioteki Data.Graph.AStar Cale'a Gibbarda (patrz http://hackage.haskell.org/package/astar ).Miasto - 50 kroków
Gauntlet - 722 kroki
Nie golfowany:
Gra w golfa:
Rodzeństwo Tutu -TS # 1 - (1764 + 43 = 2194)Edycja: TS # 1 teraz osobna odpowiedź.
Edycja II: Ścieżka do miasta jest
W The Gauntlet Tutu porusza się w następujący sposób
źródło
-O2
spowalnia program? dziwne. próbowałem-O3
?Maybe
że dużo używasz . może możesz zastąpićMaybe
listami:Maybe a
jest[a]
,Nothing
jest[]
iJust x
jest[x]
.Maybe
monada stanie się równaList
monadzie. możesz wtedy użyć dla nich wielu funkcji listy:null
,head
,(:[])
,map
i tak dalej.Gwiazda skrzyżowana - PHP - 4083 + 440 = zdecydowanie za ciężki
Ok, po 3 tygodniach bez połączenia z Internetem (dzieje się tak, gdy jeden z najbardziej okrutnych konkurentów twojego dostawcy odpowiada za zatokę budowlaną, a przynajmniej tak dzieje się w Paryżu, Francja) Mogę wreszcie opublikować moja następna próba.
Tym razem użyłem algorytmu A * i bardziej wydajnej strategii dystrybucji punktów.
Jako dodatkowy bonus napisałem coś w rodzaju PHP Crunchera, aby rozwiązać golfową część wyzwania.
A teraz, gdy solver działa na wszystkich proponowanych mapach, błąd śledzenia linii został naprawiony.
Nigdy więcej przycinania ścian (choć nadal wypasuje się, tak jak powinien :)).
uruchomienie kodu
nadaj kodowi dowolną nazwę (
runner.php
na przykład), a następnie wywołaj go w następujący sposób:Po dłuższym milczeniu powinien wygenerować
_track.png
wynik pokazujący rozwiązanie.Jak widać na obrazach wyjściowych, kod jest bardzo wolny. Zostałeś ostrzeżony.
Oczywiście moja prywatna wersja jest pełna śladów i tworzy ładne przedstawienia różnych informacji (w tym okresowe zdjęcie pokazujące postęp A *, aby pomóc zabić czas), ale za grę w golfa trzeba zapłacić ...
kod do gry w golfa
wersja bez golfa
Wyniki
Zdjęcia są tworzone przez bogatszą wersję, która wyświetla dokładnie to samo rozwiązanie z pewnymi statystykami na dole (i rysuje ścieżkę za pomocą antyaliasingu).
Mapa miasta jest dość dobrym przykładem tego, dlaczego algorytmy oparte na pozycji muszą w wielu przypadkach znaleźć słabe wyniki: krótszy nie zawsze oznacza szybszy.
(672 ruchów, jeśli nie chcesz powiększać)
ZA*
Ku mojemu zaskoczeniu, A * radzi sobie dość dobrze na przestrzeni prędkości i pozycji. W każdym razie lepsze niż BFS.
Musiałem jednak trochę się pocić, aby uzyskać działający heurystyczny szacunek odległości.
Musiałem to nieco zoptymalizować, ponieważ liczba możliwych stanów jest ogromna (kilka milionów) w porównaniu z wariantem tylko pozycji, który ponownie wymaga więcej kodu.
Dolna granica wybrana dla liczby ruchów niezbędnych do osiągnięcia celu z danej pozycji to po prostu czas potrzebny do pokonania odległości do najbliższego celu w linii prostej z zerową prędkością początkową .
Oczywiście ścieżka linii prostej zwykle prowadzi bezpośrednio do ściany, ale jest to mniej więcej ten sam problem, co użycie prostej odległości euklidesowej do wyszukiwania A * tylko w przestrzeni.
Podobnie jak odległość euklidesowa dla wariantów zajmujących tylko przestrzeń, główną zaletą tej metryki, oprócz tego, że dopuszczalne jest użycie najbardziej wydajnego wariantu A * (z zamkniętymi węzłami), wymaga bardzo niewielkiej analizy topologicznej toru.
Przy maksymalnym przyspieszeniu A liczba n ruchów potrzebnych do pokonania odległości d jest najmniejszą liczbą całkowitą spełniającą zależność:
d <= A n (n + 1) / 2
Rozwiązanie tego dla n daje oszacowanie pozostałej odległości.
Aby to obliczyć, tworzona jest mapa odległości do najbliższego celu, przy użyciu algorytmu wypełniania zalewem obsadzonego pozycjami celów.
Ma przyjemny efekt uboczny polegający na eliminowaniu punktów toru, z których nie można osiągnąć celu (jak to ma miejsce w niektórych obszarach toru koszmaru).
Liczba ruchów jest obliczana jako wartość zmiennoprzecinkowa, dzięki czemu węzły bliżej celu mogą być dalej dyskryminowane.
Punkty trasy
Podobnie jak w mojej poprzedniej próbie, pomysł polega na zmniejszeniu liczby punktów trasy do jak najmniejszej podpróbki punktów drogi. Sztuką jest wybranie najbardziej „przydatnych” pozycji na torze.
Heurystyka zaczyna się od regularnego podziału na całą ścieżkę, ale zwiększa gęstość w dwóch rodzajach obszarów:
Oto przykład.
Obszary o wysokiej gęstości są w kolorze czerwonym, a obszary o niskiej gęstości w kolorze zielonym. Niebieskie piksele to wybrane punkty.
Zwróć uwagę na skupiska punktów na ostrych zakrętach (wśród wielu bezużytecznych plam na pochyłych łukach, z powodu niewystarczającego filtrowania).
Aby obliczyć pozycje pasów ruchu, cała ścieżka jest skanowana w poszukiwaniu odległości do najbliższej ściany. Wynikiem jest pole wektorów wskazujące w kierunku najbliższej granicy ścieżki.
To pole wektorowe jest następnie przetwarzane w celu zgrubnego oszacowania lokalnej krzywizny.
Wreszcie, krzywizna i odległość do ściany są łączone, aby uzyskać pożądaną lokalną gęstość, a raczej niezgrabny algorytm próbuje odpowiednio przelać punkty na ścieżce.
Istotną poprawą w stosunku do poprzedniej strategii jest to, że wąskie pasy zawsze (jak się wydaje) zawsze będą miały wystarczającą liczbę punktów do przejechania, co pozwala poruszać się po mapie koszmaru.
Jak zawsze chodzi o znalezienie optymalnego punktu między czasem obliczeń a wydajnością.
Zmniejszenie gęstości o 50% spowoduje podzielenie czasu obliczeń przez więcej niż 4, ale z grubszymi wynikami (48 ruchów zamiast 44 w mieście, 720 zamiast 670 w koszmarze).
Gra w golfa
Nadal uważam, że gra w golfa szkodzi kreatywności w tym konkretnym przypadku: usunięcie antyaliasingu z wyjścia wystarczy, aby zdobyć 30 punktów i wymaga dużo mniej wysiłku niż przejście z 47 do 44 ruchów na mapie miasta.
Nawet przejście od 720 do 670 ruchów w koszmarze zyskałoby zaledwie 500 punktów, choć bardzo wątpię, aby A * tylko pozycja był w stanie zbliżyć się do tego miejsca.
Dla zabawy postanowiłem napisać własny kompresor PHP.
Jak się wydaje, wydajna zmiana nazwy identyfikatorów w PHP nie jest łatwym zadaniem. W rzeczywistości nie sądzę, że można to zrobić w ogólnym przypadku. Nawet przy pełnej analizie semantycznej możliwość użycia ciągów lub zmiennych pośrednich do wyznaczenia obiektów wymagałaby znajomości semantyki każdej funkcji.
Ponieważ jednak bardzo wygodny wbudowany parser pozwala od razu przejść do analizy semantycznej, udało mi się stworzyć coś, co wydaje się działać na podzbiorze PHP wystarczającym do napisania kodu „golfable” (trzymaj się z dala od $$ i nie użyj pośrednich wywołań funkcji lub innego dostępu do obiektów przez łańcuch).
Nie ma praktycznego zastosowania do mówienia i nie ma nic wspólnego z pierwotnym problemem, ale dużo zabawy z kodowaniem.
Mogłem zmodyfikować kod, aby uzyskać dodatkowe 500 znaków, ale ponieważ nazwy bibliotek graficznych PHP są niestety dość długie, jest to rodzaj trudnej walki.
Dalsze zmiany
Kod wyboru punktu trasy to przerażający bałagan, dostrajany metodą prób i błędów. Podejrzewam, że wykonanie większej liczby obliczeń matematycznych (przy użyciu odpowiednich operatorów gradientu i zawijania) znacznie poprawiłoby ten proces.
Jestem ciekawy, czy można znaleźć lepszą heurystykę na odległość. Próbowałem wziąć pod uwagę prędkość na kilka sposobów, ale albo złamał A *, albo przyniósł wolniejsze wyniki.
Może być możliwe przekodowanie tego wszystkiego w szybszym języku, takim jak C ++, ale wersja PHP w dużej mierze opiera się na wyrzucaniu elementów bezużytecznych, aby utrzymać rozsądne zużycie pamięci. Czyszczenie zamkniętych węzłów w C ++ wymagałoby sporo pracy i znacznej ilości dodatkowego kodu.
Gdyby ocena opierała się na wynikach, chętnie próbowałbym ulepszyć algorytmy. Ale ponieważ kryterium gry w golfa jest tak przytłaczające, nie ma sensu, prawda?
źródło
ThirdRacer Java (1224 + 93 * 10 = 2154)
Podobne do SecondRacer. Ale zmiana fokusu z prędkości na rozmiar kodu (ale nadal przy użyciu Java). Optymalizacja przyspieszenia jest teraz znacznie uproszczona, co niestety skutkuje wolniejszym samochodem.
Wydajność
Lepsze niż SecondRacer.
Styl ścieżki
Jak SecondRacer.
Styl kodu
Weszłam w tryb ciężkiej walki.
golfed -> OSTRZEŻENIE: zastępuje oryginalny plik w miejscu!
Miasto S + 93
źródło
Gwiazda skrzyżowała ścieżkę wyścigową na mapie koszmaru
(zgodnie z popularnym żądaniem)
(kod nie został zaktualizowany, ponieważ modyfikacje są trywialne, a wyzwanie polegające wyłącznie na wydajności nie jest rozgrywane)
Przepraszam, że opublikowałem kolejny wpis, ale osiągam limit 30 000 znaków w stosunku do poprzedniego.
Po prostu powiedz słowo, a ja je usunę.
źródło
Sunday Driver, Python 2, 3242
Kod minimalny = 2382 bajty
Wydajność: miasto = 86 przeszkód = 46 tor wyścigowy = 188 rękawica = 1092
Oto mój program weryfikacji koncepcji, który miał wykazać, że rozwiązanie jest możliwe. Wymaga optymalizacji i lepszego gry w golfa.
Operacja
Utwórz strukturę danych pierścieni odległości na zewnątrz miejsca docelowego (prosta pochodna A *, jak wypełnienie zalewowe)
Znajdź zwartą serię prostych linii do miejsca docelowego, które nie przecinają pikseli nie śledzących.
Dla każdej linii prostej przyspiesz i hamuj, aby zminimalizować liczbę zakrętów.
Kod w golfa (zminimalizowany)
Przykłady
źródło