A Tux-themed Mahjong solitaire game for Linux, windows & MacOS built with Rust and SDL2.
xMahjong is a classic tile-matching solitaire game featuring Tux penguin-themed graphics. Clear all 144 tiles from the board by matching pairs of free tiles. The game uses the traditional Turtle layout with 5 stacked layers, and every generated board is guaranteed to be solvable.
Example
- Classic Turtle layout with 144 tiles across 5 layers
- Guaranteed solvable boards via reverse-deal generation
- Hint system, undo (up to 10 moves), and progressive shuffle system
- Timer and scoring system with local leaderboard (top 10)
- Keyboard shortcuts for all actions
- Audio feedback with mute support
- Resizable window (min 1920×1080, adapts to screen resolution)
- Native Linux packages (.deb, .rpm, AppImage)
- Daily new free Shuffle +1
You need SDL2 development libraries installed:
Ubuntu / Debian:
sudo apt install libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev pkg-configFedora:
sudo dnf install SDL2-devel SDL2_image-devel SDL2_mixer-devel SDL2_ttf-devel pkg-configArch Linux:
sudo pacman -S sdl2 sdl2_image sdl2_mixer sdl2_ttf pkg-configInstall Rust via rustup:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh# Debug build
cargo build
# Release build (optimized)
cargo build --releasemacOS (requires Homebrew SDL2 libraries):
brew install sdl2 sdl2_image sdl2_mixer sdl2_ttf pkg-config
LIBRARY_PATH="/opt/homebrew/lib" cargo build --releaseThe binary is output to target/debug/xmahjong or target/release/xmahjong.
# Run directly
cargo run
# Or run the release binary
cargo run --release# Run all tests (unit + property-based)
cargo test
# Run only unit tests
cargo test --lib
# Run a specific property test file
cargo test --test board_properties
# Run tests with output shown
cargo test -- --nocaptureThe project includes 19 property-based tests using proptest that validate correctness properties like board generation invariants, solvability, matching logic, undo/redo behavior, shuffle guarantees, and layout scaling.
| Shortcut | Action |
|---|---|
| Left click | Select tile |
| Ctrl+S | Save game |
| Ctrl+Q | Save + Quit |
| Ctrl+N | New Game |
| Ctrl+R | Resume |
| Ctrl+P | Pause |
| Ctrl+M | Toggle Mute |
| Shift+S | Shuffle |
| Shift+U | Undo |
| Shift+H | Hint |
| Escape | Pause / Resume (toggle) |
Score starts at 0 and increases with each pair matched:
- Base: +10 points per pair removed
- Streak bonus: +2 per pair (rewards continuous play)
- Penalties: −5 per hint used, −10 per shuffle used
- Time bonus (at game end): max(0, 500 − elapsed_seconds)
Top 10 scores are saved to a local leaderboard.
Shuffles rearrange the remaining tiles on the board when no moves are available (or strategically when desired). The shuffle economy is progressive:
- Starting shuffles: Each new game begins with 1 shuffle
- Level completion bonus: +1 shuffle awarded for each level completed (carried across levels)
- Daily bonus: +1 shuffle granted once per day when the game is launched
- Total potential: By completing all 50 levels, a player accumulates up to 51 shuffles (1 starting + 50 level rewards), plus any daily bonuses earned
- Wait for Shuffle: If you run out of shuffles and moves mid-run, you can choose "Wait for Shuffle" instead of starting over. This saves your game and exits. The next day when you launch the game, the daily bonus gives you a new shuffle so you can continue where you left off.
Shuffle state persists across sessions via shuffles.json in the data storage directory.
A packaging script is included to create distribution packages:
# Build all three formats
./package.sh all
# Or build individually
./package.sh deb
./package.sh rpm
./package.sh appimageOutput goes to target/package/.
| Format | Tool needed | Install with |
|---|---|---|
| .deb | dpkg-deb | Pre-installed on Debian/Ubuntu |
| .rpm | rpmbuild | sudo dnf install rpm-build |
| AppImage | wget | Pre-installed on most distros (downloads appimagetool automatically) |
.deb (Ubuntu/Debian):
sudo apt install ./target/package/xmahjong_0.1.0_amd64.debThis automatically installs SDL2 runtime dependencies via apt.
.rpm (Fedora/RHEL):
sudo dnf install ./target/package/xmahjong-0.1.0-1.x86_64.rpmThis automatically installs SDL2 runtime dependencies via dnf.
AppImage (any distro):
chmod +x target/package/xmahjong-0.1.0-x86_64.AppImage
./target/package/xmahjong-0.1.0-x86_64.AppImageAppImages bundle SDL2 libraries inside, so no system dependencies are needed.
macOS (.app bundle):
cp -R xMahjong-0.1.0-aarch64.app /Applications/
open /Applications/xMahjong-0.1.0-aarch64.appCopy the .app to your Applications folder and launch it. The app bundle includes all SDL2 libraries — no Homebrew or other dependencies required.
macOS (.dmg disk image):
open xMahjong-0.1.0-arm64.dmgDouble-click the .dmg to mount it, then drag xMahjong.app into the Applications folder. No additional dependencies are needed.
All game data is stored as JSON files in a platform-specific directory:
| Platform | Path |
|---|---|
| Linux | ~/.local/share/xmahjong/ |
| macOS | ~/Library/Application Support/xmahjong/ |
| Windows | %APPDATA%\xmahjong\ (e.g. C:\Users\<user>\AppData\Roaming\xmahjong\) |
| File | Description |
|---|---|
leaderboard.json |
Top 10 scores with player name, score, time, hints used, shuffles used, undos used, and date |
settings.json |
Persistent settings (muted state) |
savegame.json |
In-progress game state for resuming later (deleted after loading) |
shuffles.json |
Shuffle state: tracks last daily bonus date for the +1 daily shuffle reward |
- Pause menu (render_menu) — ✅ Has keyboard nav
- Victory (render_victory) — ✅ Has keyboard nav
- Leaderboard (render_leaderboard) — ✅ Has Enter/Escape support
- Shortcuts (render_shortcuts) — ✅ Has Enter/Escape support
- No Moves (render_no_moves) — ✅ Has Shuffle + New Game buttons
- Game Over (render_game_over) — ✅ Has Save Score + New Game buttons
- Quit Confirmation (render_quit_confirmation) — ✅ Has Yes/No buttons
- Name Entry (render_name_entry) — ✅ Text input
This project is licensed under the GNU General Public License v3.0.
