RampantTrackGeneration is the Track generation logic for Rampant on the Tracks.
The logic is invoked by calling
@staticmethod
def generate_track(
diagram_width: int,
diagram_height: int,
num_diagram_regions: int,
length_min_quantile: float,
num_path_nodes_min_quantile: float,
max_fuel_cost: float,
min_cycle_period: int,
max_cycle_period: int,
max_length_travel_duration_seconds: int,
stop_radius: int,
take_screenshots: bool = False
) -> Track:
in TrackGenerator.
Track
@dataclass(frozen=True)
class Track:
nodes: dict[uuid4, Point]
edges: dict[uuid4, EdgeVertexInfo]
start_node_id: uuid4
destination_node_id: uuid4
start_destination_path_edges: tuple[uuid4]
node_info: dict[uuid4, NodeInfo]
edge_info: dict[uuid4, EdgeInfo]
describes a set of edges, each a connection between two Points. nodes are the Points.
generate_track derives the Track from a randomly generated Voronoi diagram.
It preserves the organic appeal of the diagram's shape - unevenly spaced points, connected by edges of varying length - and goes on to enhance that by
- calculating
diagram_edge_min_acceptable_length, the{length_min_quantile * 100}%quantile of all edge lengths - finding
edges_to_reconnect, all the edges where eitheredge_length<diagram_edge_min_acceptable_length_edge_can_be_contracted()- The probability of this method evaluating to
Trueis based on how many " lonely " neighbors the edge'sPoints have.- A
Pointis lonely if it has only one neighbor (in this case, one of the edge's twoPoints).
- A
- The probability of this method evaluating to
- processing
edges_to_reconnect- for each
edge_to_reconnect- taking edge points
AandB, and determiningML, the one that has more lonely neighbors (making the other oneLL, less lonely) - connecting all of
ML's neighbor points toLL- for neighbour point
NP, we'd examine the edgeNP<->ML- if that edge was not created as part of the subsequent process, we'd
- replace the edge
NP<->MLwithNP<->LL - delete
NP<->ML
- replace the edge
- if that edge was not created as part of the subsequent process, we'd
- for neighbour point
- deleting
A<->Bif theMLedges in the last step were all valid for replacement- otherwise, edge removal would break the graph into subgraphs
- taking edge points
- for each
- deleting all edges that could be deleted to break " cycles " (sets of edges that constitute loops)
- calculating edge fuel costs, number of stops, and " junction block cycle " period
- determining
start_node_idanddestination_node_id - constructing and returning a
Trackfrom the information so far
The diagram is generated with Voronout and modeled with rustworkX.
Track generation, visualized
voronoi_points:
(Point(x= 0.9463, y= 0.6669), Point(x= 0.4353, y= 0.5272), Point(x= 0.4222, y= 0.5968), Point(x= 0.9876, y= 0.5229), Point(x= 0.5794, y= 0.964), Point(x= 0.5983, y= 0.0106), Point(x= 0.687, y= 0.1437), Point(x= 0.4132, y= 0.2723), Point(x= 0.0361, y= 0.1436), Point(x= 0.062, y= 0.2417), Point(x= 0.8191, y= 0.4291), Point(x= 0.5383, y= 0.8066), Point(x= 0.5011, y= 0.365), Point(x= 0.3063, y= 0.9677), Point(x= 0.9008, y= 0.0296), Point(x= 0.2748, y= 0.7383), Point(x= 0.8428, y= 0.0683), Point(x= 0.1703, y= 0.0407))
Initial Voronoi diagram:
Edge contraction:
Edge deletion:
Stop generation:
Final Track:
Track info
node_info contains further information about nodes
@dataclass(frozen=True)
class NodeInfo:
num_steps_to_destination: int
num_seconds_block_cycle: int
for game logic - num_steps_to_destination tells you how many edges away it is from destination_node_id's node, while num_seconds_block_cycle is used in the " junction block cycle " mechanic.
edge_info is likewise for edges
@dataclass(frozen=True)
class EdgeInfo:
edge_traversal_fuel_cost: float
edge_traversal_duration: float
edge_stop_info: tuple[StopInfo]
edge_image_default_b64: str
edge_image_focused_b64: str
edge_traversal_fuel_cost is the fuel spent in-game by a Walker traversing the edge - edge_traversal_duration is the time it takes to do so in seconds, used for animation purposes.
edge_image_*_b64 are the edge's graphical representations in its default/focused states, stored in base64. The game converts them into sprites to show on-screen.
@dataclass(frozen=True)
class StopInfo:
stop_point: Point
stop_id: uuid4
stop_fuel: float
stop_fuel is how much fuel a Walker can draw from the stop.
Release files for RampantTrackGeneration 0.0.2.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| rampanttrackgeneration-0.0.2.1.0.tar.gz | 6.6 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rampanttrackgeneration-0.0.2.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 6.6 MB
Release files / rampanttrackgeneration-0.0.2.1.0.tar.gz
| Download URL | rampanttrackgeneration-0.0.2.1.0.tar.gz |
|---|---|
| Size | 6.6 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f697f8957f72ca9bd27f08c7d237d46ed82bf3d6da39f0a30cbf0dd7843b60e5
|
|
BLAKE2b-256 checksum How to use checksums |
97d2db723ad1b214020c57839726c50ff8e8610ed6ebc170bb1ecf91327df915
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.0
|
Release files / rampanttrackgeneration-0.0.2.1.0-py3-none-any.whl
| Download URL | rampanttrackgeneration-0.0.2.1.0-py3-none-any.whl |
|---|---|
| Size | 18.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7906e8b21d6a2cffc88bfbf6528a07c91585f546167f73ffeaf9c5436f4bfd86
|
|
BLAKE2b-256 checksum How to use checksums |
b2ab621bc1167c396899d3f6bc98984c6c80067e2ed3c4976a7ded253ac21918
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.0
|