From 616c1edf04c1ec5c95d18efb27b1b02e1231101b Mon Sep 17 00:00:00 2001 From: xiaoxiae <tomas@slama.dev> Date: Tue, 11 Feb 2025 22:30:54 +0100 Subject: [PATCH] Init specifikace --- specifikace.md | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 specifikace.md diff --git a/specifikace.md b/specifikace.md new file mode 100644 index 0000000..15bbef1 --- /dev/null +++ b/specifikace.md @@ -0,0 +1,96 @@ +# 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: + +```python +class Racer: # (loď) + x: int + y: int + vx: int + vy: int + radius: int +``` + +```python +class Asteroid: # (asteroid) + x: int + y: int + radius: int +``` + +```python +class Goal: # (gól) + x: int + y: int + radius: int +``` + +```python +class Instruction: # (instrukce) + vx: InstType + vy: InstType +``` + +```python +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.