Advertisement
nizamoff

minesweeper.cpp

Sep 30th, 2022
1,072
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.93 KB | None | 0 0
  1. #include "minesweeper.h"
  2.  
  3. #include <queue>
  4. #include <ctime>
  5. #include <random>
  6. #include <algorithm>
  7.  
  8. struct MiniCell {
  9.     size_t x = 0;
  10.     size_t y = 0;
  11. };
  12.  
  13. bool Minesweeper::OutOfRange(size_t x, int b, size_t width) const {
  14.     int64_t a = static_cast<int64_t>(x);
  15.     int64_t c = static_cast<int64_t>(width);
  16.     return a + b < 0 || a + b == c;
  17. }
  18.  
  19. void Minesweeper::Initialize(size_t width, size_t height) {
  20.     width_ = width;
  21.     height_ = height;
  22.     game_status_ = Minesweeper::GameStatus::NOT_STARTED;
  23.  
  24.     field_.clear();
  25.     field_.resize(width, std::vector<Cell>(height));
  26.  
  27.     for (size_t x = 0; x < width; ++x) {
  28.         for (size_t y = 0; y < height; ++y) {
  29.             Cell& cell = field_[x][y];
  30.             cell.x = x;
  31.             cell.y = y;
  32.             cell.status = Minesweeper::Cell::Status::NOT_OPEN;
  33.  
  34.             for (int dx : delta_) {
  35.                 if (OutOfRange(x, dx, width)) {
  36.                     continue;
  37.                 }
  38.  
  39.                 for (int dy : delta_) {
  40.                     if ((!dx && !dy) || OutOfRange(y, dy, height)) {
  41.                         continue;
  42.                     }
  43.                     size_t nx = x + dx;
  44.                     size_t ny = y + dy;
  45.                     cell.neighbors.push_back(&field_[nx][ny]);
  46.                 }
  47.             }
  48.         }
  49.     }
  50. }
  51.  
  52. void Minesweeper::PrecalcCountOfNeighborsMines() {
  53.     for (size_t x = 0; x < width_; ++x) {
  54.         for (size_t y = 0; y < height_; ++y) {
  55.             Cell& cur_cell = field_[x][y];
  56.             for (Cell* cell : cur_cell.neighbors) {
  57.                 cur_cell.neighbors_mines_count_ += cell->have_mine;
  58.             }
  59.         }
  60.     }
  61. }
  62.  
  63. void Minesweeper::NewGame(size_t width, size_t height, size_t mines_count) {
  64.     mines_count_ = mines_count;
  65.     Initialize(width, height);
  66.  
  67.     std::vector<MiniCell> vcell(width * height);
  68.     for (size_t x = 0; x < width; ++x) {
  69.         for (size_t y = 0; y < height; ++y) {
  70.             vcell[x * height + y] = {.x = x, .y = y};
  71.         }
  72.     }
  73.     std::shuffle(vcell.begin(), vcell.end(), std::default_random_engine{});
  74.  
  75.     for (size_t i = 0; i < mines_count; ++i) {
  76.         size_t x = vcell[i].x;
  77.         size_t y = vcell[i].y;
  78.         field_[x][y].have_mine = true;
  79.     }
  80.  
  81.     PrecalcCountOfNeighborsMines();
  82. }
  83.  
  84. Minesweeper::Minesweeper(size_t width, size_t height, size_t mines_count) {
  85.     NewGame(width, height, mines_count);
  86. }
  87.  
  88. void Minesweeper::NewGame(size_t width, size_t height, const std::vector<Cell>& cells_with_mines) {
  89.     mines_count_ = cells_with_mines.size();
  90.     Initialize(width, height);
  91.  
  92.     for (const Cell& cell : cells_with_mines) {
  93.         field_[cell.x][cell.y].have_mine = true;
  94.     }
  95.  
  96.     PrecalcCountOfNeighborsMines();
  97. }
  98.  
  99. Minesweeper::Minesweeper(size_t width, size_t height, const std::vector<Cell>& cells_with_mines) {
  100.     NewGame(width, height, cells_with_mines);
  101. }
  102.  
  103. bool Minesweeper::Cell::IsOpen() const {
  104.     return this->status == Minesweeper::Cell::Status::OPEN;
  105. }
  106.  
  107. bool Minesweeper::Cell::IsNotOpen() const {
  108.     return this->status == Minesweeper::Cell::Status::NOT_OPEN;
  109. }
  110.  
  111. bool Minesweeper::Cell::IsMark() const {
  112.     return this->status == Minesweeper::Cell::Status::MARK;
  113. }
  114.  
  115. void Minesweeper::StartGame() {
  116.     game_status_ = Minesweeper::GameStatus::IN_PROGRESS;
  117.     start_ = time(nullptr);
  118. }
  119.  
  120. void Minesweeper::Victory() {
  121.     game_status_ = Minesweeper::GameStatus::VICTORY;
  122.     finish_ = std::time(nullptr);
  123. }
  124.  
  125. void Minesweeper::GameOver() {
  126.     game_status_ = Minesweeper::GameStatus::DEFEAT;
  127.     finish_ = std::time(nullptr);
  128.     for (size_t x = 0; x < width_; ++x) {
  129.         for (size_t y = 0; y < height_; ++y) {
  130.             field_[x][y].status = Minesweeper::Cell::Status::OPEN;
  131.         }
  132.     }
  133. }
  134.  
  135. void Minesweeper::Open(Cell& cell) {
  136.     std::queue<Cell*> q;
  137.     q.push(&cell);
  138.  
  139.     while (!q.empty()) {
  140.         Cell* c = q.front();
  141.         q.pop();
  142.  
  143.         if (c->have_mine) {
  144.             GameOver();
  145.             return;
  146.         } else if (c->IsMark() || c->IsOpen()) {
  147.             continue;
  148.         } else if (!c->neighbors_mines_count_) {
  149.             for (Cell* nc : c->neighbors) {
  150.                 q.push(nc);
  151.             }
  152.         }
  153.         c->status = Minesweeper::Cell::Status::OPEN;
  154.         ++open_cells_count_;
  155.     }
  156.  
  157.     if (open_cells_count_ + mines_count_ == height_ * width_) {
  158.         Victory();
  159.     }
  160. }
  161.  
  162. void Minesweeper::OpenCell(const Cell& cell) {
  163.     Cell& cur_cell = field_[cell.x][cell.y];
  164.     switch (game_status_) {
  165.         case Minesweeper::GameStatus::VICTORY:
  166.         case Minesweeper::GameStatus::DEFEAT:
  167.             return;
  168.         case Minesweeper::GameStatus::NOT_STARTED:
  169.             StartGame();
  170.             Open(cur_cell);
  171.             return;
  172.         case Minesweeper::GameStatus::IN_PROGRESS:
  173.             Open(cur_cell);
  174.     }
  175. }
  176.  
  177. void Minesweeper::Mark(Cell& cell) const {
  178.     if (cell.IsMark()) {
  179.         cell.status = Minesweeper::Cell::Status::NOT_OPEN;
  180.     } else if (cell.IsNotOpen()) {
  181.         cell.status = Minesweeper::Cell::Status::MARK;
  182.     }
  183. }
  184.  
  185. void Minesweeper::MarkCell(const Cell& cell) {
  186.     Cell& cur_cell = field_[cell.x][cell.y];
  187.     switch (game_status_) {
  188.         case Minesweeper::GameStatus::VICTORY:
  189.         case Minesweeper::GameStatus::DEFEAT:
  190.             return;
  191.         case Minesweeper::GameStatus::NOT_STARTED:
  192.             StartGame();
  193.             Mark(cur_cell);
  194.             return;
  195.         case Minesweeper::GameStatus::IN_PROGRESS:
  196.             Mark(cur_cell);
  197.     }
  198. }
  199.  
  200. Minesweeper::GameStatus Minesweeper::GetGameStatus() const {
  201.     return game_status_;
  202. }
  203.  
  204. time_t Minesweeper::GetGameTime() const {
  205.     switch (game_status_) {
  206.         case Minesweeper::GameStatus::VICTORY:
  207.         case Minesweeper::GameStatus::DEFEAT:
  208.             return finish_ - start_;
  209.         case Minesweeper::GameStatus::NOT_STARTED:
  210.             return 0;
  211.         case Minesweeper::GameStatus::IN_PROGRESS:
  212.             return std::time(nullptr) - start_;
  213.     }
  214.     return 0;
  215. }
  216.  
  217. Minesweeper::RenderedField Minesweeper::RenderField() const {
  218.     Minesweeper::RenderedField field(height_);
  219.     for (size_t x = 0; x < height_; ++x) {
  220.         field[x].resize(width_);
  221.     }
  222.  
  223.     for (size_t x = 0; x < height_; ++x) {
  224.         for (size_t y = 0; y < width_; ++y) {
  225.             Cell cell = field_[y][x];
  226.             if (cell.IsMark()) {
  227.                 field[x][y] = '?';
  228.             } else if (cell.IsNotOpen()) {
  229.                 field[x][y] = '-';
  230.             } else {
  231.                 char& f = field[x][y];
  232.                 if (field_[y][x].have_mine) {
  233.                     f = '*';
  234.                     continue;
  235.                 }
  236.  
  237.                 size_t cnt = field_[y][x].neighbors_mines_count_;
  238.                 if (cnt) {
  239.                     f = static_cast<char>(cnt + '0');
  240.                 } else {
  241.                     f = '.';
  242.                 }
  243.             }
  244.         }
  245.     }
  246.  
  247.     return field;
  248. }
  249.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement