Skip to content

sugarcraft/candy-mines

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

66 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

candy-mines

CandyMines

CI codecov Packagist Version License PHP

demo

Minesweeper on the SugarCraft stack — port of maxpaulus43/go-sweep. Customisable board, recursive flood-fill, win / lose detection, vim-style movement.

Difficulty presets are available via Game::withDifficulty(Difficulty::$LEVEL)EASY (9×9, 10 mines), MEDIUM (16×16, 40 mines), EXPERT (30×16, 99 mines).

Run it

composer install
./bin/candy-mines [width] [height] [mines]   # defaults: 10 10 12

Keys

Key Action
↑/↓/←/→ or hjkl Move cursor
Space / Enter Reveal cell
f Toggle flag
c / middle-click Chord — reveal safe neighbors
r Restart with new mines
q / Esc Quit

Architecture

Five pure-state classes plus the runtime Model, renderer, UI helper, and persistence:

File Role
Cell Value object — mine / revealed / flagged / adjacent count
Board The grid + every transition (reveal, flag, flood-fill, chord). Win detection is O(1) via revealedCount counter. Serialises to versioned JSON for mid-game save/load.
Game (Model) Cursor + key routing + restart + win/lose gate + sub-second timer (microtime(true))
Stats Immutable difficulty stats — games, wins, best time per preset
DifficultyStats Atomic JSON persistence wrapper (tmp+rename, Homestead pattern)
Ui/CustomDifficulty Validated custom board dimensions — rows (2–50), cols (2–50), mines (1 to rows×cols−9). Throws i18n-aware InvalidArgumentException on constraint violation.
Renderer Pure view function. CandySprinkles Style + Border::rounded()

The first reveal is always safe — mines are placed only after click 1, with the clicked cell's 3×3 neighbourhood excluded so the player gets a non-trivial flood-fill on every game.

Chord click (c / middle-click): when a revealed number has exactly the right number of flagged neighbours, chord-clicking it safely reveals all remaining neighbours. This mirrors the standard left+right simultaneous press in classic minesweeper.

O(1) win detection: Board::isWon() compares revealedCount (the number of non-mine cells revealed) against width × height − mineCount. Win detection is constant-time regardless of board size — no full-grid scan on every move.

Save / restore mid-game: Board::serialize() produces a versioned JSON payload ({v:1, w, h, m, p, e, r, c}) covering every cell and board state. Board::unserialize() reconstructs an identical Board instance so sessions can be suspended and resumed.

Demos

Gameplay

play

Flagging

flagging

Test

composer install
vendor/bin/phpunit

About

Minesweeper TUI — port of maxpaulus43/go-sweep on the SugarCraft stack.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages