diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ee5ad1db..965666d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,24 +4,23 @@ on: push: paths: - "**.cpp" + - "**.hpp" - "**.cmake" - "**/CMakeLists.txt" - ".github/workflows/ci.yml" pull_request: - paths: - - "**.cpp" - - "**.cmake" - - "**/CMakeLists.txt" - - ".github/workflows/ci.yml" + jobs: - linux: + core: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, windows-latest, macos-latest] + os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@v2 + - &checkout + uses: actions/checkout@v6 - - run: ctest -S setup.cmake -VV + - run: cmake --workflow debug + - run: cmake --workflow release diff --git a/CMakeLists.txt b/CMakeLists.txt index 352c8dfd..bacffc6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,21 +1,23 @@ -cmake_minimum_required(VERSION 3.7...3.21) +cmake_minimum_required(VERSION 3.15...4.3) project(2048 LANGUAGES CXX) enable_testing() set(SOURCES src/2048.cpp src/gameboard.cpp src/gameboard-graphics.cpp src/game.cpp src/game-graphics.cpp src/game-input.cpp src/game-pregamemenu.cpp src/global.cpp src/loadresource.cpp src/menu.cpp src/menu-graphics.cpp src/saveresource.cpp src/scores.cpp src/scores-graphics.cpp src/statistics.cpp src/statistics-graphics.cpp src/tile.cpp src/tile-graphics.cpp) -if(CMAKE_CXX_COMPILER_ID STREQUAL GNU) - add_compile_options(-Wall) -elseif(CMAKE_CXX_COMPILER_ID STREQUAL Clang) - add_compile_options(-Wall) -elseif(CMAKE_CXX_COMPILER_ID MATCHES "^Intel") +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + add_compile_options($<$:-Wall>) +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + add_compile_options($<$:-Wall>) +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") if(WIN32) - add_compile_options(/W3) + add_compile_options($<$:/W3>) else() - add_compile_options(-w2) + add_compile_options($<$:-w2>) endif() -elseif(CMAKE_CXX_COMPILER_ID STREQUAL NVHPC) - add_compile_options(-a) +elseif(MSVC) + add_compile_options($<$:/W3>) +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "NVHPC") + add_compile_options($<$:-a>) endif() add_executable(2048 ${SOURCES}) @@ -33,8 +35,7 @@ endif() # --- install -install(TARGETS 2048 - RUNTIME DESTINATION bin) +install(TARGETS 2048) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data - DESTINATION ${CMAKE_INSTALL_PREFIX}) + DESTINATION ${CMAKE_INSTALL_PREFIX}/data) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 00000000..04211d37 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,66 @@ +{ + "version": 6, + + "configurePresets": [ +{ + "name": "default", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_COMPILE_WARNING_AS_ERROR": true, + "CMAKE_LINK_WARNING_AS_ERROR": true + } +}, +{ + "name": "multi", "inherits": "default", + "generator": "Ninja Multi-Config" +} +], +"buildPresets": [ + { "name": "default", "configurePreset": "default" }, + { "name": "debug", "configurePreset": "multi", "configuration": "Debug" }, + { "name": "release", "configurePreset": "multi", "configuration": "Release" } +], +"testPresets": [ +{ + "name": "default", + "configurePreset": "default", + "output": { + "outputOnFailure": true, + "verbosity": "verbose" + }, + "execution": { + "noTestsAction": "error", + "scheduleRandom": true, + "stopOnFailure": false, + "timeout": 60 + } +}, +{ "name": "debug", "inherits": "default", "configurePreset": "multi", "configuration": "Debug" }, +{ "name": "release", "inherits": "default", "configurePreset": "multi", "configuration": "Release" } +], +"workflowPresets": [ + { + "name": "default", + "steps": [ + { "type": "configure", "name": "default" }, + { "type": "build", "name": "default" }, + { "type": "test", "name": "default" } + ] + }, + { "name": "debug", + "steps": [ + { "type": "configure", "name": "multi" }, + { "type": "build", "name": "debug" }, + { "type": "test", "name": "debug" } + ] + }, + { + "name": "release", + "steps": [ + { "type": "configure", "name": "multi" }, + { "type": "build", "name": "release" }, + { "type": "test", "name": "release" } + ] + } +] +} diff --git a/meson.build b/meson.build deleted file mode 100644 index c7164df7..00000000 --- a/meson.build +++ /dev/null @@ -1,14 +0,0 @@ -project('2048', 'cpp', - default_options : ['cpp_std=c++14', 'warning_level=2']) - -main_target_name = '2048' -sources = ['src/2048.cpp', 'src/gameboard.cpp', 'src/gameboard-graphics.cpp', 'src/game.cpp', 'src/game-input.cpp', 'src/game-graphics.cpp', 'src/game-pregamemenu.cpp', 'src/global.cpp', 'src/loadresource.cpp', 'src/menu.cpp', 'src/menu-graphics.cpp', 'src/saveresource.cpp', 'src/scores.cpp', 'src/scores-graphics.cpp', 'src/statistics.cpp', 'src/statistics-graphics.cpp', 'src/tile.cpp', 'src/tile-graphics.cpp'] -hdrs = include_directories('src/headers') - -executable(main_target_name, sources, - include_directories : hdrs, - install : true) - -install_data(['data/scores.txt', 'data/statistics.txt'], - install_dir : 'data') - diff --git a/setup.cmake b/setup.cmake deleted file mode 100644 index b3720c7d..00000000 --- a/setup.cmake +++ /dev/null @@ -1,69 +0,0 @@ -# run by: -# ctest -S setup.cmake - -# --- Project-specific -Doptions -# these will be used if the project isn't already configured. -set(_opts) - -# --- boilerplate follows - -# CTEST_CMAKE_GENERATOR must always be defined -if(NOT DEFINED CTEST_CMAKE_GENERATOR AND DEFINED ENV{CMAKE_GENERATOR}) - set(CTEST_CMAKE_GENERATOR $ENV{CMAKE_GENERATOR}) -endif() -if(NOT DEFINED CTEST_CMAKE_GENERATOR AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.17) - find_program(_gen NAMES ninja ninja-build samu) - if(_gen) - execute_process(COMMAND ${_gen} --version - OUTPUT_VARIABLE _ninja_version - OUTPUT_STRIP_TRAILING_WHITESPACE - RESULT_VARIABLE _gen_ok - TIMEOUT 10) - if(_gen_ok EQUAL 0 AND _ninja_version VERSION_GREATER_EQUAL 1.10) - set(CTEST_CMAKE_GENERATOR "Ninja") - endif() - endif(_gen) -endif() -if(NOT DEFINED CTEST_CMAKE_GENERATOR) - set(CTEST_BUILD_FLAGS -j) # not --parallel as this goes to generator directly - if(WIN32) - set(CTEST_CMAKE_GENERATOR "MinGW Makefiles") - else() - set(CTEST_CMAKE_GENERATOR "Unix Makefiles") - endif() -endif() - -if(NOT DEFINED CTEST_BUILD_CONFIGURATION) - list(APPEND _opts -DCMAKE_BUILD_TYPE=Release) -endif() - -set(CTEST_SOURCE_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}) -if(NOT DEFINED CTEST_BINARY_DIRECTORY) - set(CTEST_BINARY_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/build) -endif() - -# -- build and test -ctest_start("Experimental") - -ctest_configure( - OPTIONS "${_opts}" - RETURN_VALUE _ret - CAPTURE_CMAKE_ERROR _err) -if(NOT (_ret EQUAL 0 AND _err EQUAL 0)) - message(FATAL_ERROR "Configure failed: return ${_ret} cmake return ${_err}") -endif() - -ctest_build( - RETURN_VALUE _ret - CAPTURE_CMAKE_ERROR _err) -if(NOT (_ret EQUAL 0 AND _err EQUAL 0)) - message(FATAL_ERROR "Build failed.") -endif() - -ctest_test( - RETURN_VALUE _ret - CAPTURE_CMAKE_ERROR _err) - -if(NOT (_ret EQUAL 0 AND _err EQUAL 0)) - message(FATAL_ERROR "Test failed.") -endif() diff --git a/src/global.cpp b/src/global.cpp index 7ad361a0..94eb7a5a 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -1,7 +1,11 @@ #include "global.hpp" #include "color.hpp" + #include #include +#include // for system +#include +#include #ifdef _WIN32 @@ -51,10 +55,12 @@ void wait_for_any_letter_input(std::istream &is) { void clearScreen() { #ifdef _WIN32 - system("cls"); + if(system("cls")) { #else - system("clear"); + if(system("clear")) { #endif + std::cerr << "Failed to clear screen: " << std::error_code(errno, std::generic_category()).message() << "\n"; + } }; std::string secondsFormat(double sec) { diff --git a/src/headers/gameboard.hpp b/src/headers/gameboard.hpp index 4f60a718..5b1886c0 100644 --- a/src/headers/gameboard.hpp +++ b/src/headers/gameboard.hpp @@ -5,7 +5,7 @@ #include #include -struct point2D_t; +class point2D_t; namespace Game { diff --git a/src/loadresource.cpp b/src/loadresource.cpp index 299dc3a7..a7f5c063 100644 --- a/src/loadresource.cpp +++ b/src/loadresource.cpp @@ -17,14 +17,14 @@ namespace { /** * @brief Counts the number of lines in a file until a line containing '[' is found. * - * This function opens a file specified by the given filename and counts the number - * of lines until it encounters a line that contains the character '['. If the file + * This function opens a file specified by the given filename and counts the number + * of lines until it encounters a line that contains the character '['. If the file * cannot be opened, it prints an error message and returns -1. * * @param filename The name of the file to be read. * @return The number of lines read before encountering a line with '['. Returns -1 if the file cannot be opened. */ -int GetLines(std::string filename) +int GetLines(std::string filename) { std::ifstream stateFile(filename); if (!stateFile) { @@ -48,10 +48,10 @@ int GetLines(std::string filename) /** * @brief Extracts tile data from a given input stream until a line containing '[' is encountered. * - * This function reads lines from the provided input stream and extracts tile data - * formatted as comma-separated values. The process continues until either the maximum - * width (10 lines) is reached or a line containing the character '[' is found. When - * a line with '[' is encountered, the function stops reading further and processes + * This function reads lines from the provided input stream and extracts tile data + * formatted as comma-separated values. The process continues until either the maximum + * width (10 lines) is reached or a line containing the character '[' is found. When + * a line with '[' is encountered, the function stops reading further and processes * the line up to, but not including, the '[' character. * * @param buf The input stream from which to read the tile data. @@ -181,7 +181,7 @@ load_game_stats_from_file(std::string filename) { * @brief Loads game data from a specified file into a GameBoard object. * * This function opens a file specified by the given filename, reads the game board data, - * and initializes a GameBoard object with the read data. It first counts the number of lines + * and initializes a GameBoard object with the read data. It first counts the number of lines * until a line containing '[' is found to determine the size of the game board. Then, it reads * the tile data from the file, processes it, and updates the GameBoard object. Finally, it reads * the score and move count from the last relevant line containing these values. diff --git a/src/saveresource.cpp b/src/saveresource.cpp index 7b28402d..92536f6c 100644 --- a/src/saveresource.cpp +++ b/src/saveresource.cpp @@ -1,5 +1,8 @@ #include "saveresource.hpp" #include "gameboard.hpp" + +#include +#include #include #include @@ -10,14 +13,14 @@ namespace { /** * @brief Generates a file from the previous game's statistics data. - * + * * This function writes the score and move count of the given game board to the provided output stream. * The data is formatted as "score:moveCount]" to indicate the end of the statistics data. - * + * * @param os The output stream where the statistics data will be written. * @param gb The game board containing the statistics to be saved. * @return bool Returns true after successfully writing the statistics data. - * + * * @note The ']' character is used to signify the end of the statistics data. */ bool generateFilefromPreviousGameStatisticsData(std::ostream &os, @@ -28,10 +31,10 @@ bool generateFilefromPreviousGameStatisticsData(std::ostream &os, /** * @brief Generates a file from the previous game's state data. - * + * * This function writes the state of the given game board to the provided output stream. * The data is formatted using the printStateOfGameBoard function. - * + * * @param os The output stream where the state data will be written. * @param gb The game board containing the state to be saved. * @return bool Returns true after successfully writing the state data. @@ -44,10 +47,10 @@ bool generateFilefromPreviousGameStateData(std::ostream &os, /** * @brief Saves the previous game state and statistics to a file. - * + * * This function creates or appends to a file specified by the filename, saving both the game state and statistics. * The game state is written first, followed by the game statistics. - * + * * @param filename The name of the file where the game state and statistics will be saved. * @param gb The game board containing the state and statistics to be saved. */ @@ -73,32 +76,35 @@ void saveToFilePreviousGameStateData(std::string filename, /** * @brief Saves the current game state to a file. - * + * * This function checks for the existence of the directory and creates it if necessary. - * It then removes any existing file with the specified filename before saving the - * current state and statistics of the provided game board to a new file. This ensures + * It then removes any existing file with the specified filename before saving the + * current state and statistics of the provided game board to a new file. This ensures * that only the most recent game state is saved. - * + * * @param gb The game board object containing the current state to be saved. * @param filename The name of the file where the game state will be saved. This file will * be located in the ../data/SavedGameFiles/ directory. If a file with this * name already exists, it will be deleted before saving the new state. - * + * * @note If the directory does not exist, it will be created. Ensure that the application * has the necessary permissions to write to the specified location. */ void saveGamePlayState(GameBoard gb, const std::string& filename) { - std::filesystem::path directory_path = "../data/SavedGameFiles/"; + const std::filesystem::path directory_path = "../data/SavedGameFiles/"; + + std::error_code ec; - if (!std::filesystem::exists(directory_path)) - { - std::filesystem::create_directories(directory_path); + std::filesystem::create_directories(directory_path, ec); + if (ec) { + std::cerr << directory_path << " " << ec.message() << "\n"; + return; } - const auto path_to_file_gd_state = "../data/SavedGameFiles/" + filename; - std::remove(path_to_file_gd_state.c_str()); + const auto path_to_file_gd_state = directory_path / filename; + std::filesystem::remove(path_to_file_gd_state); - saveToFilePreviousGameStateData(path_to_file_gd_state, gb); + saveToFilePreviousGameStateData(path_to_file_gd_state.string(), gb); } } // namespace Saver