minesweeper/src/main.cpp

356 lines
9.5 KiB
C++

#include <iostream>
#include <stdexcept>
#include <ncursesw/ncurses.h>
#include <ctime>
#include <unistd.h>
#include "Board.h"
#define MAX_TIME 60
void startGame(Board &board)
{
int minesLeft = board.getMineCount();
Vector2 boardSize = board.getBoardSize();
int c;
int cursorX = 0, cursorY = 0;
refresh();
bool gameRunning = true;
time_t startTime = 0;
int elapsedTime = 0;
bool isPaused = false;
time_t startPauseTime = 0;
time_t pauseTime = 0;
time_t totalpausetime = 0;
bool somethingHasBeenDone = false;
while (gameRunning)
{
usleep((1000 / MAX_TIME) * 1000);
if (board.isGameOver() || board.isGameWon())
{
gameRunning = false;
}
if (!isPaused && somethingHasBeenDone)
elapsedTime = difftime(time(NULL), startTime) - totalpausetime;
char flags[5];
char tim[5];
sprintf(flags, "%03d", minesLeft);
sprintf(tim, "%03d", elapsedTime);
attron(COLOR_PAIR(3));
mvprintw(1, 1, "%s", flags);
attroff(COLOR_PAIR(3));
if (!isPaused)
mvprintw(1, 5, ":)");
else
mvprintw(1, 5, ":|");
attron(COLOR_PAIR(3));
mvprintw(1, 8, "%s", tim);
attroff(COLOR_PAIR(3));
refresh();
for (int y = 0; y < boardSize.y; y++)
{
for (int x = 0; x < boardSize.x; x++)
{
Cell::State state = board.getCellStateAt(x, y);
char displayChar = ' ';
if (state == Cell::State::Flagged)
{
displayChar = 'F';
}
else if (state == Cell::State::Revealed)
{
Cell::Content content = board.revealCellAt(x, y).getContent();
if (content == Cell::Content::Mine)
{
attron(COLOR_PAIR(7));
displayChar = '+';
}
else if (content != Cell::Content::Empty)
{
displayChar = '0' + static_cast<int>(content);
}
}
else if (state == Cell::State::Hidden)
{
displayChar = '#';
}
else if (state == Cell::State::NotAMine)
{
displayChar = 'X';
}
if (isPaused)
displayChar = '#';
if (x == cursorX && y == cursorY)
{
attron(A_REVERSE);
}
if (displayChar == 'F')
{
attron(COLOR_PAIR(9));
}
if (displayChar >= '1' && displayChar <= '8')
{
attron(COLOR_PAIR(displayChar - '0'));
}
if (displayChar == 'X')
{
attron(COLOR_PAIR(9));
}
mvaddch(y + 2, x + 1, displayChar);
if (displayChar == 'X')
{
attroff(COLOR_PAIR(9));
}
if (displayChar >= '1' && displayChar <= '8')
{
attroff(COLOR_PAIR(displayChar - '0'));
}
if (displayChar == 'F')
{
attroff(COLOR_PAIR(9));
}
if (displayChar == '+')
{
attroff(COLOR_PAIR(7));
}
if (x == cursorX && y == cursorY)
{
attroff(A_REVERSE);
}
}
}
c = getch();
if (c == ERR)
continue;
switch (c)
{
case KEY_UP:
cursorY = (cursorY > 0) ? cursorY - 1 : boardSize.y - 1;
break;
case KEY_DOWN:
cursorY = (cursorY < boardSize.y - 1) ? cursorY + 1 : 0;
break;
case KEY_LEFT:
cursorX = (cursorX > 0) ? cursorX - 1 : boardSize.x - 1;
break;
case KEY_RIGHT:
cursorX = (cursorX < boardSize.x - 1) ? cursorX + 1 : 0;
break;
case 'q':
return;
break;
case 'z':
if (!somethingHasBeenDone)
{
startTime = time(nullptr);
somethingHasBeenDone = true;
}
board.revealCellAt(cursorX, cursorY);
break;
case 'x':
if (!somethingHasBeenDone)
{
startTime = time(nullptr);
somethingHasBeenDone = true;
}
if (board.getCellStateAt(cursorX, cursorY) == Cell::State::Flagged)
{
minesLeft++;
}
else
{
minesLeft--;
}
board.flagCellAt(cursorX, cursorY);
break;
case 'r':
startTime = 0;
minesLeft = board.getMineCount();
board.regenerateBoard();
somethingHasBeenDone = false;
elapsedTime = 0;
break;
case 'p':
if (isPaused)
{
pauseTime = difftime(time(NULL), startPauseTime);
totalpausetime += pauseTime;
}
else
{
startPauseTime = time(NULL);
}
isPaused = !isPaused;
break;
case 'c':
if (!somethingHasBeenDone)
{
startTime = time(nullptr);
somethingHasBeenDone = true;
}
auto neighbors = board.getNeighborsOf(cursorX, cursorY);
for (const Cell &neighbor : neighbors)
{
if (neighbor.getState() == Cell::State::Flagged)
continue;
board.revealCellAt(neighbor.getPosition().x, neighbor.getPosition().y);
}
break;
}
if (isPaused)
continue;
refresh();
}
if (board.isGameOver())
{
char flags[3];
char tim[3];
sprintf(flags, "%03d", minesLeft);
sprintf(tim, "%03d", elapsedTime);
attron(COLOR_PAIR(3));
mvprintw(1, 1, "%s", flags);
attroff(COLOR_PAIR(3));
mvprintw(1, 5, "X(");
attron(COLOR_PAIR(3));
mvprintw(1, 8, "%s", tim);
attroff(COLOR_PAIR(3));
refresh();
while ((c = getch()) != 'q')
{
if (c == 'r')
{
Board newBoard(boardSize.x, boardSize.y, board.getMineCount());
startGame(newBoard);
}
};
}
else if (board.isGameWon())
{
char flags[3];
char tim[3];
sprintf(flags, "%03d", minesLeft);
sprintf(tim, "%03d", elapsedTime);
attron(COLOR_PAIR(3));
mvprintw(1, 1, "%s", flags);
attroff(COLOR_PAIR(3));
mvprintw(1, 5, "B)");
attron(COLOR_PAIR(3));
mvprintw(1, 8, "%s", tim);
attroff(COLOR_PAIR(3));
refresh();
int c;
while ((c = getch()) != 'q')
{
if (c == 'r')
{
Board newBoard(boardSize.x, boardSize.y, board.getMineCount());
startGame(newBoard);
}
};
}
}
int main()
{
setlocale(LC_ALL, "");
initscr();
noecho();
cbreak();
keypad(stdscr, TRUE);
nodelay(stdscr, TRUE);
start_color();
init_pair(1, COLOR_BLUE, COLOR_BLACK);
init_pair(2, COLOR_GREEN, COLOR_BLACK);
init_pair(3, COLOR_RED, COLOR_BLACK);
init_pair(4, COLOR_BLUE, COLOR_BLACK);
init_pair(5, COLOR_RED, COLOR_BLACK);
init_pair(6, COLOR_CYAN, COLOR_BLACK);
init_pair(7, COLOR_BLACK, COLOR_WHITE);
init_pair(8, COLOR_WHITE, COLOR_BLACK);
init_pair(9, COLOR_RED, COLOR_WHITE);
int choice = 0;
int max_choice = 2;
curs_set(0);
while (true)
{
usleep((1000 / MAX_TIME) * 1000);
mvprintw(1, 1, "Select a difficulty:");
attron(A_REVERSE);
mvprintw(2, 2, choice == 0 ? "Beginner (9x9, 10 mines)" : "");
attroff(A_REVERSE);
mvprintw(2, 2, choice == 0 ? "" : "Beginner (9x9, 10 mines)");
attron(A_REVERSE);
mvprintw(3, 2, choice == 1 ? "Intermediate (16x16, 40 mines)" : "");
attroff(A_REVERSE);
mvprintw(3, 2, choice == 1 ? "" : "Intermediate (16x16, 40 mines)");
attron(A_REVERSE);
mvprintw(4, 2, choice == 2 ? "Expert (16x30, 99 mines)" : "");
attroff(A_REVERSE);
mvprintw(4, 2, choice == 2 ? "" : "Expert (16x30, 99 mines)");
refresh();
int ch = getch();
switch (ch)
{
case KEY_UP:
choice = (choice > 0) ? choice - 1 : max_choice;
break;
case KEY_DOWN:
choice = (choice < max_choice) ? choice + 1 : 0;
break;
case '\n':
int w, h, mines;
if (choice == 0)
{
w = 9;
h = 9;
mines = 10;
}
else if (choice == 1)
{
w = 16;
h = 16;
mines = 40;
}
else
{
w = 16;
h = 30;
mines = 99;
}
Board board(w, h, mines);
clear();
startGame(board);
curs_set(2);
endwin();
return 0;
}
}
}