/* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "Board.h" Board:: Board(int width, int height, int minecount) { this->width = width; this->height = height; this->tilecount = width*height; this->minecount = minecount; this->game_running = true; this->game_won = false; /* create tiles */ for (int x = 0; x < height; x++) { for (int y = 0; y < width; y++) { std::shared_ptr t(new Tile(x, y)); tiles.push_back(t); } } generate_mines(); retrieve_neighbors(); } Board::~Board() { } Tile *Board::get_tile_at(int x, int y) { return tiles.at(this->width*x+y).get(); } bool Board::reveal_tile_at(int x, int y) { Tile *tile = get_tile_at(x, y); printf("revealing x: %d y: %d\n", tile->get_x(), tile->get_y()); if (tile->is_mine()) { /* lose */ reveal_all_mines(); game_running = false; game_won = false; return false; } tile->reveal(); reveal_neighbor_tiles(tile->get_x(), tile->get_y()); if (check_win()) { /* win */ reveal_all_mines(); game_won = true; game_running = false; } return true; } void Board::new_game(int x, int y) { } void Board::reveal_all_mines() { Tile *tile; for(auto t = tiles.begin(); t != tiles.end(); ++t) { tile = (*t).get(); /* explicitly unflag tile */ tile->clear_flag(Tile::FLAGGED); // FIXME: doesnt work as intended, it should unflag all tiles if (tile->is_mine()) { tile->set_flag(Tile::REVEALED); } } } void Board::retrieve_neighbors() { Tile *tile; for(auto t = tiles.begin(); t != tiles.end(); ++t) { tile = (*t).get(); int badup = 0, baddown = 0, badleft = 0, badright = 0; if (tile->get_x()-1<0) badleft = 1; if (tile->get_x()+1>width-1) badright = 1; if (tile->get_y()-1<0) badup = 1; if (tile->get_y()+1>height-1) baddown = 1; if (!badleft && !badup) tile->neighbors[0] = get_tile_at(tile->get_x()-1, tile->get_y()-1); if (!badup) tile->neighbors[1] = get_tile_at(tile->get_x(), tile->get_y()-1); if (!badright && !badup) tile->neighbors[2] = get_tile_at(tile->get_x()+1, tile->get_y()-1); if (!badleft) tile->neighbors[3] = get_tile_at(tile->get_x()-1, tile->get_y()); if (!badright) tile->neighbors[4] = get_tile_at(tile->get_x()+1, tile->get_y()); if (!badleft && !baddown) tile->neighbors[5] = get_tile_at(tile->get_x()-1, tile->get_y()+1); if (!baddown) tile->neighbors[6] = get_tile_at(tile->get_x(), tile->get_y()+1); if (!badright && !baddown) tile->neighbors[7] = get_tile_at(tile->get_x()+1, tile->get_y()+1); count_neighbor_mines(tile); } } void Board::count_neighbor_mines(Tile *tile) { Tile *neighbor; int mines = 0; for (int i = 0; i < 8; i++) { neighbor = tile->get_neighbor(i); if (neighbor) { if (neighbor->is_mine()) { mines++; } } } tile->set_neighbor_mine_count(mines); printf("init tile: x: %d, y: %d, neighbor mines: %d\n", tile->get_x(), tile->get_y(), tile->get_neighbor_mine_count()); } void Board::generate_mines() { srand(time(NULL)); int mx, my; Tile *tile; for (int i = 0; i < minecount; i++) { replace_mine: mx = rand() % width; my = rand() % height; tile = get_tile_at(mx, my); if (tile->is_mine()) /* don't overwrite mines */ goto replace_mine; tile->set_flag(Tile::MINE); } } bool Board::reveal_neighbor_tiles(int x, int y) { /* * reveal all neighbor tiles that are empty, recursively */ Tile *tile, *neighbor; tile = get_tile_at(x, y); /* always reveal the first tile even if it has a neighbor mines */ tile->set_flag(Tile::REVEALED); if (tile->is_mine()) return false; if (tile->get_neighbor_mine_count() == 0) { /* if our tile is empty we want to reveal its immediate neighbors */ for (int nc = 0; nc < 8; nc++) { neighbor = tile->get_neighbor(nc); if (neighbor != nullptr && !neighbor->is_mine() && !neighbor->is_revealed()) { reveal_neighbor_tiles(neighbor->get_x(), neighbor->get_y()); } } } return true; } bool Board::check_win() { int allowedmines = minecount; int safetiles = (height * width) - minecount; int correctflags = 0; int correcttiles = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { Tile *tile = get_tile_at(x, y); if (tile->is_mine() && tile->is_flagged()) correctflags++; else if (!(tile->is_mine()) && (tile->is_revealed())) correcttiles++; } } return (correctflags == allowedmines) || (correcttiles == safetiles); }