A C++17 railway simulation using fixed-size arrays and global state declared in
core/simulation_state.h. Core simulation logic has zero SFML dependency and
compiles/runs standalone from console/main_console.cpp.
Windows (MSYS2 MinGW64 shell):
pacman -Syu
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-make mingw-w64-x86_64-sfmlLinux:
bash libraries.shmingw32-make clean # (or `make clean` on Linux)
mingw32-make # (or `make`)
./switchback_rails.exe data/levels/easy_level.lvl # graphical (SFML)Console-only build (no graphics, useful for quick logic testing):
mingw32-make console
./switchback_console.exe data/levels/easy_level.lvlThe Makefile links against -lsfml-graphics -lsfml-window -lsfml-system, and
uses -std=c++17. This project's SFML code targets SFML 3's event API
(sf::Event::is<...>() / getIf<...>()), which is what MSYS2's
mingw-w64-x86_64-sfml package currently installs on Windows.
Linux note:
apt-get install libsfml-devon most current distros installs SFML 2.6, which uses the olderpollEvent(sf::Event&)API and will not compilesfml/app.cppas-is. Linux users should either build SFML 3 from source, or use the console-only build below, which has no SFML dependency at all.
| Key/Mouse | Action |
|---|---|
| SPACE | Pause/Resume |
| . (period) | Step one tick |
| Arrow keys | Pan camera |
| R | Reset camera |
| Left click | Toggle safety tile = |
| Right click | Toggle switch state |
| E (hover a switch) | Emergency halt |
| Mouse wheel | Zoom |
| Middle click + drag | Pan |
| ESC | Exit and save metrics |
The window opens at your desktop's full resolution automatically. On Windows,
SetProcessDPIAware() is called on startup so the OS doesn't auto-scale the
window on displays with scaling settings above 100% (this requires linking
-luser32, already in the Makefile).
- Level parsing for
MAP,SWITCHES,TRAINS,SEED,WEATHER. - Real
D-tile destinations assigned to trains (not a placeholder formula). - Per-direction and global switch counters, initial state parsing, deferred post-movement flips.
- Safety-tile delays, blocked-spawn retries, rain delays, fog-delayed signal display.
- Same-target, head-on swap, and crossing (
+) collision resolution using Manhattan-distance priority, including the "equal distance = all crash" tie rule. - Signal lights (GREEN/YELLOW/RED) computed before collision resolution each tick, so RED/YELLOW are visible ahead of a crash rather than always showing GREEN.
- Sprite rendering using cropped, background-removed tile art in
Sprites/tiles/(tracks, curves, crossings, switches, spawn/destination markers, safety tiles, signal lights, and directional train sprites), loaded viasf::Texture/sf::Spriteand scaled to a consistent tile size. - Deterministic: identical
seed+ level file → byte-identicaltrace.csvacross repeated runs (verified for all four bundled levels).
data/levels/easy_level.lvl, medium_level.lvl, and hard_level.lvl were
corrected from their original versions, which had two bugs:
- Train spawn coordinates in
TRAINS:didn't match any realStile on the map (off by one row, or entirely out of bounds), causing most trains to derail immediately instead of demonstrating real traffic. medium_level.lvlnamed a switchD, colliding with the reserved destination-tile symbolD, which caused every real destination on that map to be misidentified as that switch.
Both are fixed; io.cpp also now falls back to snapping a train to the
nearest real spawn tile if a level file's coordinates are still invalid, as
a defensive measure against future bad level data.
out/trace.csv-Tick,TrainID,X,Y,Direction,Stateout/switches.csv- switch state recordsout/signals.csv- GREEN/YELLOW/RED signal records per switch per tickout/metrics.txt- delivered/crashed/signal-violation totals
core/ simulation logic, no SFML includes
sfml/ SFML UI, calls into core headers
console/ console-only main, for testing core logic without SFML
data/levels/ .lvl level files
out/ one committed sample run (trace.csv, switches.csv, signals.csv, metrics.txt)
Sprites/tiles/ PNG tile art
docs/ Edit.png, Simulate.png screenshots
Makefile
libraries.sh
README.md