The classic card game War, implemented cleanly in Python with proper object-oriented design — and a security engineer's twist: an HMAC-signed, tamper-evident results log. A score file is the kind of thing nobody thinks to protect, which is exactly why it's a nice place to show integrity controls.
Author: Syed Muhammad Waleed Bukhari (@WalBuk28) · Cybersecurity Engineer
war/
├── cards.py Suit, Rank, Card (immutable), Deck (seedable shuffle)
├── player.py Player — draw pile + winnings pile, auto-reshuffle
├── game.py WarGame engine (rounds, wars, termination, results)
└── storage.py ResultsLog — HMAC-SHA256 signed, tamper-evident
play.py command-line interface
Clean separation of concerns: cards don't know about players, players don't know the rules, and the rules engine doesn't know about persistence.
python play.py # auto-played game, random deal
python play.py --a Alice --b Bob # named players
python play.py --seed 42 --verbose # reproducible, round-by-round⚔ War: Alice vs Bob (seed=42)
🏆 Alice wins after 1184 rounds (36 wars, knockout).
final: {'Alice': 52, 'Bob': 0}
recorded to results.log (HMAC-signed)
- 52-card deck dealt evenly; Ace high.
- Each round both players reveal the top card — higher rank takes both.
- War on a tie: three cards face-down, then one face-up decides it; ties recurse. Run out of cards mid-war and you lose the pot.
- Ends on a knockout (one player holds all 52) or a configurable
max_roundscap (deterministic War can loop) — then the larger hand wins.
Every recorded game is signed with HMAC-SHA256 over its canonical JSON, so
any edit, reorder or deletion is detectable. The signing key is generated on
first run and stored separately from the log (.war_key, chmod 600) —
mirroring how, in production, the key would live in a secrets manager, never
beside the data it protects.
python play.py --verify-log# untouched:
✅ results log intact — 3/3 records verified
# after someone edits a winner in results.log:
⛔ TAMPERING DETECTED on lines: [2]
2/3 records still valid # (exit code 1)
Verification uses hmac.compare_digest for a constant-time comparison, so it
doesn't leak signature bytes through timing.
python -m unittest discover -s tests -v15 tests: deck integrity (52 unique cards, even split, reproducible shuffle), rank comparison, card conservation (the two hands always total 52), game termination and determinism, plus the full tamper-detection suite (clean log, edited data, forged signature, wrong key).
MIT © Syed Muhammad Waleed Bukhari