Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "minesweeper.h"
- #include <queue>
- #include <ctime>
- #include <random>
- #include <algorithm>
- struct MiniCell {
- size_t x = 0;
- size_t y = 0;
- };
- bool Minesweeper::OutOfRange(size_t x, int b, size_t width) const {
- int64_t a = static_cast<int64_t>(x);
- int64_t c = static_cast<int64_t>(width);
- return a + b < 0 || a + b == c;
- }
- void Minesweeper::Initialize(size_t width, size_t height) {
- width_ = width;
- height_ = height;
- game_status_ = Minesweeper::GameStatus::NOT_STARTED;
- field_.clear();
- field_.resize(width, std::vector<Cell>(height));
- for (size_t x = 0; x < width; ++x) {
- for (size_t y = 0; y < height; ++y) {
- Cell& cell = field_[x][y];
- cell.x = x;
- cell.y = y;
- cell.status = Minesweeper::Cell::Status::NOT_OPEN;
- for (int dx : delta_) {
- if (OutOfRange(x, dx, width)) {
- continue;
- }
- for (int dy : delta_) {
- if ((!dx && !dy) || OutOfRange(y, dy, height)) {
- continue;
- }
- size_t nx = x + dx;
- size_t ny = y + dy;
- cell.neighbors.push_back(&field_[nx][ny]);
- }
- }
- }
- }
- }
- void Minesweeper::PrecalcCountOfNeighborsMines() {
- for (size_t x = 0; x < width_; ++x) {
- for (size_t y = 0; y < height_; ++y) {
- Cell& cur_cell = field_[x][y];
- for (Cell* cell : cur_cell.neighbors) {
- cur_cell.neighbors_mines_count_ += cell->have_mine;
- }
- }
- }
- }
- void Minesweeper::NewGame(size_t width, size_t height, size_t mines_count) {
- mines_count_ = mines_count;
- Initialize(width, height);
- std::vector<MiniCell> vcell(width * height);
- for (size_t x = 0; x < width; ++x) {
- for (size_t y = 0; y < height; ++y) {
- vcell[x * height + y] = {.x = x, .y = y};
- }
- }
- std::shuffle(vcell.begin(), vcell.end(), std::default_random_engine{});
- for (size_t i = 0; i < mines_count; ++i) {
- size_t x = vcell[i].x;
- size_t y = vcell[i].y;
- field_[x][y].have_mine = true;
- }
- PrecalcCountOfNeighborsMines();
- }
- Minesweeper::Minesweeper(size_t width, size_t height, size_t mines_count) {
- NewGame(width, height, mines_count);
- }
- void Minesweeper::NewGame(size_t width, size_t height, const std::vector<Cell>& cells_with_mines) {
- mines_count_ = cells_with_mines.size();
- Initialize(width, height);
- for (const Cell& cell : cells_with_mines) {
- field_[cell.x][cell.y].have_mine = true;
- }
- PrecalcCountOfNeighborsMines();
- }
- Minesweeper::Minesweeper(size_t width, size_t height, const std::vector<Cell>& cells_with_mines) {
- NewGame(width, height, cells_with_mines);
- }
- bool Minesweeper::Cell::IsOpen() const {
- return this->status == Minesweeper::Cell::Status::OPEN;
- }
- bool Minesweeper::Cell::IsNotOpen() const {
- return this->status == Minesweeper::Cell::Status::NOT_OPEN;
- }
- bool Minesweeper::Cell::IsMark() const {
- return this->status == Minesweeper::Cell::Status::MARK;
- }
- void Minesweeper::StartGame() {
- game_status_ = Minesweeper::GameStatus::IN_PROGRESS;
- start_ = time(nullptr);
- }
- void Minesweeper::Victory() {
- game_status_ = Minesweeper::GameStatus::VICTORY;
- finish_ = std::time(nullptr);
- }
- void Minesweeper::GameOver() {
- game_status_ = Minesweeper::GameStatus::DEFEAT;
- finish_ = std::time(nullptr);
- for (size_t x = 0; x < width_; ++x) {
- for (size_t y = 0; y < height_; ++y) {
- field_[x][y].status = Minesweeper::Cell::Status::OPEN;
- }
- }
- }
- void Minesweeper::Open(Cell& cell) {
- std::queue<Cell*> q;
- q.push(&cell);
- while (!q.empty()) {
- Cell* c = q.front();
- q.pop();
- if (c->have_mine) {
- GameOver();
- return;
- } else if (c->IsMark() || c->IsOpen()) {
- continue;
- } else if (!c->neighbors_mines_count_) {
- for (Cell* nc : c->neighbors) {
- q.push(nc);
- }
- }
- c->status = Minesweeper::Cell::Status::OPEN;
- ++open_cells_count_;
- }
- if (open_cells_count_ + mines_count_ == height_ * width_) {
- Victory();
- }
- }
- void Minesweeper::OpenCell(const Cell& cell) {
- Cell& cur_cell = field_[cell.x][cell.y];
- switch (game_status_) {
- case Minesweeper::GameStatus::VICTORY:
- case Minesweeper::GameStatus::DEFEAT:
- return;
- case Minesweeper::GameStatus::NOT_STARTED:
- StartGame();
- Open(cur_cell);
- return;
- case Minesweeper::GameStatus::IN_PROGRESS:
- Open(cur_cell);
- }
- }
- void Minesweeper::Mark(Cell& cell) const {
- if (cell.IsMark()) {
- cell.status = Minesweeper::Cell::Status::NOT_OPEN;
- } else if (cell.IsNotOpen()) {
- cell.status = Minesweeper::Cell::Status::MARK;
- }
- }
- void Minesweeper::MarkCell(const Cell& cell) {
- Cell& cur_cell = field_[cell.x][cell.y];
- switch (game_status_) {
- case Minesweeper::GameStatus::VICTORY:
- case Minesweeper::GameStatus::DEFEAT:
- return;
- case Minesweeper::GameStatus::NOT_STARTED:
- StartGame();
- Mark(cur_cell);
- return;
- case Minesweeper::GameStatus::IN_PROGRESS:
- Mark(cur_cell);
- }
- }
- Minesweeper::GameStatus Minesweeper::GetGameStatus() const {
- return game_status_;
- }
- time_t Minesweeper::GetGameTime() const {
- switch (game_status_) {
- case Minesweeper::GameStatus::VICTORY:
- case Minesweeper::GameStatus::DEFEAT:
- return finish_ - start_;
- case Minesweeper::GameStatus::NOT_STARTED:
- return 0;
- case Minesweeper::GameStatus::IN_PROGRESS:
- return std::time(nullptr) - start_;
- }
- return 0;
- }
- Minesweeper::RenderedField Minesweeper::RenderField() const {
- Minesweeper::RenderedField field(height_);
- for (size_t x = 0; x < height_; ++x) {
- field[x].resize(width_);
- }
- for (size_t x = 0; x < height_; ++x) {
- for (size_t y = 0; y < width_; ++y) {
- Cell cell = field_[y][x];
- if (cell.IsMark()) {
- field[x][y] = '?';
- } else if (cell.IsNotOpen()) {
- field[x][y] = '-';
- } else {
- char& f = field[x][y];
- if (field_[y][x].have_mine) {
- f = '*';
- continue;
- }
- size_t cnt = field_[y][x].neighbors_mines_count_;
- if (cnt) {
- f = static_cast<char>(cnt + '0');
- } else {
- f = '.';
- }
- }
- }
- }
- return field;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement