██████╗ ██████╗ ██╗ ██╗██╗ ███████╗████████╗████████╗███████╗
██╔══██╗██╔═══██╗██║ ██║██║ ██╔════╝╚══██╔══╝╚══██╔══╝██╔════╝
██████╔╝██║ ██║██║ ██║██║ █████╗ ██║ ██║ █████╗
██╔══██╗██║ ██║██║ ██║██║ ██╔══╝ ██║ ██║ ██╔══╝
██║ ██║╚██████╔╝╚██████╔╝███████╗███████╗ ██║ ██║ ███████╗
╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚══════╝
Six chambers. Six chances. Don't be a coward — this game is winner-takes-all. Life or death. If you think you're brave enough, come play.
If you like it, star the repo. If you want to build on it, fork it — the buttons are right there at the top of this page.
ROULETTE is a multiplayer-only terminal game. Two players share one revolver, one live TCP connection, and a single question repeated every turn: will the next pull be the one? Written in Python, with a dedicated Ruby narrative layer giving the game its voice — flavor text, typing effects, ASCII art.
There is no folding, no walking away once a match begins. Every survived pull raises your score. Score is the only thing that can ever buy you a Last Chance — one single emergency survival, earned, not given, and usable exactly once per match.
By launching and entering the game, you accept these rules:
- Entering the game means you accept the rules. No warning screen comes twice — the rules screen is shown once, before you can host or join, and that is your only notice.
- You are not permitted to run this game on virtual machines. This is a played-straight, single-environment experience — it is not built or intended to be run inside a VM.
- Any form of cheating guarantees your loss. There is no benefit to tampering with the client or the odds — the server is authoritative and treats detected tampering as an automatic loss for the offending player.
اگه به خدا اعتقاد داری موقعی که خشاب رو سرته بگو نجاتت بده
"If you believe in God, when the cylinder is against your head — ask Him to save you."
- Multiplayer only, room-based matchmaking. Host a room under a name, share that name, and the server pairs the two of you together for an authoritative, real-time match. No bots. No practice mode.
- The Last Chance system. Each player can earn exactly one emergency survival for the entire match. Score is checked before any death is ever finalized — if you've earned enough, it's spent instead of you.
- Deliberately scarce, streak-based scoring. A small, flat amount of score per survived pull, scaled by your own consecutive-survival streak. Earning a Last Chance takes real, sustained risk — it cannot be farmed.
- A rules screen before every session. Plain-language rules are shown before anyone can host or join, so nobody sits down blind.
- A dedicated narrative engine. All atmosphere — flavor text, typing effects, ASCII banners — is generated by a separate Ruby layer, cleanly decoupled from the Python game logic.
- Persistent statistics. Wins, losses, best score, streaks, and full match history — including room and opponent names — are stored between sessions.
- A death record for every loss. A personal, readable report is generated the moment a match ends in death, alongside a compact audit trail of every death across every match.
- Cryptographically strong randomness. The bullet's chamber is chosen with a cryptographically secure random source, not a seedable or predictable generator. The outcome cannot be predicted or reverse-engineered.
- Fail soft, not hard. A missing narrative layer, a dropped connection, or a corrupted save file all degrade the experience gracefully, with a clear message, instead of crashing the match.
- Python 3.10+
- Ruby (optional, but strongly recommended for the full narrative experience — the game falls back gracefully without it)
git clone https://github.com/your-username/roulette.git
cd roulette
chmod +x install.sh
./install.sh
source .venv/bin/activate
python3 client/main.pyIf Ruby isn't already installed:
# Debian/Ubuntu
sudo apt install ruby
# macOS (Homebrew)
brew install rubygit clone https://github.com/your-username/roulette.git
cd roulette
install.bat
.venv\Scripts\activate
python client\main.pyIf Ruby isn't already installed, get it from rubyinstaller.org.
- One player starts the game and chooses Host a room, picking a room name and, optionally, starting a local server automatically.
- The other player starts the game, chooses Join a room, and enters the same room name plus the host's address and port.
- Once both players are in the room, the match begins — the server is authoritative from that point on.
To run a standalone server for more than one room, or for players connecting from different machines:
python3 server/main.pyroulette/
├── client/
│ └── main.py # Entry point: startup checks, rules, menu, dispatch
├── server/
│ └── main.py # Persistent, multi-room authoritative match server
├── game/
│ ├── revolver.py # Pure revolver mechanics (spin / fire / odds)
│ ├── online.py # Client-side networking + UI for matches
│ ├── score.py # Stats, Last Chance rules, death record artifacts
│ └── narrator.py # Bridge to the Ruby narrative/effects layer
├── scripts/
│ ├── texts.rb # Atmospheric text generation
│ └── effects.rb # Typewriter effects + ASCII art rendering
├── assets/
│ └── texts.txt # Categorized pool of narrative lines
├── data/
│ ├── scores.json # Persistent player statistics
│ └── deaths.log # Append-only death audit trail
├── install.sh / install.bat # Platform installers
└── requirements.txt
Design principles:
- Rooms, not raw pairing. A room name is the only thing two players need to agree on ahead of time — no connection-order choreography.
- Authoritative server. All randomness and rule enforcement —
including the one-time Last Chance check — happen server-side, before
a death is ever finalized. Clients only render state and send intent
(
pull). They don't get a vote. - Separation of voice and logic. Python never hard-codes flavor
text. Every line, every typing effect, every ASCII banner is requested
from the Ruby layer through
game/narrator.py, which shells out toscripts/texts.rbandscripts/effects.rb. - Small, testable core.
game/revolver.pyhas zero UI or I/O dependencies, so the core mechanic can be tested in total isolation from the drama around it. - Fail soft, not hard. Missing Ruby, a dropped connection, a corrupted save file, a permissions problem — all of it degrades gracefully with a clear message instead of a crash and a shrug.
MIT — see LICENSE.
