Skip to content

Conversation

@scamiv
Copy link
Contributor

@scamiv scamiv commented Nov 18, 2025

This is not yet a pr but a idea to tackle multiple train related issues. Feedback very welcome! Code needs cleanup!

Description:

Before: Trains followed fixed, pre-calculated paths between stations using a pathfinding algorithm
After: After: Trains now use a local cost based routing system.

Local Greedy Routing (Smart decision-making at each station)

At each station, trains evaluate neighboring stations based on multiple factors:
Profit potential: How much gold they can earn based on diplomatic relationships
Traffic congestion: Avoids overcrowded stations
Travel distance: Considers physical distance and travel time
Recent history: Avoids recently visited stations to prevent loops
Some randomness: chance of making a non-optimal choice for exploration

Key Benefits

Organic route discovery: Routes improve as trains explore the network
Congestion avoidance: Trains naturally spread out to less busy areas
Adaptive behavior: System responds to changing network conditions
Loop prevention: Memory of recent visits discourages trains from getting stuck

Currenlty disabled:
BATMAN like broadcast.
Stations broadcast routing information to neighbors like the BATMAN wireless mesh protocol Builds a distributed routing table that learns about the entire network over time Handles network topology changes automatically
Uses lazy cleanup to manage memory efficiently

Settings need to be tweaked

Performance impact is not yet measured, but could be positive.

Describe the PR.

Please complete the following:

  • I have added screenshots for all UI updates
  • I process any text displayed to the user through translateText() and I've added it to the en.json file
  • I have added relevant tests to the test directory
  • I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced

Please put your Discord username so you can be contacted if a bug or regression is found:

DISCORD_USERNAME

…lection

Replace fixed pathfinding with dynamic routing system featuring:
- Local greedy routing: Trains evaluate neighbors based on profit potential, traffic congestion, distance, and recent history
- Exploration capability: 10% randomness prevents suboptimal but discovers new routes
- Congestion avoidance: Trains naturally spread to less busy stations
- Loop prevention: Memory of recent visits prevents getting stuck
- Adaptive behavior: System responds to changing network conditions
- Enhanced journey tracking: Share complete route information instead of just start position

Includes BATMAN-style routing protocol (currently disabled) for future network-wide knowledge distribution.
…urney transmission, journeySource wasnt loop proof
- Added search radius
- Updated several properties in TrainStation class to be readonly for better immutability and clarity.
- Introduced heat decay interval and factor for more flexible heat management.
- pre-computed decay factors avoiding Math.pow in critical paths.
- Enhance logging
- Refined routing logic
- removed journeyPreviousStation property
- removed RecentArrivals
- unbounded StationTraffic.heat -> score can now be negative
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 18, 2025

Walkthrough

Refactors train traversal to local greedy routing with journey tracking and hop limits; adds station-originated routing broadcasts and traffic metrics; injects station tick calls; extends Game API and GameImpl with train arrival/hop-limit recording and runtime stats; invokes station cleanup on removal.

Changes

Cohort / File(s) Change Summary
Train execution
src/core/execution/TrainExecution.ts
Replaces path-array navigation with step-based greedy routing: currentStation, recentStations, hop counters, arrival/departure handling, getNextStep() and shareJourneyInfo(); adds arrival processing, hop-limit removal, and car positioning adjustments.
Station execution tick
src/core/execution/TrainStationExecution.ts
Calls TrainStation.tick() each station-exec tick (before spawn) so stations broadcast/age routing and update edge/traffic state.
Game API & stats
src/core/game/Game.ts, src/core/game/GameImpl.ts
Adds recordTrainArrival(steps) and recordTrainRemovedDueToHopLimit(steps) to Game; GameImpl tracks arrivals, completed/active steps, hop-limit removals, exposes getActiveTrainCount(), getAverageCompletedTrainSteps(), getAverageActiveTrainSteps(), printTrainStats(), and prints periodic summaries.
Station routing & types
src/core/game/TrainStation.ts
Introduces BATMAN-like routing and types (RoutingEntry, RoutingEntryFull, EdgeMetrics, StationTraffic), routing table with sequence numbers, originator broadcasts (broadcastOriginatorMessage, receiveOriginatorMessage, tick()), edge/traffic metrics, greedy neighbor selection (chooseNextStation, chooseGreedyNeighbor), journey-driven reverse-route updates (processJourneyInformation, updateReverseRouteFromJourney), and removal handlers.
Rail network lifecycle
src/core/game/RailNetworkImpl.ts
Calls station.onStationRemoved() after disconnecting a station to allow station-level cleanup before deregistration.

