// SPDX-FileCopyrightText: 2025 thorium1256 // // SPDX-License-Identifier: GPL-3.0-or-later #include "Board.h" #include Board::Board(int w, int h, short mines) : size(w, h), mines(mines), isFirstClick(true), b_gameOver(false) { cells.resize(h); for (int y = 0; y < h; y++) { cells[y].resize(w); for (int x = 0; x < w; x++) { cells[y][x] = Cell(x, y); } } std::vector positions; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { positions.push_back(Vector2(x, y)); } } std::random_device rd; std::mt19937 g(rd()); std::shuffle(positions.begin(), positions.end(), g); for (int i = 0; i < mines; i++) { Vector2 pos = positions[i]; cells[pos.y][pos.x].setContent(Cell::Content::Mine); } for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { Cell &cell = cells[y][x]; if (cell.getContent() != Cell::Content::Mine) { int count = 0; std::vector neighbors = getNeighborsOf(x, y); for (const Cell &neighbor : neighbors) { if (neighbor.getContent() == Cell::Content::Mine) { count++; } } cell.setContent(static_cast(count)); } } } } std::vector Board::getNeighborsOf(int x, int y) { std::vector neighbors; for (int dx = -1; dx <= 1; dx++) { for (int dy = -1; dy <= 1; dy++) { if (dx == 0 && dy == 0) continue; int nx = x + dx; int ny = y + dy; if (nx >= 0 && nx < size.x && ny >= 0 && ny < size.y) neighbors.push_back(cells[ny][nx]); } } return neighbors; } bool Board::isGameOver() { return b_gameOver; } Cell Board::revealCellAt(int x, int y) { if (x < 0 || x >= size.x || y < 0 || y >= size.y) { throw std::out_of_range("Cell coordinates out of bounds"); } Cell &cell = cells[y][x]; if (cell.getState() == Cell::State::Revealed || cell.getState() == Cell::State::Flagged) { return cell; } if (isFirstClick) { if (cell.getContent() == Cell::Content::Mine) { regenerateBoard(); return revealCellAt(x, y); } isFirstClick = false; } if (cell.getContent() == Cell::Content::Mine) { cell.reveal(); gameOver(); return cell; } if (cell.getContent() == Cell::Content::Empty) { revealEmptyCells(x, y); } else { cell.reveal(); } return cell; } void Board::revealEmptyCells(int x, int y) { std::queue q; q.push(Vector2(x, y)); while (!q.empty()) { Vector2 pos = q.front(); q.pop(); Cell ¤t = cells[pos.y][pos.x]; if (current.getState() != Cell::State::Hidden) { continue; } current.reveal(); if (current.getContent() == Cell::Content::Empty) { // for (int dx = -1; dx <= 1; dx++) // { // for (int dy = -1; dy <= 1; dy++) // { // if (dx == 0 && dy == 0) // continue; // int nx = pos.x + dx; // int ny = pos.y + dy; // if (nx >= 0 && nx < size.x && ny >= 0 && ny < size.y) // { // Cell &neighbor = cells[ny][nx]; // if (neighbor.getState() == Cell::State::Hidden) // { // q.push(Vector2(nx, ny)); // } // } // } // } std::vector neighbors = getNeighborsOf(pos.x, pos.y); for (const Cell &neighbor : neighbors) { if (neighbor.getState() == Cell::State::Hidden) { q.push(Vector2(neighbor.position.x, neighbor.position.y)); } } } } } void Board::gameOver() { b_gameOver = true; for (int y = 0; y < size.y; y++) { for (int x = 0; x < size.x; x++) { Cell &cell = cells[y][x]; if (cell.getContent() == Cell::Content::Mine && cell.getState() != Cell::State::Flagged) { cell.reveal(); } if (cell.getContent() != Cell::Content::Mine && cell.getState() == Cell::State::Flagged) { cell.state = Cell::State::NotAMine; } } } } void Board::flagCellAt(int x, int y) { if (x < 0 || x >= size.x || y < 0 || y >= size.y) { return; } cells[y][x].toggleFlag(); } Vector2 Board::getBoardSize() const { return size; } void Board::regenerateBoard() { cells.clear(); isFirstClick = true; cells.resize(size.y); for (int y = 0; y < size.y; y++) { cells[y].resize(size.x); for (int x = 0; x < size.x; x++) { cells[y][x] = Cell(x, y); } } std::vector positions; for (int y = 0; y < size.y; y++) { for (int x = 0; x < size.x; x++) { positions.push_back(Vector2(x, y)); } } std::random_device rd; std::mt19937 g(rd()); std::shuffle(positions.begin(), positions.end(), g); for (int i = 0; i < mines; i++) { Vector2 pos = positions[i]; cells[pos.y][pos.x].setContent(Cell::Content::Mine); } for (int y = 0; y < size.y; y++) { for (int x = 0; x < size.x; x++) { Cell &cell = cells[y][x]; if (cell.getContent() != Cell::Content::Mine) { int count = 0; std::vector neighbors = getNeighborsOf(x, y); for (const Cell &neighbor : neighbors) { if (neighbor.getContent() == Cell::Content::Mine) { count++; } } cell.setContent(static_cast(count)); } } } } int Board::getMineCount() const { return mines; } Cell::State Board::getCellStateAt(int x, int y) { return cells[y][x].getState(); } bool Board::isGameWon() const { return checkWinCondition(); } bool Board::checkWinCondition() const { for (int y = 0; y < size.y; y++) { for (int x = 0; x < size.x; x++) { const Cell &cell = cells[y][x]; if (cell.getContent() != Cell::Content::Mine && cell.getState() != Cell::State::Revealed) { return false; } } } return true; }