Files
roro9stack/lib/games/src/mines.h
T
twislaandClaude Opus 5.5 fcc5533c83 Games: Minesweeper and 2048 as state machines
Minesweeper on 20 x 9 with 28 mines, laid at the first dig and never
under or next to it, with flags and the open-around-a-number dig; 2048
on 4 x 4, a tile merging once a move. Seeded, host-tested.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0162FokPdvY2KsS4NBfwyWPk
2026-10-14 18:46:49 +02:00

57 lines
2.3 KiB
C++

#pragma once
#include <array>
#include <cstddef>
#include <cstdint>
#include "game_rng.h"
namespace roro::games {
// Minesweeper (issue #101's follow-up): a field of 20 x 9 with 28 mines, cells big enough to read
// on this screen. The mines are laid at
// the first dig, never under it or next to it, so the first dig always opens something. Digging
// an open number whose flags are all placed opens what is left around it. The clock runs from the
// first dig to the end.
class Mines {
public:
static constexpr int kCols = 20, kRows = 9, kMines = 28; // the classic "intermediate" share: one cell in six or seven
enum Event : uint8_t { Opened = 1, Flagged = 2, Boom = 4, Won = 8 };
enum class Phase : uint8_t { Fresh, Running, Lost, Won };
explicit Mines(uint32_t seed) : rng_(seed) { start(); }
void start();
uint8_t dig(int col, int row);
uint8_t flag(int col, int row); // put on a closed cell, or taken off
void tick(uint32_t ms); // the clock, while the game runs
Phase phase() const { return phase_; }
bool open(int col, int row) const { return cells_[at(col, row)] & kOpen; }
bool flagged(int col, int row) const { return cells_[at(col, row)] & kFlag; }
bool mine(int col, int row) const { return cells_[at(col, row)] & kMine; }
int around(int col, int row) const { return cells_[at(col, row)] & kCount; } // mines next to it
int minesLeft() const { return kMines - flags_; } // by the flags placed, right or wrong
uint32_t seconds() const { return elapsedMs_ / 1000; }
// For the tests: the mines put where one wants them, before any dig.
void lay(const uint16_t* where, int count);
private:
static constexpr uint8_t kCount = 0x0F, kMine = 0x10, kOpen = 0x20, kFlag = 0x40;
static size_t at(int col, int row) { return static_cast<size_t>(row * kCols + col); }
static bool inside(int col, int row) { return col >= 0 && col < kCols && row >= 0 && row < kRows; }
void layAwayFrom(int col, int row);
void count();
uint8_t reveal(int col, int row);
uint8_t settle(uint8_t events);
Rng rng_;
std::array<uint8_t, kCols * kRows> cells_{};
Phase phase_ = Phase::Fresh;
bool laid_ = false;
int flags_ = 0, opened_ = 0;
uint32_t elapsedMs_ = 0;
};
} // namespace roro::games