Spaces:
Sleeping
Sleeping
Download core/rail_core/network.py from bpHigh/RailSimEnv: direct link, hf CLI and curl.
- Browser
- Download file 3.24 kB
-
https://huggingface.co/spaces/bpHigh/RailSimEnv/resolve/main/core/rail_core/network.py
- Command line
-
hf download hf://spaces/bpHigh/RailSimEnv/core/rail_core/network.py
-
curl -L -o network.py https://huggingface.co/spaces/bpHigh/RailSimEnv/resolve/main/core/rail_core/network.py
3.24 kB
| """The line: points west to east (terminals, stations, halts, junctions) and the sections between them. | |
| A section joins two neighbouring points and is single or double track. A point has a number of tracks (None: as many | |
| as needed, the terminals), may be *directional* (a station on double track: one track per direction, so two trains | |
| going the same way cannot both stand there and nothing overtakes), and may be a *turn* point where a train can be | |
| short-turned. Junctions are where double track becomes single between two stations; trains pass them but never stop. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| from dataclasses import asdict, dataclass | |
| from pathlib import Path | |
| _UP = Path(__file__).resolve().parents | |
| DATA = (_UP[4] if len(_UP) > 4 else _UP[-1]) / "data" # the repository's data/: only curation and builds read it | |
| class Point: | |
| code: str | |
| name: str | |
| km: float | |
| kind: str # terminal | station | halt | junction | |
| tracks: int | None # None: unlimited (terminal) | |
| directional: bool # one track per direction (station on double track) | |
| turn: bool # trains may be short-turned here | |
| def stoppable(self) -> bool: | |
| return self.kind != "junction" | |
| class Section: | |
| a: str # west end | |
| b: str # east end | |
| single: bool | |
| prorail: str = "" | |
| class Network: | |
| def __init__(self, points: list[Point], sections: list[Section], line: str = "", name: str = ""): | |
| self.line, self.name = line, name | |
| self.points = points | |
| self.sections = sections | |
| self.index = {p.code: i for i, p in enumerate(points)} | |
| self.by_code = {p.code: p for p in points} | |
| for i, s in enumerate(sections): | |
| if (self.index[s.a], self.index[s.b]) != (i, i + 1): | |
| raise ValueError(f"section {s.a}-{s.b} is not between neighbouring points {i} and {i + 1}") | |
| def from_dict(cls, d: dict) -> "Network": | |
| return cls([Point(**p) for p in d["points"]], [Section(**s) for s in d["sections"]], d.get("line", ""), | |
| d.get("name", "")) | |
| def to_dict(self) -> dict: | |
| return {"line": self.line, "name": self.name, "points": [asdict(p) for p in self.points], | |
| "sections": [asdict(s) for s in self.sections]} | |
| def section(self, x: str, y: str) -> int: | |
| """Index of the section between neighbouring points x and y (either order).""" | |
| i, j = self.index[x], self.index[y] | |
| if abs(i - j) != 1: | |
| raise ValueError(f"{x} and {y} are not neighbours") | |
| return min(i, j) | |
| def route(self, a: str, b: str) -> list[str]: | |
| """Every point from a to b inclusive, in travel order.""" | |
| i, j = self.index[a], self.index[b] | |
| step = 1 if j >= i else -1 | |
| return [self.points[k].code for k in range(i, j + step, step)] | |
| def direction(self, a: str, b: str) -> int: | |
| """+1 eastbound (towards the last point), -1 westbound.""" | |
| return 1 if self.index[b] > self.index[a] else -1 | |
| def load_network(line: str = "gnlw") -> Network: | |
| return Network.from_dict(json.loads((DATA / line / "network.json").read_text())) | |