Merge pull request 'Další reformulace specifikace' (#2) from kubapelc/asteracer:kubapelc/spec-improvements into master
Reviewed-on: #2
This commit is contained in:
commit
dbb6d513c8
1 changed files with 38 additions and 12 deletions
|
@ -42,6 +42,20 @@ class BoundingBox: # (okraj)
|
|||
max_y: int
|
||||
```
|
||||
|
||||
A tyto funkce:
|
||||
|
||||
```python
|
||||
def distance_squared(x1, y1, x2=0, y2=0) -> int:
|
||||
"""Squared Euclidean distance between two points."""
|
||||
return (int(x1) - int(x2)) ** 2 + (int(y1) - int(y2)) ** 2
|
||||
```
|
||||
|
||||
```python
|
||||
def euclidean_distance(x1, y1, x2=0, y2=0):
|
||||
"""Integer Euclidean distance between two points. Uses integer square root."""
|
||||
return int(isqrt(distance_squared(x1, y1, x2, y2)))
|
||||
```
|
||||
|
||||
## Simulace
|
||||
Každý krok simulace lze rozdělit do následujících tří fází:
|
||||
|
||||
|
@ -71,15 +85,19 @@ Kontrola délky instrukce se provádí porovnáním čtverců délky instrukce a
|
|||
|
||||
### 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).
|
||||
Kolize se řeší v **1 až 5 podkrocích**. Každý podkrok má dvě fáze:
|
||||
|
||||
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.
|
||||
- kontrola kolizí s asteroidy - v této fázi dojde k **nejvýše jedné** kolizi
|
||||
- kontrola kolizí s okraji mapy - kontrolujeme každý ze čtyř okrajů mapy
|
||||
|
||||
Pokud v podkroku nedojde k žádné kolizi (ani s asteroidem, ani s okrajem mapy), považujeme kolize za vyřešené. Pokud ke kolizi dojde, provedeme další podkrok. Podkroků provedeme maximálně 5.
|
||||
|
||||
Pokud v aspoň jednom podkroku dojde ke kolizi (ať už s asteroidem nebo s okrajem mapy), rychlost závodníka se sníží na polovinu.
|
||||
Toto zpomalení může tedy 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:
|
||||
|
||||
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í:
|
||||
|
@ -87,6 +105,9 @@ Iterujeme přes všechny asteroidy `asteroid` v pořadí, v jakém byly přidán
|
|||
- 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`.
|
||||
- **Přestaneme iterovat** přes asteroidy a posuneme se do další fáze podkroku (řešení kolize s okrajem mapy).
|
||||
|
||||
Pokud by tedy loď kolidovala s více asteroidy, vyhodnotíme kolizi pouze s tím, který má nejnižší index.
|
||||
|
||||
#### Ohraničující box
|
||||
Pro každou stranu boxu zkontrolujeme kolizi (například pokud `racer.x - racer.radius < box.min_x` pro levou stranu).
|
||||
|
@ -97,10 +118,15 @@ Iterujeme přes všechny cíle `goal` a označíme je jako dosažené, pokud `eu
|
|||
|
||||
### Poznámky
|
||||
|
||||
Všimněte si, že simulace používá několik neintuitivních zjednodušení:
|
||||
Všimněte si, že simulace má několik neintuitivních zjednodušení a vlastností:
|
||||
|
||||
- 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 nezáleží na tom, v jaké fázi řešení podkroků vydělíme rychlost lodi dvěma
|
||||
- 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 nezáleží na tom, v jaké fázi řešení podkroků vydělíme rychlost lodi dvěma.
|
||||
|
||||
Dále, pro detekci průsečíku lodi s asteroidem či cílem schválně používáme `euclidean_distance`, která má odmocninu zaokrouhlenou dolů.
|
||||
Sice by kolize šly počítat exaktně pomocí druhých mocnin vzdálenosti, ale v okrajových případech bychom naráželi na limity velikosti čísel.
|
||||
|
||||
Naše rustová (vyhodnocovadlo) i typescriptová (webová vizualizace) implementace používá místo exaktní `isqrt` klasickou float64 odmocninu, kterou poté zaokrouhlíme dolů na celé číslo.
|
||||
|
|
Loading…
Reference in a new issue