2022-02-23
This commit is contained in:
parent
35a0c40d14
commit
dc68cce9ed
80 changed files with 859345 additions and 4387 deletions
1
docs_mdbook/.gitignore
vendored
Normal file
1
docs_mdbook/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
book
|
11
docs_mdbook/.vscode/settings.json
vendored
Normal file
11
docs_mdbook/.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"spellright.language": [
|
||||
"de",
|
||||
"en"
|
||||
],
|
||||
"spellright.documentTypes": [
|
||||
"latex",
|
||||
"plaintext",
|
||||
"git-commit"
|
||||
]
|
||||
}
|
6
docs_mdbook/.vscode/vscode-kanban.json
vendored
Normal file
6
docs_mdbook/.vscode/vscode-kanban.json
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"todo": [],
|
||||
"in-progress": [],
|
||||
"testing": [],
|
||||
"done": []
|
||||
}
|
22
docs_mdbook/book.toml
Normal file
22
docs_mdbook/book.toml
Normal file
|
@ -0,0 +1,22 @@
|
|||
[book]
|
||||
authors = ["Daniel Seiller"]
|
||||
language = "en"
|
||||
multilingual = false
|
||||
src = "src"
|
||||
title = "Elite: Dangerous Long Range Router"
|
||||
|
||||
[output.html]
|
||||
preferred-dark-theme = "ayu"
|
||||
mathjax-support = true
|
||||
|
||||
[preprocessor.svgbob]
|
||||
text_width = 8.0
|
||||
text_height = 16.0
|
||||
class = "bob"
|
||||
font_family = "arial"
|
||||
font_size = 14.0
|
||||
stroke_width = 2.0
|
||||
# there's using css-variables from theme:
|
||||
stroke_color = "var(--fg)" # see default theme / variables.css
|
||||
background_color = "transparent" # also useful `var(--bg)`
|
||||
# all properties are optional.
|
12
docs_mdbook/src/SUMMARY.md
Normal file
12
docs_mdbook/src/SUMMARY.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Summary
|
||||
|
||||
- [Intro](./intro/_index.md)
|
||||
- [Galactic Travel in Elite: Dangerous](./intro/ed_travel.md)
|
||||
- [FSD Fuel consumption and jump range](./intro/fsd_fuel.md)
|
||||
- [Graph Search algorithms](./intro/graph_algos.md)
|
||||
|
||||
- [Elite Dangerous Long Range Router](./ed_lrr/_index.md)
|
||||
- [Graph representation](./ed_lrr/graph.md)
|
||||
- [Search modes](./ed_lrr/modes.md)
|
||||
- [Graph precomputation](./ed_lrr/precomp.md)
|
||||
- [Python API](./ed_lrr/py_api.md)
|
1
docs_mdbook/src/ed_lrr/_index.md
Normal file
1
docs_mdbook/src/ed_lrr/_index.md
Normal file
|
@ -0,0 +1 @@
|
|||
# Elite Dangerous Long Range Router
|
4
docs_mdbook/src/ed_lrr/graph.md
Normal file
4
docs_mdbook/src/ed_lrr/graph.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Graph representation
|
||||
|
||||
ED_LRR uses an implicit graph built on top of an R*-Tree for its route computation.
|
||||
Every node (star system) has edges towards all systems within jump range, edge weights (the distance between star systems) can be computed on the fly when necessary
|
31
docs_mdbook/src/ed_lrr/modes.md
Normal file
31
docs_mdbook/src/ed_lrr/modes.md
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Search modes
|
||||
|
||||
## Heuristic
|
||||
|
||||
A*, Greedy and Beam search all use the following heuristic to select candidates to expand on the next layer of the graph
|
||||
|
||||
$$mult(n) =
|
||||
\begin{cases}
|
||||
4 &\text{if $n$ is a neutron star} \\\\
|
||||
1.5 &\text{if $n$ is a white dwarf star} \\\\
|
||||
1 &\text{otherwise}
|
||||
\end{cases}
|
||||
$$
|
||||
|
||||
$$d(a,b) = \sqrt{(a_x-b_x)^2+(a_y-b_y)^2+(a_z-b_z)^2}$$
|
||||
|
||||
$$
|
||||
h(\text{node},\text{goal})=
|
||||
\max(
|
||||
d(\text{node},\text{goal})-
|
||||
(
|
||||
\text{range}*mult(\text{node})
|
||||
),0)
|
||||
$$
|
||||
|
||||
potential new heuristic:
|
||||
|
||||
$$
|
||||
h(\text{node},\text{next},\text{goal})=
|
||||
1 - {\cos^{-1}(|(\text{next}-\text{node})| \cdot |(\text{goal}-\text{node})|)\over\pi}
|
||||
$$
|
2
docs_mdbook/src/ed_lrr/precomp.md
Normal file
2
docs_mdbook/src/ed_lrr/precomp.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Graph precomputation
|
||||
|
58
docs_mdbook/src/ed_lrr/py_api.md
Normal file
58
docs_mdbook/src/ed_lrr/py_api.md
Normal file
|
@ -0,0 +1,58 @@
|
|||
# Python API
|
||||
|
||||
First the module needs to be imported
|
||||
|
||||
```python
|
||||
from _ed_lrr import PyRouter, PyShip
|
||||
```
|
||||
|
||||
Then we need to instantiate a route plotter
|
||||
|
||||
```python
|
||||
# callback is passed a dict describing the current search state and progress
|
||||
def callback(state):
|
||||
print(state)
|
||||
|
||||
r=PyRouter(callback)
|
||||
```
|
||||
|
||||
Optionally ship loadouts can be loaded from the Elite: Dangerous journal files
|
||||
|
||||
```python
|
||||
ships = PyShip.from_journal()
|
||||
```
|
||||
|
||||
To plot a route we need to load a list of star systems with coordinates
|
||||
|
||||
```python
|
||||
r.load("./stars.csv")
|
||||
```
|
||||
|
||||
After a list has been loaded we can resolve star systems to their IDs
|
||||
|
||||
```python
|
||||
systems = [
|
||||
# resolve by coordinates, needs to build an R*-Tree so uses a few GB of RAM
|
||||
(0,0,0),
|
||||
# resolve by name, does fuzzy search, has to scan the whole list of system names
|
||||
"Colonia",
|
||||
# resolve by ID, fairly fast, but the IDs are ed_lrr specific
|
||||
3553323
|
||||
]
|
||||
systems = r.resolve_systems(*query) # this will return a dict mapping the input key to a dict
|
||||
assert sorted(systems.keys())==sorted(query)
|
||||
sys_ids = {k: v["id"] for k, v in systems.items()}
|
||||
```
|
||||
|
||||
Once the system IDs are known we can compute a route
|
||||
|
||||
```python
|
||||
route = r.route(
|
||||
[sys_ids["Sol"], sys_ids["Colonia"]] # route hops, can be any number of systems (at least 2)
|
||||
48.0, # jump range
|
||||
beam_width=1<<12, # beam width to limit exploration (4096)
|
||||
greedyness=0, # greedyness for A* (0=BFS,0.5 = A*, 1=Greedy)
|
||||
max_dist=500, # maximum deviation from straight line (not yet implemented)
|
||||
num_workers=0 # number of workers to distribute the search accross (0 -> serial mode, >=1 -> spawn worker pool)
|
||||
)
|
||||
```
|
17
docs_mdbook/src/fsd.asy
Normal file
17
docs_mdbook/src/fsd.asy
Normal file
|
@ -0,0 +1,17 @@
|
|||
import graph;
|
||||
size(500,0);
|
||||
real fsd(real m_fuel) {
|
||||
// 4A drive
|
||||
real boost = 1.0;
|
||||
real f_max = 3.0;
|
||||
real m_opt = 525.0;
|
||||
real m_ship = 347.0;
|
||||
real l = 12.0;
|
||||
real p = 2.30;
|
||||
return ((boost*m_opt*(1000.0*min(f_max,m_fuel)/l)^(1/p)))/(m_ship+m_fuel);
|
||||
}
|
||||
|
||||
draw(graph(fsd,-100,100,n=500,Hermite),red);
|
||||
|
||||
xaxis("$m_{fuel}$");
|
||||
yaxis("$range (Ly)$",0);
|
1
docs_mdbook/src/intro/_index.md
Normal file
1
docs_mdbook/src/intro/_index.md
Normal file
|
@ -0,0 +1 @@
|
|||
# Intro
|
19
docs_mdbook/src/intro/ed_travel.md
Normal file
19
docs_mdbook/src/intro/ed_travel.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Galactic Travel in Elite: Dangerous
|
||||
|
||||
All ships in Elite: Dangerous (E:D) are equipped with a Frame Shift Drive (FSD) which allows them to jumpst vast distances (multiple light years) from one star system to another.
|
||||
|
||||
The maximum range you can traverse in a single jump is limited by the maximum fuel consuption per jump of the specific drive (depends on class and rating) and influenced by the following factors:
|
||||
|
||||
- Rating of the FSD
|
||||
- Class of the FSD
|
||||
- Mass of your ship (Base mass+Cargo mass+Fuel mass)
|
||||
- Amount of fuel available in the tank
|
||||
|
||||
For details see [the chapter detailing FSD fuel consumption](./fsd_fuel.html)
|
||||
|
||||
If the ship is equipped with a Fuel Scoop it can:
|
||||
|
||||
- Scoop hydrogen from the corona of a star to refill its fuel tank (only applies to stars of class K, G, B, F, O, A or M)
|
||||
- Supercharge its FSD to increase the maximum jump range by a factor of:
|
||||
- 4 if supercharging in the jets of a neutron star
|
||||
- 1.5 if supercharging in the jets of a white dwarf star
|
36
docs_mdbook/src/intro/fsd_fuel.md
Normal file
36
docs_mdbook/src/intro/fsd_fuel.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Notes on FSD Fuel consumption and jump range
|
||||
|
||||
FSD Fuel consumption ([Elite: Dangerous Wiki](https://elite-dangerous.fandom.com/wiki/Frame_Shift_Drive#Hyperspace_Fuel_Equation)):
|
||||
$$Fuel = 0.001 \cdot l \cdot \left(\frac{dist \cdot \left(m_{fuel} + m_{ship}\right)}{boost \cdot m_{opt}}\right)^{p}$$
|
||||
|
||||
Solving for \\(dist\\) gives the jump range (in Ly) for a given amount of fuel (in tons) as:
|
||||
$$dist = \frac{boost \cdot m_{opt} \cdot \left(\frac{1000.0 \cdot \min\left(f_{max}, m_{fuel}\right)}{l}\right)^{\frac{1}{p}}}{m_{fuel} + m_{ship}}$$
|
||||
|
||||
Assuming \\(f_{max}\\) tons of available fuel gives us the maximum jump range for a single jump as:
|
||||
$$dist_{max} = \frac{boost \cdot m_{opt} \cdot \left(\frac{1000.0 \cdot f_{max}}{l}\right)^{\frac{1}{p}}}{f_{max} + m_{ship}}$$
|
||||
|
||||
Since the guardian FSD booster increases the maximum jump range by \\(B_g\\) light years we can calculate a correction factor for the fuel consumption as:
|
||||
$$ e_{fuel} = 0.001 \cdot l \cdot \left(\frac{boost^{2} \cdot m_{opt} \cdot \left(\frac{1000.0 \cdot \min\left(f_{max}, m_{fuel}\right)}{l}\right)^{\frac{1}{p}}}{B_{g} \cdot \left(m_{fuel} + m_{ship}\right) + boost^{2} \cdot m_{opt} \cdot \left(\frac{1000.0 \cdot \min\left(f_{max}, m_{fuel}\right)}{l}\right)^{\frac{1}{p}}}\right)^{p}$$
|
||||
|
||||
Incorporating \\(e_{fuel}\\) into the distance equation yields
|
||||
$$dist = \frac{boost \cdot m_{opt} \cdot \left(\frac{1000.0 \cdot e_{fuel} \cdot \min\left(f_{max}, m_{fuel}\right)}{l}\right)^{\frac{1}{p}}}{m_{fuel} + m_{ship}}$$
|
||||
|
||||
Expanding \\(e_{fuel}\\) yields
|
||||
$$dist = \frac{boost \cdot m_{opt} \cdot \left(1.0 \cdot \left(\frac{boost^{2} \cdot m_{opt} \cdot \left(\frac{1000.0 \cdot \min\left(f_{max}, m_{fuel}\right)}{l}\right)^{\frac{1}{p}}}{B_{g} \cdot \left(m_{fuel} + m_{ship}\right) + boost^{2} \cdot m_{opt} \cdot \left(\frac{1000.0 \cdot \min\left(f_{max}, m_{fuel}\right)}{l}\right)^{\frac{1}{p}}}\right)^{p} \cdot \min\left(f_{max}, m_{fuel}\right)\right)^{\frac{1}{p}}}{m_{fuel} + m_{ship}}$$
|
||||
|
||||
Finally, Expanding \\(dist_{max}\\) yields the full equation as
|
||||
$$dist = \frac{boost \cdot m_{opt} \cdot \left(\frac{1000000.0 \cdot \left(\frac{boost^{2} \cdot m_{opt} \cdot \left(\frac{1000.0 \cdot \min\left(f_{max}, m_{fuel}\right)}{l}\right)^{\frac{1}{p}}}{B_{g} \cdot \left(m_{fuel} + m_{ship}\right) + boost^{2} \cdot m_{opt} \cdot \left(\frac{1000.0 \cdot \min\left(f_{max}, m_{fuel}\right)}{l}\right)^{\frac{1}{p}}}\right)^{- p} \cdot \min\left(f_{max}, m_{fuel}\right)}{l^{2}}\right)^{\frac{1}{p}}}{m_{fuel} + m_{ship}}$$
|
||||
|
||||
Where:
|
||||
- \\(Fuel\\) is the fuel needed to jump (in tons)
|
||||
- \\(l\\) is the linear constant of your FSD (depends on the rating)
|
||||
- \\(p\\) is the power constant of your FSD (depends on the class)
|
||||
- \\(m_{ship}\\) is the mass of your ship (including cargo)
|
||||
- \\(m_{fuel}\\) is the amount of fuel in tons currently stored in your tanks
|
||||
- \\(m_{opt}\\) is the optimized mass of your FSD (in tons)
|
||||
- \\(f_{max}\\) is the maximum amount of fuel your FSD can use per jump
|
||||
- \\(boost\\) is the "boost factor" of your FSD (1.0 when jumping normally, 1.5 when supercharged by a white dwarf, 4.0 for a neutron star, etc)
|
||||
- \\(dist\\) is the distance you can jump with a given fuel amount
|
||||
- \\(dist_{max}\\) is the maximum distance you can jump (when \\(m_{fuel}=f_{max}\\))
|
||||
- \\(B_{g}\\) is the amount of Ly added by your Guardian FSD Booster
|
||||
- \\(e_{fuel}\\) is the efficiency increase added by the Guardian FSD Booster
|
25
docs_mdbook/src/intro/graph_algos.md
Normal file
25
docs_mdbook/src/intro/graph_algos.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Graph Search algorithms
|
||||
|
||||
## Breadth-first search (BFS)
|
||||
|
||||
BFS expand node in breadth first order while keeping track of the parent node of each expanded node
|
||||
|
||||
## Beam search
|
||||
|
||||
Beam search is similar to BFS but limits the number of expanded nodes based on a heuristic
|
||||
|
||||
## Greedy search
|
||||
|
||||
Greedy search is essentially Beam search with a beam width of 1
|
||||
|
||||
## Dijkstra
|
||||
|
||||
Dijkstra's algorithm finds the shortest path across a graph based on some edge weight
|
||||
|
||||
## A*
|
||||
|
||||
A* is similar to Dijkstra but uses a heuristic to speed up the search
|
||||
|
||||
## Beam-Stack search (BSS)
|
||||
|
||||
Beam-Stack search is a variation of beam search which keeps a separate priority queue for each layer of the graph to allow backtracking and expand previously unexpanded nodes
|
47
docs_mdbook/src/range.asy
Normal file
47
docs_mdbook/src/range.asy
Normal file
|
@ -0,0 +1,47 @@
|
|||
|
||||
import graph;
|
||||
import stats;
|
||||
size(500);
|
||||
srand(10);
|
||||
|
||||
struct Star {
|
||||
pair pos;
|
||||
real mult;
|
||||
}
|
||||
|
||||
real range = 48.0;
|
||||
|
||||
int n_stars=1000;
|
||||
Star[] stars=new Star[n_stars];
|
||||
for(int i=0; i < n_stars; ++i) {
|
||||
Star s=new Star;
|
||||
s.pos=(Gaussrand()*range*2,Gaussrand()*range*2);
|
||||
s.mult=1.0;
|
||||
if (unitrand()<0.2) {
|
||||
s.mult=1.5;
|
||||
} else {
|
||||
if (unitrand()<0.1) {
|
||||
s.mult=4.0;
|
||||
}
|
||||
}
|
||||
stars[i]=s;
|
||||
}
|
||||
|
||||
Star origin=new Star;
|
||||
origin.pos=(0,0);
|
||||
origin.mult=1.0;
|
||||
|
||||
draw(circle(origin.pos,range*origin.mult),white);
|
||||
draw(circle(origin.pos,range),white+dashed);
|
||||
draw(circle(origin.pos,range*2),white+dashed);
|
||||
draw(circle(origin.pos,range*4),white+dashed);
|
||||
fill(circle(origin.pos,2),red);
|
||||
|
||||
for (Star s: stars) {
|
||||
if (length(s.pos-origin.pos)<(range*origin.mult)) {
|
||||
draw(s.pos--origin.pos,white+dashed);
|
||||
fill(circle(s.pos,s.mult),green);
|
||||
} else {
|
||||
fill(circle(s.pos,s.mult),white);
|
||||
}
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue