asteracer/specifikace.md

4.5 KiB

Specifikace

Následující dokument obsahuje specifikaci závodu, pokud ji chcete implementovat ve vašem oblíbeném jazyce. Aby závod fungoval stejně v každé implementaci, všechny výpočty jsou prováděny pomocí 64-bitových celých čísel.

Objekty

V rámci závodu definujeme tyto objekty:

class Racer:  # (loď)
    x: int
    y: int
    vx: int
    vy: int
    radius: int
class Asteroid:  # (asteroid)
    x: int
    y: int
    radius: int
class Goal:  # (gól)
    x: int
    y: int
    radius: int
class Instruction:  # (instrukce)
    vx: InstType
    vy: InstType
class BoundingBox:  # (okraj)
    min_x: int
    min_y: int
    max_x: int
    max_y: int

Simulace

Každý krok simulace lze rozdělit do následujících tří fází:

  1. pohyb lodi podle zadané instrukce
  2. řešení kolizí
  3. kontrola dosažení cíle (označení splněných cílů)

Tyto kroky jsou podrobně vysvětleny v následujících sekcích.

Poznámka 1: Pro účely optimalizace je k ukládání asteroidů a cílů vhodné použít nějakou datovou strukturu (například 2D slovník nebo K-d strom), aby stačilo kontrolovat kolize pouze okolo aktuální pozice lodi. Nezapomeňte zohlednit poloměr lodi!

Poznámka 2: Celá část druhé odmocniny, kterou simulace používá, odpovídá Python funkci math.isqrt, která vrací „největší celé číslo takové, že a² ≤ n.“ Tato implementace je přesná a nevyužívá plovoucí desetinnou čárku.

1) Pohyb lodi

S danou instrukcí (vx, vy) se loď pohybuje podle následujících pravidel:

  • zpomalí se o 10 %: racer.velocity = (racer.velocity * 9) // 10
  • k její rychlosti se přidá instrukce: racer.velocity += (vx, vy)
  • závodník se posune podle své rychlosti: racer.position += racer.velocity

Je důležité poznamenat, že operátor dělení zahodí desetinnou část čísla. To znamená, že Pythoní celočíselné dělení nefunguje korektně pro záporná čísla (-5 // 2 = -3), což je v našem případě špatně. Jedním ze způsobů, jak to napravit, je použít abs(x) // v * signum(x), což zajistí správný výsledek.

Instrukce je platná pouze tehdy, pokud její délka (euklidovská vzdálenost) nepřesáhne 127. Kontrola délky instrukce se provádí porovnáním čtverců délky instrukce a maximálního zrychlení (distance_squared(vx, vy) > 127 ** 2).

2) Řešení kolizí

Kolize se řeší v 1 až 5 podkrocích. V rámci každého podkroku se nejprve kontrolují kolize se všemi asteroidy a poté s ohraničujícím boxem. Pokud dojde ke kolizi během podkroku, kolize se vyřeší (viz. níže) a okamžitě se zahájí další podkrok, dokud není dosažen limit (5).

Pokud během celého kroku dojde ke kolizi, rychlost závodníka se sníží na polovinu. Toto zpomalení může nastat nejvýše jednou za krok, bez ohledu na počet kolizí v individuálních podkrocích.

Asteroidy

Iterujeme přes všechny asteroidy asteroid v pořadí, v jakém byly přidány do simulace, a pro každý provádíme následující kroky:

  • Pokud euclidean_distance(asteroid, racer) > (asteroid.radius + racer.radius), kolize nenastala (pokračujeme k dalšímu asteroidu).
  • V případě kolize provedeme následující:
    • Spočítáme vzdálenost: distance = euclidean_distance(asteroid, racer)
    • Vektor k vytlačení závodníka: vn = racer.position - asteroid.position.
    • Vzdálenost posunutí: push_by = distance - (asteroid.radius + racer.radius).
    • Posuneme závodníka: racer.position -= (push_by * vn) / distance.

Ohraničující box

Pro každou stranu boxu zkontrolujeme kolizi (například pokud racer.x - racer.radius < box.min_x pro levou stranu). Pokud ke kolizi dojde, posuneme závodníka zpět k hranici boxu.

3) Kontrola dosažení cíle

Iterujeme přes všechny cíle goal a označíme je jako dosažené, pokud euclidean_distance(racer, goal) <= (racer.radius + goal.radius), tedy pokud dochází k jejich průniku.

Poznámky

Všimněte si, že simulace používá několik neintuitivních zjednodušení:

  • při úvodním posunu lodi o její rychlost nekontrolujeme kolize
  • kolize kontrolujeme až jako průsečík finální pozice lodi s asteroidy či cíle
  • při kolizi s asteroidem se loď neodrazí, tedy nezmění se směr její rychlosti
  • při řešení kolizí loď pouze posouváme ven z asteroidů
  • při kolizi je jedno v jaké fázi řešení podkroků vydělíme rychlost lodi dvěma