Skip to content

Commit

Permalink
Merge pull request #146 from BurhanHTW/new-feature-branch
Browse files Browse the repository at this point in the history
Update CMakelists.txt to C++17, src directory and adding .vscode into…
  • Loading branch information
plibither8 authored Jun 24, 2024
2 parents 30597b1 + 28cfb0d commit ad931d9
Show file tree
Hide file tree
Showing 16 changed files with 571 additions and 81 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
/data/*
2048
/.vscode
/src/.vscode/
.DS_Store

# CMake
Expand All @@ -47,4 +48,4 @@ Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
CTestTestfile.cmake
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ endif()

add_executable(2048 ${SOURCES})
target_include_directories(2048 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/headers/)
target_compile_features(2048 PRIVATE cxx_std_14)
target_compile_features(2048 PRIVATE cxx_std_17)

# --- test

Expand Down
13 changes: 12 additions & 1 deletion src/game-graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,22 @@ std::string BoardSizeErrorPrompt() {
return error_prompt_richtext.str();
}

/**
* @brief Generates a string prompt listing the available input commands.
*
* This function creates a formatted string that lists the available input commands for the game.
* The commands include movements (Up, Left, Down, Right), saving the game, and returning to the menu.
* The prompt is formatted with indentation for readability.
*
*
*
* @return std::string A formatted string containing the list of input commands.
*/
std::string InputCommandListPrompt() {
constexpr auto sp = " ";
const auto input_commands_list_text = {
"W or K or ↑ => Up", "A or H or ← => Left", "S or J or ↓ => Down",
"D or L or → => Right", "Z or P => Save"};
"D or L or → => Right", "Z or P => Save", "M => Return to menu"};
std::ostringstream str_os;
for (const auto txt : input_commands_list_text) {
str_os << sp << txt << "\n";
Expand Down
62 changes: 39 additions & 23 deletions src/game-pregamemenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,32 +125,40 @@ void SetUpNewGame(NewGameFlag ns) {
endlessLoop();
}

load_gameboard_status_t initialiseContinueBoardArray() {
/**
* @brief Initializes a GameBoard object by loading game data from a specified file.
*
* This function constructs the full path to the game data file by prepending "../data/" to the given filename.
* It then calls the `load_game` function to load the game data into a new GameBoard object. The function returns
* a tuple containing the status of the game load operation (true if successful, false otherwise) and the initialized
* GameBoard object.
*
* @param filename The name of the file from which to read the game data.
* @return A tuple containing a boolean indicating the success of the load operation and the initialized GameBoard object.
*/
load_gameboard_status_t initialiseContinueBoardArray(const std::string& filename)
{
using namespace Loader;
constexpr auto gameboard_data_filename = "../data/previousGame";
constexpr auto game_stats_data_filename = "../data/previousGameStats";
auto loaded_gameboard{false};
auto loaded_game_stats{false};
auto tempGBoard = GameBoard{1};
// Note: Reserved for gameboard.score and gameboard.moveCount!
// TODO: Combine data into one resource file.
auto score_and_movecount =
std::tuple<decltype(tempGBoard.score), decltype(tempGBoard.moveCount)>{};
std::tie(loaded_gameboard, tempGBoard) =
load_GameBoard_data_from_file(gameboard_data_filename);
std::tie(loaded_game_stats, score_and_movecount) =
load_game_stats_from_file(game_stats_data_filename);
std::tie(tempGBoard.score, tempGBoard.moveCount) = score_and_movecount;

const auto all_files_loaded_ok = (loaded_gameboard && loaded_game_stats);

return std::make_tuple(all_files_loaded_ok, tempGBoard);
// const auto gameboard_data_filename = "../data/" + filename;
auto gb = GameBoard{1};
auto loaded_game = load_game(filename, gb);
return std::make_tuple(loaded_game, gb);
}

void DoContinueOldGame() {

/**
* @brief Continues a previously saved game from a specified file.
*
* This function attempts to load the game state from the provided filename.
* If successful, it continues the game using the loaded state. If the loading
* fails, it sets up a new game indicating that no previous save is available.
*
* @param filename The name of the file from which to load the previous game state.
*/
void DoContinueOldGame(const std::string& filename) {
bool load_old_game_ok;
GameBoard oldGameBoard;
std::tie(load_old_game_ok, oldGameBoard) = initialiseContinueBoardArray();
std::tie(load_old_game_ok, oldGameBoard) = initialiseContinueBoardArray(filename);
if (load_old_game_ok) {
playGame(PlayGameFlag::ContinuePreviousGame, oldGameBoard);
} else {
Expand All @@ -164,8 +172,16 @@ void SetUpNewGame() {
SetUpNewGame(NewGameFlag::NewGameFlagNull);
}

void ContinueOldGame() {
DoContinueOldGame();
/**
* @brief Continue a previously saved game.
*
* The ContinueOldGame function has been updated to accept a filename directly.
* This allows the user to load a specific save file instead of only the last saved game.
*
* @param filename The name of the file containing the saved game to load.
*/
void ContinueOldGame(const std::string& filename) {
DoContinueOldGame(filename);
}

} // namespace PreGameSetup
Expand Down
142 changes: 136 additions & 6 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <chrono>
#include <iostream>
#include <sstream>
#include <random> // Required for generating random numbers/integers in the RemoveTiles() function.

namespace Game {
namespace {
Expand All @@ -28,13 +29,24 @@ enum GameStatusFlag {
FLAG_ENDLESS_MODE,
FLAG_GAME_IS_ASKING_QUESTION_MODE,
FLAG_QUESTION_STAY_OR_QUIT,
FLAG_TILES_REMOVED, // Indicates if tiles have already been removed
MAX_NO_GAME_STATUS_FLAGS
};

using gamestatus_t = std::array<bool, MAX_NO_GAME_STATUS_FLAGS>;

using gamestatus_gameboard_t = std::tuple<gamestatus_t, GameBoard>;

/**
* @brief Processes the game logic for the current game state.
*
* This function updates the game status and game board based on the current state.
* It handles tile movements, checks for game-winning conditions, and verifies if the game can continue.
* If the player cannot make any more moves, it prompts the player to remove random tiles before ending the game.
*
* @param gsgb A tuple containing the current game status and game board.
* @return gamestatus_gameboard_t A tuple containing the updated game status and game board.
*/
gamestatus_gameboard_t process_gamelogic(gamestatus_gameboard_t gsgb) {
gamestatus_t gamestatus;
GameBoard gb;
Expand All @@ -53,7 +65,31 @@ gamestatus_gameboard_t process_gamelogic(gamestatus_gameboard_t gsgb) {
}
}
if (!canMoveOnGameboard(gb)) {
gamestatus[FLAG_END_GAME] = true;
if(gamestatus[FLAG_TILES_REMOVED] == false)
{
char input;
std::cout << "You lose. Do you want to remove random tiles (Y/N) ?" << std::endl;
std::cin >> input;

if(input == 'Y' || input == 'y')
{
gamestatus[FLAG_TILES_REMOVED] = true;
removeTiles(gb);
}
else if (input == 'N' || input == 'n')
{
gamestatus[FLAG_END_GAME] = true;
gamestatus[FLAG_START_MENU] = true;
}
else
{
std::cout << "Invalid input." << std::endl;
}
}
else
{
gamestatus[FLAG_END_GAME] = true;
}
}
return std::make_tuple(gamestatus, gb);
}
Expand Down Expand Up @@ -162,6 +198,21 @@ gamestatus_t update_one_shot_display_flags(gamestatus_t gamestatus) {
}

using bool_gamestatus_t = std::tuple<bool, gamestatus_t>;
/**
* @brief Processes non-standard input commands and updates the game status accordingly.
*
* This function handles additional input commands that are not part of the standard gameplay.
* It updates the game status based on the input character received. The function supports saving
* the game, quitting endless mode, and returning to the main menu.
*
* @param c The input character received from the user.
* @param gamestatus The current game status flags.
* @return bool_gamestatus_t A tuple containing a boolean indicating if the keycode is invalid and the updated game status flags.
*
* @note Changes in the new version:
* - Added support for returning to the main menu with CODE_RETURN_TO_MENU.
* - When CODE_RETURN_TO_MENU is detected, the appropriate main menu flags are set.
*/
bool_gamestatus_t check_input_other(char c, gamestatus_t gamestatus) {
using namespace Input::Keypress::Code;
auto is_invalid_keycode{true};
Expand All @@ -178,6 +229,12 @@ bool_gamestatus_t check_input_other(char c, gamestatus_t gamestatus) {
is_invalid_keycode = false;
}
break;
case CODE_RETURN_TO_MENU:
// When CODE_RETURN_TO_MENU is detected, the main menu is set to start, and game flags are adjusted. mainmenustatus[FLAG_START_MENU] = true;
mainmenustatus[FLAG_START_GAME] = false;
mainmenustatus[FLAG_CONTINUE_GAME] = false;
is_invalid_keycode = false;
break;
}
return std::make_tuple(is_invalid_keycode, gamestatus);
}
Expand Down Expand Up @@ -267,6 +324,21 @@ bool continue_playing_game(std::istream &in_os) {
return true;
}

/**
* @brief Processes the current game status and updates the game loop control.
*
* This function evaluates the current game status flags and takes appropriate actions:
* - It handles winning conditions and prompts the user to continue playing.
* - It checks for the end of the game conditions.
* - It manages saving the game state by prompting the user for a filename.
* - It resets the question asking event trigger for a new loop cycle.
*
* @param gsgb A tuple containing the current game status and game board.
* @return bool_gamestatus_t A tuple containing a boolean indicating whether to continue the game loop and the updated game status flags.
*
* @note Changes in the new version:
* - Added a prompt asking the user to enter a filename when saving the game state.
*/
bool_gamestatus_t process_gameStatus(gamestatus_gameboard_t gsgb) {
gamestatus_t gamestatus;
GameBoard gb;
Expand All @@ -288,7 +360,10 @@ bool_gamestatus_t process_gameStatus(gamestatus_gameboard_t gsgb) {
loop_again = false;
}
if (gamestatus[FLAG_SAVED_GAME]) {
Saver::saveGamePlayState(gb);
std::cout << "Please enter the filename to save the game state" << std::endl;
std::string filename;
std::cin >> filename;
Saver::saveGamePlayState(gb, filename);
}

// New loop cycle: reset question asking event trigger
Expand Down Expand Up @@ -361,13 +436,31 @@ std::string drawEndGameLoopGraphics(current_game_session_t finalgamestatus) {
return str_os.str();
}

/**
* @brief Runs the endless game loop until the game ends or the user returns to the menu.
*
* This function manages the continuous gameplay loop for the endless game mode.
* It repeatedly calls the solo game loop until the game ends or the user chooses to return to the menu.
* The game status and game board are updated accordingly in each iteration.
*
* @param currentBestScore The current best score achieved.
* @param cm The competition mode settings.
* @param gb The current game board state.
* @return GameBoard The final state of the game board after the loop ends.
*
* @note Changes in the new version:
* - Added checks to monitor if the current state is set to GAME or MENU.
* - The loop will terminate if the user presses the M key and the state changes to MENU.
*/
GameBoard endlessGameLoop(ull currentBestScore, competition_mode_t cm,
GameBoard gb) {
auto loop_again{true};
auto currentgamestatus =
std::make_tuple(currentBestScore, cm, gamestatus_t{}, gb);

while (loop_again) {
// Monitor the loop to check if the current state is still set to GAME
// If not, then the M key was pressed, setting the current state to MENU
// Thus, we return to the menu
while (loop_again && ((mainmenustatus[FLAG_START_GAME] == true) || (mainmenustatus[FLAG_CONTINUE_GAME] == true))) {
std::tie(loop_again, currentgamestatus) = soloGameLoop(currentgamestatus);
}

Expand Down Expand Up @@ -423,8 +516,45 @@ void startGame() {
PreGameSetup::SetUpNewGame();
}

void continueGame() {
PreGameSetup::ContinueOldGame();
/**
* @brief Continue a previously saved game.
*
* The ContinueOldGame function has been updated to accept a filename directly.
* This allows the user to load a specific save file instead of only the last saved game.
*
* @param filename The name of the file containing the saved game to load.
*/
void continueGame(const std::string& filename) {
PreGameSetup::ContinueOldGame(filename);
}

/**
* @brief Randomly removes two tiles from a GameBoard by setting their values to 0.
*
* This function uses a random number generator to select and remove two non-empty tiles
* from the given GameBoard by setting their values to 0. The process continues until
* exactly two tiles are removed.
*
* @param gb The GameBoard object from which tiles will be removed.
*/
void removeTiles(GameBoard& gb) {
// Seed with a real random value, if available
std::random_device rd;
std::mt19937 gen(rd());

auto& [playsize, tiles] = gb.gbda;
std::uniform_int_distribution<> dis(0, tiles.size() - 1);

int tiles_to_remove = 2;
while (tiles_to_remove > 0) {
int random_index = dis(gen);
auto& tile = tiles[random_index];

if (tile.value != 0) { // Ensure it's not already an empty tile
tile.value = 0; // Remove the tile
--tiles_to_remove;
}
}
}

} // namespace Game
18 changes: 17 additions & 1 deletion src/gameboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,19 @@ bool getTileBlockedOnGameboardDataArray(gameboard_data_array_t gbda,
return gameboard_data_point_t{}(gbda, pt).blocked;
}

/**
* @brief Generates a string representation of the game board data array.
*
* This function creates a formatted string that represents the current state of the game board.
* It includes the tile values and their blocked status for each position on the board.
* The string representation ends with a "[" character to indicate the end of the data.
*
* @param gbda The game board data array to be printed.
* @return std::string A formatted string representing the game board state.
*
* @note Changes in the new version:
* - Added a "[" character at the end of the string to indicate the end of the data.
*/
std::string printStateOfGameBoardDataArray(gameboard_data_array_t gbda) {
const int playsize = getPlaySizeOfGameboardDataArray(gbda);
std::ostringstream os;
Expand All @@ -78,6 +91,7 @@ std::string printStateOfGameBoardDataArray(gameboard_data_array_t gbda) {
}
os << "\n";
}
os << "["; // Indicates the end of the game board data
return os.str();
}

Expand Down Expand Up @@ -135,7 +149,9 @@ bool canMoveOnGameboardDataArray(gameboard_data_array_t gbda) {
const auto offset_check = {
current_point + offset, // Positive adjacent check
current_point - offset}; // Negative adjacent Check
for (const auto current_offset : offset_check) {

// Use reference to avoid unnecessary copying of complex structures
for (const auto &current_offset : offset_check) {
if (is_point_in_board_play_area(current_offset, playsize)) {
return getTileValueOnGameboardDataArray(gbda, current_offset) ==
current_point_value;
Expand Down
3 changes: 2 additions & 1 deletion src/headers/game-input.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ enum {
CODE_HOTKEY_QUIT_ENDLESS_MODE = 'X',
CODE_HOTKEY_CHOICE_NO = 'N',
CODE_HOTKEY_CHOICE_YES = 'Y',
CODE_HOTKEY_PREGAMEMENU_BACK_TO_MAINMENU = 0
CODE_HOTKEY_PREGAMEMENU_BACK_TO_MAINMENU = 0,
CODE_RETURN_TO_MENU = 'M' // Press 'M' to return to menu
};

} // namespace Code
Expand Down
Loading

0 comments on commit ad931d9

Please sign in to comment.