Compare commits

..

No commits in common. "v1.26" and "main" have entirely different histories.
v1.26 ... main

4 changed files with 276 additions and 166 deletions

1
.gitignore vendored
View File

@ -6,4 +6,3 @@ lib
.vscode
bin
build
Makefile

View File

@ -9,7 +9,7 @@ DBG_CXXFLAGS := $(CXXFLAGS) -g
RLS_CXXFLAGS := $(CXXFLAGS) -O2
# linker stuff
LDFLAGS := -lncursesw
LDFLAGS := -lncursesw -lSDL2
DBG_LDFLAGS := $(LDFLAGS)
RLS_LDFLAGS := $(LDFLAGS) -s
@ -39,7 +39,7 @@ $(shell mkdir -p $(RLS_DIR))
$(shell mkdir -p $(BUILD_DIR))
# phony rules
.PHONY := all debug release clean install uninstall
.PHONY = all debug release clean install uninstall
all: release

View File

@ -1,72 +0,0 @@
# SPDX-FileCopyrightText: 2025 thorium1256
#
# SPDX-License-Identifier: GPL-3.0-or-later
# compiler stuff
CXX := c++
CXXFLAGS := -I include -std=c++11 -Wall -Wextra
DBG_CXXFLAGS := $(CXXFLAGS) -g
RLS_CXXFLAGS := $(CXXFLAGS) -O2
# linker stuff
LDFLAGS := -L C:\msys64\mingw64\bin -lncursesw6
DBG_LDFLAGS := $(LDFLAGS)
RLS_STRP_LDFLAGS := $(LDFLAGS) -s
# directories
BUILD_DIR := build
SRC_DIR := src
BIN_DIR := bin
DBG_DIR := $(BIN_DIR)\debug
RLS_DIR := $(BIN_DIR)\release
LIB_DIR := lib
DBG_EXEC := $(DBG_DIR)\debug.exe
RLS_STRIPPED_EXEC := $(RLS_DIR)\tuimine.exe
# sources and objects
LIBS := $(wildcard $(LIB_DIR)/*.dll)
LIBS_DBG := $(patsubst $(LIB_DIR)/%.dll, $(DBG_DIR)\\%.dll, $(LIBS))
LIBS_RLS := $(patsubst $(LIB_DIR)/%.dll, $(RLS_DIR)\\%.dll, $(LIBS))
SRCS := $(wildcard $(SRC_DIR)/*.cpp)
DBG_OBJS := $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/debug_%.o,$(SRCS))
RLS_OBJS := $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/release_%.o,$(SRCS))
$(shell if not exist $(BIN_DIR) mkdir $(BIN_DIR))
$(shell if not exist $(DBG_DIR) mkdir $(DBG_DIR))
$(shell if not exist $(RLS_DIR) mkdir $(RLS_DIR))
$(shell if not exist $(BUILD_DIR) mkdir $(BUILD_DIR))
# phony rules
.PHONY := all debug release clean libraries_debug libraries_release both
all: release
debug: $(DBG_EXEC) libraries_debug
release: $(RLS_STRIPPED_EXEC) libraries_release
both: debug release
libraries_debug: $(LIBS_DBG)
libraries_release: $(LIBS_RLS)
# linking
$(DBG_EXEC): $(DBG_OBJS)
$(CXX) -o $@ $^ $(DBG_LDFLAGS)
$(RLS_STRIPPED_EXEC): $(RLS_OBJS)
$(CXX) -o $@ $^ $(RLS_STRP_LDFLAGS)
# compiling
$(BUILD_DIR)/debug_%.o: $(SRC_DIR)/%.cpp
$(CXX) -c -o $@ $< $(DBG_CXXFLAGS)
$(BUILD_DIR)/release_%.o: $(SRC_DIR)/%.cpp
$(CXX) -c -o $@ $< $(RLS_CXXFLAGS)
$(DBG_DIR)\\%.dll: $(LIB_DIR)\\%.dll
xcopy $< $(DBG_DIR)\ >nul
$(RLS_DIR)\\%.dll: $(LIB_DIR)\\%.dll
xcopy $< $(RLS_DIR)\ >nul
clean:
rmdir /s /q $(BUILD_DIR) $(DBG_DIR) $(RLS_DIR)

View File

@ -4,13 +4,25 @@
#include <iostream>
#include <stdexcept>
#include <ncursesw/ncurses.h>
#include <ncurses.h>
#include <ctime>
#include <unistd.h>
#include <SDL2/SDL.h>
#include "Board.h"
#ifndef _WIN32
#include <signal.h>
#include <sys/ioctl.h>
struct winsize w;
void handleSIGWINCH(int sig)
{
ioctl(STDIN_FILENO, TIOCGWINSZ, &w);
}
#endif
#define MAX_TIME 60
SDL_GameController *controller;
void startGame(Board &board)
{
int minesLeft = board.getMineCount();
@ -33,8 +45,17 @@ void startGame(Board &board)
while (gameRunning)
{
usleep((1000 / MAX_TIME) * 1000);
#ifndef _WIN32
if ((w.ws_row < boardSize.x + 3) || (w.ws_col < boardSize.y + 2))
{
mvprintw(w.ws_col / 2, w.ws_row / 2, "Your terminal is too small:");
mvprintw(w.ws_col / 2 + 1, w.ws_row / 2, "Current size: %dx%d", w.ws_row, w.ws_col);
mvprintw(w.ws_col / 2 + 2, w.ws_row / 2, "Min size: %dx%d", boardSize.x + 3, boardSize.y + 2);
refresh();
continue;
}
#endif
if (board.isGameOver() || board.isGameWon())
{
gameRunning = false;
@ -143,8 +164,115 @@ void startGame(Board &board)
c = getch();
if (c == ERR)
{
if (controller != nullptr)
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
if (event.type == SDL_CONTROLLERBUTTONDOWN)
{
switch (event.cbutton.button)
{
case SDL_CONTROLLER_BUTTON_DPAD_UP:
cursorY = (cursorY > 0) ? cursorY - 1 : boardSize.y - 1;
break;
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
cursorY = (cursorY < boardSize.y - 1) ? cursorY + 1 : 0;
break;
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
cursorX = (cursorX > 0) ? cursorX - 1 : boardSize.x - 1;
break;
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
cursorX = (cursorX < boardSize.x - 1) ? cursorX + 1 : 0;
break;
case SDL_CONTROLLER_BUTTON_START:
if (isPaused)
{
pauseTime = difftime(time(NULL), startPauseTime);
totalpausetime += pauseTime;
}
else
{
startPauseTime = time(NULL);
}
isPaused = !isPaused;
break;
case SDL_CONTROLLER_BUTTON_A:
if (!somethingHasBeenDone)
{
startTime = time(nullptr);
somethingHasBeenDone = true;
}
if (board.getCellStateAt(cursorX, cursorY) == Cell::State::Revealed)
{
if (!somethingHasBeenDone)
{
startTime = time(nullptr);
somethingHasBeenDone = true;
}
auto neighbors = board.getNeighborsOf(cursorX, cursorY);
int flagCount = 0;
for (const Cell &neighbor : neighbors)
{
if (neighbor.getState() == Cell::State::Flagged)
flagCount++;
}
if (static_cast<int>(board.revealCellAt(cursorX, cursorY).getContent()) > flagCount)
break;
for (const Cell &neighbor : neighbors)
{
if (neighbor.getState() == Cell::State::Flagged)
continue;
board.revealCellAt(neighbor.getPosition().x, neighbor.getPosition().y);
}
break;
}
board.revealCellAt(cursorX, cursorY);
break;
case SDL_CONTROLLER_BUTTON_B:
if (board.getCellStateAt(cursorX, cursorY) == Cell::State::Revealed)
break;
if (!somethingHasBeenDone)
{
startTime = time(nullptr);
somethingHasBeenDone = true;
}
if (board.getCellStateAt(cursorX, cursorY) == Cell::State::Flagged)
{
minesLeft++;
}
else
{
minesLeft--;
}
board.flagCellAt(cursorX, cursorY);
break;
case SDL_CONTROLLER_BUTTON_MISC1:
startTime = time(NULL);
minesLeft = board.getMineCount();
board.regenerateBoard();
somethingHasBeenDone = false;
elapsedTime = 0;
break;
case SDL_CONTROLLER_BUTTON_BACK:
echo();
cbreak();
endwin();
exit(0);
break;
}
}
else
{
break;
}
}
}
}
if (!(c == ERR))
{
switch (c)
{
case KEY_UP:
@ -160,6 +288,9 @@ void startGame(Board &board)
cursorX = (cursorX < boardSize.x - 1) ? cursorX + 1 : 0;
break;
case 'q':
echo();
cbreak();
endwin();
exit(0);
break;
case 'z':
@ -189,7 +320,7 @@ void startGame(Board &board)
board.flagCellAt(cursorX, cursorY);
break;
case 'r':
startTime = 0;
startTime = time(NULL);
minesLeft = board.getMineCount();
board.regenerateBoard();
somethingHasBeenDone = false;
@ -234,6 +365,7 @@ void startGame(Board &board)
}
break;
}
}
if (isPaused)
continue;
@ -255,13 +387,21 @@ void startGame(Board &board)
mvprintw(1, 8, "%s", tim);
attroff(COLOR_PAIR(3));
refresh();
while ((c = getch()) != 'q')
while (true)
{
c = getch();
if (c == 'r')
{
Board newBoard(boardSize.x, boardSize.y, board.getMineCount());
startGame(newBoard);
}
else if (c == 'q')
{
echo();
cbreak();
endwin();
exit(0);
}
};
}
else if (board.isGameWon())
@ -279,25 +419,68 @@ void startGame(Board &board)
attroff(COLOR_PAIR(3));
refresh();
int c;
while ((c = getch()) != 'q')
while (true)
{
c = getch();
if (c == 'r')
{
Board newBoard(boardSize.x, boardSize.y, board.getMineCount());
startGame(newBoard);
}
else if (c == 'q')
{
echo();
cbreak();
endwin();
exit(0);
}
};
}
}
SDL_GameController *findController()
{
for (int i = 0; i < SDL_NumJoysticks(); i++)
{
if (SDL_IsGameController(i))
{
return SDL_GameControllerOpen(i);
}
}
return nullptr;
}
int main()
{
#ifndef _WIN32
signal(SIGWINCH, handleSIGWINCH);
#endif
setlocale(LC_ALL, "");
initscr();
noecho();
cbreak();
keypad(stdscr, TRUE);
nodelay(stdscr, TRUE);
#ifndef _WIN32
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
#endif
bool controllerSupport;
if (SDL_Init(SDL_INIT_GAMECONTROLLER) < 0)
{
std::cerr << "SDL failed to initialize GameController API! Controller support will not be available!" << std::endl;
controllerSupport = false;
}
else
{
controllerSupport = true;
}
controller = findController();
if (controller != nullptr)
controllerSupport = false; // no controller for you
start_color();
init_pair(1, COLOR_BLUE, COLOR_BLACK);
@ -328,9 +511,9 @@ int main()
attroff(A_REVERSE);
mvprintw(3, 2, choice == 1 ? "" : "Intermediate (16x16, 40 mines)");
attron(A_REVERSE);
mvprintw(4, 2, choice == 2 ? "Expert (16x30, 99 mines)" : "");
mvprintw(4, 2, choice == 2 ? "Expert (30x16, 99 mines)" : "");
attroff(A_REVERSE);
mvprintw(4, 2, choice == 2 ? "" : "Expert (16x30, 99 mines)");
mvprintw(4, 2, choice == 2 ? "" : "Expert (30x16, 99 mines)");
refresh();
int ch = getch();