merge
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,115 +0,0 @@
|
||||
#include "MineField.hpp"
|
||||
|
||||
MineField::MineField(int cols, int rows, int mines): m_rows(rows),
|
||||
m_cols(cols),
|
||||
m_totalMines(mines),
|
||||
m_remainingFlags(mines),
|
||||
m_exploded(false) {
|
||||
for(int i=0; i< m_cols*m_rows; i++) {
|
||||
std::shared_ptr<Cell> cell = std::make_shared<Cell>();
|
||||
m_cells.push_back(cell);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MineField::initBombs(int x, int y) {
|
||||
|
||||
int remainingMines = m_totalMines;
|
||||
int startPos = x + y * m_rows;
|
||||
|
||||
srand(time(NULL)); //initialize rand()
|
||||
|
||||
while(remainingMines > 0) {
|
||||
int position = rand() % (m_cols * m_rows);
|
||||
if(isBomb(position % m_cols, position / m_rows) || position == startPos) {
|
||||
continue;
|
||||
}
|
||||
m_cells.at(position)->isBomb = true;
|
||||
--remainingMines;
|
||||
}
|
||||
}
|
||||
|
||||
bool MineField::clearCell(int x, int y) {
|
||||
setClearCell(x, y);
|
||||
|
||||
if(isBomb(x, y)) {
|
||||
m_exploded = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bombsNearby(x, y) == 0) {
|
||||
openNeighboorhood(x, y);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MineField::computeBombsNearby(int x, int y) {
|
||||
int total = 0;
|
||||
//compute bombs in neighboorhood
|
||||
for(int i=-1; i<2; i++) {
|
||||
for(int j=-1; j<2; j++) {
|
||||
if(x+i >= 0 && x+i < m_cols && y+j >= 0 && y+j < m_rows) {
|
||||
if(isBomb(x+i, y+j)){
|
||||
++total;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_cells.at(x + y * m_rows)->bombsNearby = total;
|
||||
}
|
||||
|
||||
void MineField::openNeighboorhood(int x, int y) {
|
||||
//compute bombs in neighboorhood
|
||||
for(int i=-1; i<2; i++) {
|
||||
for(int j=-1; j<2; j++) {
|
||||
if(x+i >= 0 && x+i < m_cols && y+j >= 0 && y+j < m_rows) {
|
||||
if((isCleared(x+i, y+j) == false) && (isBomb(x+i, y+j) == false)){
|
||||
setClearCell((x+i), (y+j));
|
||||
if(bombsNearby(x+i, y+j) == 0) {
|
||||
openNeighboorhood(x+i, y+j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MineField::isCleared(int x, int y) {
|
||||
return m_cells.at(x + y * m_rows)->isCleared;
|
||||
}
|
||||
|
||||
bool MineField::isFlagged(int x, int y) {
|
||||
return m_cells.at(x + y * m_rows)->isFlagged;
|
||||
}
|
||||
|
||||
bool MineField::isBomb(int x, int y) {
|
||||
return m_cells.at(x + y * m_rows)->isBomb;
|
||||
}
|
||||
|
||||
int MineField::bombsNearby(int x, int y) {
|
||||
if(m_cells.at(x + y * m_rows)->bombsNearby == -1) {
|
||||
computeBombsNearby(x, y);
|
||||
}
|
||||
return m_cells.at(x + y * m_rows)->bombsNearby;
|
||||
}
|
||||
|
||||
void MineField::setClearCell(int x, int y) {
|
||||
m_cells.at(x + y * m_rows)->isCleared = true;
|
||||
clearCellSignal.emit(x, y);
|
||||
}
|
||||
|
||||
bool MineField::toggleFlag(int x, int y) {
|
||||
if(m_cells.at(x + y * m_rows)->isFlagged == true) {
|
||||
m_cells.at(x + y * m_rows)->isFlagged = false;
|
||||
++m_remainingFlags;
|
||||
remainingFlagsChangedSignal.emit(m_remainingFlags);
|
||||
return true;
|
||||
}
|
||||
else if(m_remainingFlags > 0) {
|
||||
m_cells.at(x + y * m_rows)->isFlagged = true;
|
||||
--m_remainingFlags;
|
||||
remainingFlagsChangedSignal.emit(m_remainingFlags);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
//#include <emmintrin.h>
|
||||
#include <sigc++/signal.h>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
|
||||
struct Cell {
|
||||
bool isFlagged;
|
||||
bool isCleared;
|
||||
bool isBomb;
|
||||
int bombsNearby;
|
||||
Cell(): isFlagged(false), isCleared(false), isBomb(false), bombsNearby(-1) {};
|
||||
};
|
||||
|
||||
class MineField {
|
||||
|
||||
std::vector<std::shared_ptr<Cell>> m_cells;
|
||||
int m_rows;
|
||||
int m_cols;
|
||||
int m_totalMines;
|
||||
int m_remainingFlags;
|
||||
bool m_exploded;
|
||||
void computeBombsNearby(int x, int y);
|
||||
void openNeighboorhood(int x, int y);
|
||||
void setClearCell(int x, int y);
|
||||
|
||||
public:
|
||||
MineField(int cols, int rows, int mines);
|
||||
void initBombs(int x, int y);
|
||||
bool isBomb(int x, int y);
|
||||
bool isFlagged(int x, int y);
|
||||
bool isCleared(int x, int y);
|
||||
bool clearCell(int x, int y);
|
||||
int bombsNearby(int x, int y);
|
||||
bool isGameOver() {return m_exploded; };
|
||||
int getCols() {return m_cols; };
|
||||
int getRows() {return m_rows; };
|
||||
bool toggleFlag(int x, int y);
|
||||
int getRemainingFlags() {return m_remainingFlags; };
|
||||
int getTotalMines() {return m_totalMines; };
|
||||
sigc::signal<void(int, int)> clearCellSignal;
|
||||
sigc::signal<void(int)> remainingFlagsChangedSignal;
|
||||
};
|
||||
339
src/window.cpp~
339
src/window.cpp~
@@ -1,339 +0,0 @@
|
||||
#include "window.hpp"
|
||||
#include "gdkmm/pixbuf.h"
|
||||
#include "gtkmm/cssprovider.h"
|
||||
#include "gtkmm/image.h"
|
||||
#include "sigc++/adaptors/bind.h"
|
||||
#include "sigc++/functors/mem_fun.h"
|
||||
#include <memory>
|
||||
|
||||
|
||||
//}
|
||||
// void MainWindow::ApplyStyles() {
|
||||
// // Load and apply the CSS file
|
||||
// auto css_provider = Gtk::CssProvider::create();
|
||||
// css_provider->load_from_path("style.css");
|
||||
// Gtk::StyleContext::add_provider_for_display(Gdk::Display::get_default(), css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
// }
|
||||
|
||||
void MainWindow::OnCellRightClick(int n_press, double n_x, double n_y, int index) {
|
||||
(void)n_press, (void)n_x, (void)n_y;
|
||||
int x = index % field.getCols();
|
||||
int y = index / field.getRows();
|
||||
|
||||
if(field.isCleared(x, y) == false) {
|
||||
field.toggleFlag(x, y);
|
||||
if(field.isFlagged(x, y)) {
|
||||
auto imgflag = Gtk::make_managed<Gtk::Image>();
|
||||
imgflag->set(m_pixbufFlag);
|
||||
buttons.at(x + y * field.getRows())->set_child(*imgflag);
|
||||
buttons.at(x + y * field.getRows())->set_active(true);
|
||||
}
|
||||
else {
|
||||
buttons.at(x + y * field.getRows())->unset_child();
|
||||
buttons.at(x+ y * field.getRows())->queue_draw();
|
||||
buttons.at(x + y * field.getRows())->set_active(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", field.getRemainingFlags());
|
||||
// flagLabel.set_label(msg);
|
||||
}
|
||||
|
||||
void MainWindow::updateFlagsLabel(int flags) {
|
||||
Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", flags);
|
||||
flagLabel.set_label(msg);
|
||||
}
|
||||
// void MainWindow::OnNewButtonClick() {
|
||||
// newGame = true;
|
||||
// gameOver = false;
|
||||
|
||||
// for (auto &button : buttons) {
|
||||
// button->set_active(false);
|
||||
// button->set_sensitive(true);
|
||||
// button->set_label("");
|
||||
// }
|
||||
|
||||
// field->remainingFlags = MINES;
|
||||
// Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", field->remainingFlags);
|
||||
// flagLabel.set_label(msg);
|
||||
|
||||
// if (clockConn.connected()) clockConn.disconnect();
|
||||
// elapsedTime = 0;
|
||||
// clockConn = Glib::signal_timeout().connect(sigc::mem_fun(*this, &MainWindow::UpdateClockLabel), 100);
|
||||
// }
|
||||
|
||||
|
||||
// void MainWindow::OpenNearCells(int index, std::set<int> &visited) {
|
||||
// int cols = field->Cols();
|
||||
// int x = index % cols;
|
||||
// int y = index / cols;
|
||||
|
||||
// if (visited.count(index)) return;
|
||||
|
||||
// Cell* cell = field->GetCell(x, y);
|
||||
// if (!cell || cell->bombsNearby > 0 || cell->type == CellType::Bomb) return;
|
||||
|
||||
// visited.insert(index);
|
||||
// buttons[index]->set_active(true);
|
||||
|
||||
// for (int i = -1; i <= 1; i++) {
|
||||
// for (int j = -1; j <= 1; j++) {
|
||||
// if (i == 0 && j == 0) continue; // Skip the current cell
|
||||
|
||||
// int nx = x + i;
|
||||
// int ny = y + j;
|
||||
// int newIndex = ny * cols + nx;
|
||||
// Cell* neighborCell = field->GetCell(nx, ny);
|
||||
|
||||
// // Bounds check before recursive call
|
||||
// if (nx >= 0 && nx < cols && ny >= 0 && ny < cols) {
|
||||
// if (visited.count(newIndex) == 0) {
|
||||
// OpenNearCells(newIndex, visited);
|
||||
// }
|
||||
// if (neighborCell && !buttons[newIndex]->get_active() && !neighborCell->isFlag) {
|
||||
// OpenNearCells(newIndex, visited);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
void MainWindow::OnCellClick(int x, int y) {
|
||||
if (newGame) {
|
||||
field.initBombs(x, y);
|
||||
newGame = false;
|
||||
}
|
||||
|
||||
if(field.isFlagged(x, y)) {
|
||||
buttons.at(x + y * field.getRows())->set_active(true);
|
||||
}
|
||||
else if(field.isBomb(x, y)) {
|
||||
openBombs();
|
||||
}
|
||||
else {
|
||||
field.clearCell(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::openBombs() {
|
||||
for(int i=0; i < field.getCols() * field.getRows(); i++) {
|
||||
int x = i % field.getCols();
|
||||
int y = i / field.getRows();
|
||||
|
||||
buttons.at(i)->set_sensitive(false);
|
||||
|
||||
if(field.isBomb(x, y)) {
|
||||
if(field.isFlagged(x, y)) {
|
||||
auto imgFlagBomb = std::make_shared<Gtk::Image>();
|
||||
imgFlagBomb->set(m_pixbufFlagBomb);
|
||||
buttons.at(i)->set_child(*imgFlagBomb);
|
||||
}
|
||||
else {
|
||||
auto imgBomb = std::make_shared<Gtk::Image>();
|
||||
imgBomb->set(m_pixbufBomb);
|
||||
buttons.at(i)->set_child(*imgBomb);
|
||||
}
|
||||
buttons.at(i)->set_active(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateCell(int x, int y) {
|
||||
if(field.isCleared(x, y)) {
|
||||
if (field.bombsNearby(x, y) > 0) {
|
||||
switch(field.bombsNearby(x, y)) {
|
||||
case 1:
|
||||
buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-1");
|
||||
break;
|
||||
case 2:
|
||||
buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-2");
|
||||
break;
|
||||
case 3:
|
||||
buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-3");
|
||||
break;
|
||||
case 4:
|
||||
buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-4");
|
||||
break;
|
||||
case 5:
|
||||
buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-5");
|
||||
break;
|
||||
case 6:
|
||||
buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-6");
|
||||
break;
|
||||
case 7:
|
||||
buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-7");
|
||||
break;
|
||||
case 8:
|
||||
buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-8");
|
||||
break;
|
||||
}
|
||||
buttons.at(x + y * field.getRows())->set_label(Glib::ustring::format(field.bombsNearby(x, y)));
|
||||
}
|
||||
buttons.at(x + y * field.getRows())->set_active(true);
|
||||
buttons.at(x + y * field.getRows())->set_sensitive(false);
|
||||
}
|
||||
}
|
||||
// void MainWindow::ShowGameWonAnimation() {
|
||||
// // Limit the number of confetti images to 10
|
||||
// int confettiCount = 10;
|
||||
// for (int i = 0; i < confettiCount; ++i) {
|
||||
// Glib::signal_timeout().connect_once([this]() {
|
||||
// auto confetti = Gtk::make_managed<Gtk::Image>();
|
||||
// confetti->set_from_resource("/mineSweeper/confetti");
|
||||
// // Randomize position on the grid or overlay.
|
||||
// grid->attach(*confetti, rand() % COLS, rand() % COLS);
|
||||
// grid->queue_draw();
|
||||
// }, i * 100); // Add confetti with a delay of 100ms each
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// bool MainWindow::AllCellsOpened()
|
||||
// {
|
||||
// for(int i=0; i<COLS * COLS; i++) {
|
||||
// if (!buttons[i]->get_active())
|
||||
// return false;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
|
||||
// bool MainWindow::UpdateClockLabel()
|
||||
// {
|
||||
// if(gameOver) return false;
|
||||
|
||||
// elapsedTime++;
|
||||
|
||||
// int deciseconds = elapsedTime % 10;
|
||||
// int seconds = (elapsedTime / 10) % 60;
|
||||
// int minutes = (elapsedTime /600) % 60;
|
||||
|
||||
// Glib::ustring msg = Glib::ustring::compose("Elapsed time: %1:%2.%3", \
|
||||
// Glib::ustring::format(std::setfill(L'0'), std::setw(2), minutes), \
|
||||
// Glib::ustring::format(std::setfill(L'0'), std::setw(2), seconds), \
|
||||
// Glib::ustring::format(std::setfill(L'0'), std::setw(1), deciseconds));
|
||||
// clockLabel.set_label(msg);
|
||||
|
||||
// return true;
|
||||
// }
|
||||
|
||||
MainWindow::MainWindow()
|
||||
{
|
||||
// ApplyStyles(); // Load the CSS file
|
||||
elapsedTime = 0;
|
||||
newGame = true;
|
||||
set_title("MineSweeper");
|
||||
set_default_size(400, 400);
|
||||
set_resizable(false);
|
||||
|
||||
boxV = Gtk::Box(Gtk::Orientation::VERTICAL);
|
||||
boxH = Gtk::Box(Gtk::Orientation::HORIZONTAL);
|
||||
|
||||
boxH.set_hexpand(true);
|
||||
|
||||
boxV.append(boxH);
|
||||
boxH.set_expand(true);
|
||||
|
||||
Gtk::Label labelMines;
|
||||
labelMines.set_margin_top(12);
|
||||
labelMines.set_margin_start(12);
|
||||
labelMines.set_label(Glib::ustring::compose("Total mines: %1", field.getTotalMines()));
|
||||
//labelMines.set_hexpand(true);
|
||||
|
||||
Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", field.getRemainingFlags());
|
||||
flagLabel = Gtk::Label(msg);
|
||||
flagLabel.set_margin_top(12);
|
||||
flagLabel.set_margin_start(12);
|
||||
flagLabel.set_margin_end(12);
|
||||
//flagLabel.set_hexpand(true);
|
||||
|
||||
clockLabel.set_margin_top(12);
|
||||
clockLabel.set_margin_start(12);
|
||||
clockLabel.set_margin_end(12);
|
||||
clockLabel.set_hexpand(true);
|
||||
Glib::ustring clockmsg = Glib::ustring::compose("Elapsed time: 00:00.0");
|
||||
clockLabel.set_label(clockmsg);
|
||||
|
||||
boxH.append(labelMines);
|
||||
boxH.append(clockLabel);
|
||||
boxH.append(flagLabel);
|
||||
|
||||
|
||||
//TODO check if it's okay to mix std::shared_ptr with Gdk::ptr
|
||||
m_pixbufBomb = Gdk::Pixbuf::create_from_resource("/minesweeper/bomb-solid");
|
||||
m_pixbufFlag = Gdk::Pixbuf::create_from_resource("/minesweeper/flag-solid");
|
||||
m_pixbufFlagBomb = Gdk::Pixbuf::create_from_resource("/minesweeper/flag-bomb");
|
||||
|
||||
// bombPix.set_from_resource("/minesweeper/bomb-solid");
|
||||
|
||||
auto css_provider = Gtk::CssProvider::create();
|
||||
css_provider->load_from_data(
|
||||
".label-1 { font-weight: bold; font-size: 1.5em; color: Blue; }\
|
||||
.label-2 { font-weight: bold; font-size: 1.5em; color: Green; }\
|
||||
.label-3 { font-weight: bold; font-size: 1.5em; color: Darkorange; }\
|
||||
.label-4 { font-weight: bold; font-size: 1.5em; color: Purple; }\
|
||||
.label-5 { font-weight: bold; font-size: 1.5em; color: Red; }\
|
||||
.label-6 { font-weight: bold; font-size: 1.5em; color: Salmon; }\
|
||||
.label-7 { font-weight: bold; font-size: 1.5em; color: Turquoise; }\
|
||||
.label-8 { font-weight: bold; font-size: 1.5em; color: Magenta; }");
|
||||
|
||||
auto display = Gdk::Display::get_default();
|
||||
Gtk::StyleContext::add_provider_for_display(display, css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
|
||||
for (int i = 0; i < field.getCols() * field.getRows(); i++) {
|
||||
auto button = std::make_shared<Gtk::ToggleButton>();
|
||||
button->set_size_request(50, 40);
|
||||
button->set_sensitive(true);
|
||||
button->set_active(false);
|
||||
int x = i % field.getCols();
|
||||
int y = i / field.getRows();
|
||||
button->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::OnCellClick), x, y));
|
||||
|
||||
//button->get_style_context()->add_class("fixed-button");
|
||||
|
||||
auto gesture = Gtk::GestureClick::create();
|
||||
gesture->set_button(3);
|
||||
gesture->signal_released().connect(sigc::bind(sigc::mem_fun(*this, \
|
||||
&MainWindow::OnCellRightClick), i));
|
||||
button->add_controller(gesture);
|
||||
|
||||
buttons.push_back(button);
|
||||
|
||||
grid.attach(*button, x, y);
|
||||
}
|
||||
|
||||
field.clearCellSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::updateCell)));
|
||||
field.remainingFlagsChangedSignal.connect(sigc::bind(sigc::mem_fun(*this, \
|
||||
&MainWindow::updateFlagsLabel)));
|
||||
//newGameButton.set_label("New");
|
||||
//newGameButton.add_css_class("suggested-action");
|
||||
//newGameButton.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::OnNewButtonClick));
|
||||
|
||||
//optionButton.set_icon_name("open-menu");
|
||||
|
||||
//create the minefield
|
||||
//field = new MineField(COLS, MINES);
|
||||
|
||||
//bar.pack_start(newGameButton);
|
||||
//bar.pack_end(optionButton);
|
||||
|
||||
//grid.set_row_homogeneous(false);
|
||||
//grid.set_column_homogeneous(false);
|
||||
grid.set_margin(10);
|
||||
//grid.set_vexpand(true);
|
||||
//grid.set_hexpand(true);
|
||||
// grid.set_fill(false);
|
||||
|
||||
boxV.append(grid);
|
||||
|
||||
this->set_titlebar(bar);
|
||||
this->set_child(boxV);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
auto app = Gtk::Application::create("eu.minesweeper");
|
||||
return app->make_window_and_run<MainWindow>(argc, argv);
|
||||
}
|
||||
Reference in New Issue
Block a user