Sequence Diagram(s)

sequenceDiagram
    participant GameLoop as Game.executeNextTick
    participant GameImpl as GameImpl
    participant StationExec as TrainStationExecution
    participant Station as TrainStation
    participant TrainExec as TrainExecution

    GameLoop->>+GameImpl: executeNextTick()
    GameImpl->>+StationExec: tick all stations
    StationExec->>+Station: tick()
    Note right of Station `#E8F0FF`: Broadcast/age routes\nupdate edge metrics & traffic
    Station-->>-StationExec: done
    StationExec->>GameImpl: spawn trains (if any)

    GameImpl->>+TrainExec: tick trains
    alt train moving
        TrainExec->>Station: shareJourneyInfo() (optional)
        TrainExec->>Station: chooseNextStation(destination,recent)
        Station-->>TrainExec: nextHop / null
        TrainExec->>TrainExec: processArrival/update journey
        TrainExec->>GameImpl: recordTrainArrival(steps)
    else hop limit exceeded
        TrainExec->>GameImpl: recordTrainRemovedDueToHopLimit(steps)
    end

    GameImpl->>GameImpl: accumulate per-tick stats
    alt every 60 ticks
        GameImpl->>GameImpl: printTrainStats()
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Review focus:
    • src/core/game/TrainStation.ts — routing protocol correctness, sequence/aging, and edge/traffic scoring.
    • src/core/execution/TrainExecution.ts — journey state transitions, hop-limit logic, and shareJourneyInfo() integration.
    • src/core/game/GameImpl.ts — stat aggregation, timing, and public API behavior.
    • src/core/game/RailNetworkImpl.ts — removal ordering and side-effects.

Possibly related PRs

Suggested labels

Feature - Simulation

Suggested reviewers

  • evanpelle
  • scottanderson

Poem

🚂 Trains learn paths by whisper and hop,
Stations hum routes that never stop,
Counters tick steps, memories share,
Greedy choices guide them there,
Rails and stats in tidy crop.

Pre-merge checks

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title directly describes the main architectural change: replacing global pathfinding with local routing, which aligns with all major modifications across TrainExecution, TrainStation, and Game components.
Description check ✅ Passed The description relates to the changeset by explaining the local greedy routing system, benefits, and current state; however, it's incomplete with placeholder text, unchecked checklist items, and 'code needs cleanup' warning suggests work-in-progress status.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot]

This comment was marked as off-topic.

coderabbitai[bot]

This comment was marked as off-topic.

…counting

The new station-aware routing introduced a bug where train arrivals were being
double-counted and termination conditions were incorrectly classified as arrivals.

Problems fixed:
- targetReached() was called twice for successful arrivals: once in getNextTile()
  when destination was reached, and again in tick() when no tile was returned
- Trains removed due to hop limit were counted as successful arrivals
- Trains stuck with no routing options were counted as successful arrivals

Solution implemented:
- Introduced MoveResult union type with explicit cases: "move", "arrived",
  "hopLimit", "stuck" to clearly distinguish termination conditions
- Renamed getNextTile() to getNextStep() and changed return type to MoveResult
- Removed targetReached() call from navigation logic to prevent double counting
- Updated tick() method to use switch statement on MoveResult for proper handling
- Ensured recordTrainArrival() only called for actual destination arrivals
- Ensured recordTrainRemovedDueToHopLimit() only called for hop limit terminations
- Stuck trains are deleted without recording any arrival statistics

This ensures accurate train statistics tracking with the new routing system.
@scamiv scamiv force-pushed the feature/Local-Train-Routing branch from da8ae46 to 1d352e1 Compare November 18, 2025 19:41
coderabbitai[bot]

This comment was marked as off-topic.

@ryanbarlow97
Copy link
Contributor

Personally, I'd say close this and work off the new branch you made, once it's ready, make a new PR using that branch

Copy link
Collaborator

@evanpelle evanpelle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of local pathfinding. this approach seems a bit overly complex to me. is there a way to simplify this down to something like 100 lines?

@scamiv scamiv marked this pull request as draft November 20, 2025 11:30
@scamiv
Copy link
Contributor Author

scamiv commented Nov 20, 2025

Maybe discuss the changes here https://discord.com/channels/1359946986937258015/1441027562967928862 ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants