Skip to content

Commit 28cfb0d

Browse files
committed
Update CMakelists.txt to C++17, src directory and adding .vscode into .gitignore
1 parent 30597b1 commit 28cfb0d

16 files changed

+571
-81
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
/data/*
3737
2048
3838
/.vscode
39+
/src/.vscode/
3940
.DS_Store
4041

4142
# CMake
@@ -47,4 +48,4 @@ Makefile
4748
cmake_install.cmake
4849
install_manifest.txt
4950
compile_commands.json
50-
CTestTestfile.cmake
51+
CTestTestfile.cmake

CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ endif()
2020

2121
add_executable(2048 ${SOURCES})
2222
target_include_directories(2048 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/headers/)
23-
target_compile_features(2048 PRIVATE cxx_std_14)
23+
target_compile_features(2048 PRIVATE cxx_std_17)
2424

2525
# --- test
2626

src/game-graphics.cpp

+12-1
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,22 @@ std::string BoardSizeErrorPrompt() {
117117
return error_prompt_richtext.str();
118118
}
119119

120+
/**
121+
* @brief Generates a string prompt listing the available input commands.
122+
*
123+
* This function creates a formatted string that lists the available input commands for the game.
124+
* The commands include movements (Up, Left, Down, Right), saving the game, and returning to the menu.
125+
* The prompt is formatted with indentation for readability.
126+
*
127+
*
128+
*
129+
* @return std::string A formatted string containing the list of input commands.
130+
*/
120131
std::string InputCommandListPrompt() {
121132
constexpr auto sp = " ";
122133
const auto input_commands_list_text = {
123134
"W or K or ↑ => Up", "A or H or ← => Left", "S or J or ↓ => Down",
124-
"D or L or → => Right", "Z or P => Save"};
135+
"D or L or → => Right", "Z or P => Save", "M => Return to menu"};
125136
std::ostringstream str_os;
126137
for (const auto txt : input_commands_list_text) {
127138
str_os << sp << txt << "\n";

src/game-pregamemenu.cpp

+39-23
Original file line numberDiff line numberDiff line change
@@ -125,32 +125,40 @@ void SetUpNewGame(NewGameFlag ns) {
125125
endlessLoop();
126126
}
127127

128-
load_gameboard_status_t initialiseContinueBoardArray() {
128+
/**
129+
* @brief Initializes a GameBoard object by loading game data from a specified file.
130+
*
131+
* This function constructs the full path to the game data file by prepending "../data/" to the given filename.
132+
* It then calls the `load_game` function to load the game data into a new GameBoard object. The function returns
133+
* a tuple containing the status of the game load operation (true if successful, false otherwise) and the initialized
134+
* GameBoard object.
135+
*
136+
* @param filename The name of the file from which to read the game data.
137+
* @return A tuple containing a boolean indicating the success of the load operation and the initialized GameBoard object.
138+
*/
139+
load_gameboard_status_t initialiseContinueBoardArray(const std::string& filename)
140+
{
129141
using namespace Loader;
130-
constexpr auto gameboard_data_filename = "../data/previousGame";
131-
constexpr auto game_stats_data_filename = "../data/previousGameStats";
132-
auto loaded_gameboard{false};
133-
auto loaded_game_stats{false};
134-
auto tempGBoard = GameBoard{1};
135-
// Note: Reserved for gameboard.score and gameboard.moveCount!
136-
// TODO: Combine data into one resource file.
137-
auto score_and_movecount =
138-
std::tuple<decltype(tempGBoard.score), decltype(tempGBoard.moveCount)>{};
139-
std::tie(loaded_gameboard, tempGBoard) =
140-
load_GameBoard_data_from_file(gameboard_data_filename);
141-
std::tie(loaded_game_stats, score_and_movecount) =
142-
load_game_stats_from_file(game_stats_data_filename);
143-
std::tie(tempGBoard.score, tempGBoard.moveCount) = score_and_movecount;
144-
145-
const auto all_files_loaded_ok = (loaded_gameboard && loaded_game_stats);
146-
147-
return std::make_tuple(all_files_loaded_ok, tempGBoard);
142+
// const auto gameboard_data_filename = "../data/" + filename;
143+
auto gb = GameBoard{1};
144+
auto loaded_game = load_game(filename, gb);
145+
return std::make_tuple(loaded_game, gb);
148146
}
149147

150-
void DoContinueOldGame() {
148+
149+
/**
150+
* @brief Continues a previously saved game from a specified file.
151+
*
152+
* This function attempts to load the game state from the provided filename.
153+
* If successful, it continues the game using the loaded state. If the loading
154+
* fails, it sets up a new game indicating that no previous save is available.
155+
*
156+
* @param filename The name of the file from which to load the previous game state.
157+
*/
158+
void DoContinueOldGame(const std::string& filename) {
151159
bool load_old_game_ok;
152160
GameBoard oldGameBoard;
153-
std::tie(load_old_game_ok, oldGameBoard) = initialiseContinueBoardArray();
161+
std::tie(load_old_game_ok, oldGameBoard) = initialiseContinueBoardArray(filename);
154162
if (load_old_game_ok) {
155163
playGame(PlayGameFlag::ContinuePreviousGame, oldGameBoard);
156164
} else {
@@ -164,8 +172,16 @@ void SetUpNewGame() {
164172
SetUpNewGame(NewGameFlag::NewGameFlagNull);
165173
}
166174

167-
void ContinueOldGame() {
168-
DoContinueOldGame();
175+
/**
176+
* @brief Continue a previously saved game.
177+
*
178+
* The ContinueOldGame function has been updated to accept a filename directly.
179+
* This allows the user to load a specific save file instead of only the last saved game.
180+
*
181+
* @param filename The name of the file containing the saved game to load.
182+
*/
183+
void ContinueOldGame(const std::string& filename) {
184+
DoContinueOldGame(filename);
169185
}
170186

171187
} // namespace PreGameSetup

src/game.cpp

+136-6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <chrono>
1515
#include <iostream>
1616
#include <sstream>
17+
#include <random> // Required for generating random numbers/integers in the RemoveTiles() function.
1718

1819
namespace Game {
1920
namespace {
@@ -28,13 +29,24 @@ enum GameStatusFlag {
2829
FLAG_ENDLESS_MODE,
2930
FLAG_GAME_IS_ASKING_QUESTION_MODE,
3031
FLAG_QUESTION_STAY_OR_QUIT,
32+
FLAG_TILES_REMOVED, // Indicates if tiles have already been removed
3133
MAX_NO_GAME_STATUS_FLAGS
3234
};
3335

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

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

40+
/**
41+
* @brief Processes the game logic for the current game state.
42+
*
43+
* This function updates the game status and game board based on the current state.
44+
* It handles tile movements, checks for game-winning conditions, and verifies if the game can continue.
45+
* If the player cannot make any more moves, it prompts the player to remove random tiles before ending the game.
46+
*
47+
* @param gsgb A tuple containing the current game status and game board.
48+
* @return gamestatus_gameboard_t A tuple containing the updated game status and game board.
49+
*/
3850
gamestatus_gameboard_t process_gamelogic(gamestatus_gameboard_t gsgb) {
3951
gamestatus_t gamestatus;
4052
GameBoard gb;
@@ -53,7 +65,31 @@ gamestatus_gameboard_t process_gamelogic(gamestatus_gameboard_t gsgb) {
5365
}
5466
}
5567
if (!canMoveOnGameboard(gb)) {
56-
gamestatus[FLAG_END_GAME] = true;
68+
if(gamestatus[FLAG_TILES_REMOVED] == false)
69+
{
70+
char input;
71+
std::cout << "You lose. Do you want to remove random tiles (Y/N) ?" << std::endl;
72+
std::cin >> input;
73+
74+
if(input == 'Y' || input == 'y')
75+
{
76+
gamestatus[FLAG_TILES_REMOVED] = true;
77+
removeTiles(gb);
78+
}
79+
else if (input == 'N' || input == 'n')
80+
{
81+
gamestatus[FLAG_END_GAME] = true;
82+
gamestatus[FLAG_START_MENU] = true;
83+
}
84+
else
85+
{
86+
std::cout << "Invalid input." << std::endl;
87+
}
88+
}
89+
else
90+
{
91+
gamestatus[FLAG_END_GAME] = true;
92+
}
5793
}
5894
return std::make_tuple(gamestatus, gb);
5995
}
@@ -162,6 +198,21 @@ gamestatus_t update_one_shot_display_flags(gamestatus_t gamestatus) {
162198
}
163199

164200
using bool_gamestatus_t = std::tuple<bool, gamestatus_t>;
201+
/**
202+
* @brief Processes non-standard input commands and updates the game status accordingly.
203+
*
204+
* This function handles additional input commands that are not part of the standard gameplay.
205+
* It updates the game status based on the input character received. The function supports saving
206+
* the game, quitting endless mode, and returning to the main menu.
207+
*
208+
* @param c The input character received from the user.
209+
* @param gamestatus The current game status flags.
210+
* @return bool_gamestatus_t A tuple containing a boolean indicating if the keycode is invalid and the updated game status flags.
211+
*
212+
* @note Changes in the new version:
213+
* - Added support for returning to the main menu with CODE_RETURN_TO_MENU.
214+
* - When CODE_RETURN_TO_MENU is detected, the appropriate main menu flags are set.
215+
*/
165216
bool_gamestatus_t check_input_other(char c, gamestatus_t gamestatus) {
166217
using namespace Input::Keypress::Code;
167218
auto is_invalid_keycode{true};
@@ -178,6 +229,12 @@ bool_gamestatus_t check_input_other(char c, gamestatus_t gamestatus) {
178229
is_invalid_keycode = false;
179230
}
180231
break;
232+
case CODE_RETURN_TO_MENU:
233+
// When CODE_RETURN_TO_MENU is detected, the main menu is set to start, and game flags are adjusted. mainmenustatus[FLAG_START_MENU] = true;
234+
mainmenustatus[FLAG_START_GAME] = false;
235+
mainmenustatus[FLAG_CONTINUE_GAME] = false;
236+
is_invalid_keycode = false;
237+
break;
181238
}
182239
return std::make_tuple(is_invalid_keycode, gamestatus);
183240
}
@@ -267,6 +324,21 @@ bool continue_playing_game(std::istream &in_os) {
267324
return true;
268325
}
269326

327+
/**
328+
* @brief Processes the current game status and updates the game loop control.
329+
*
330+
* This function evaluates the current game status flags and takes appropriate actions:
331+
* - It handles winning conditions and prompts the user to continue playing.
332+
* - It checks for the end of the game conditions.
333+
* - It manages saving the game state by prompting the user for a filename.
334+
* - It resets the question asking event trigger for a new loop cycle.
335+
*
336+
* @param gsgb A tuple containing the current game status and game board.
337+
* @return bool_gamestatus_t A tuple containing a boolean indicating whether to continue the game loop and the updated game status flags.
338+
*
339+
* @note Changes in the new version:
340+
* - Added a prompt asking the user to enter a filename when saving the game state.
341+
*/
270342
bool_gamestatus_t process_gameStatus(gamestatus_gameboard_t gsgb) {
271343
gamestatus_t gamestatus;
272344
GameBoard gb;
@@ -288,7 +360,10 @@ bool_gamestatus_t process_gameStatus(gamestatus_gameboard_t gsgb) {
288360
loop_again = false;
289361
}
290362
if (gamestatus[FLAG_SAVED_GAME]) {
291-
Saver::saveGamePlayState(gb);
363+
std::cout << "Please enter the filename to save the game state" << std::endl;
364+
std::string filename;
365+
std::cin >> filename;
366+
Saver::saveGamePlayState(gb, filename);
292367
}
293368

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

439+
/**
440+
* @brief Runs the endless game loop until the game ends or the user returns to the menu.
441+
*
442+
* This function manages the continuous gameplay loop for the endless game mode.
443+
* It repeatedly calls the solo game loop until the game ends or the user chooses to return to the menu.
444+
* The game status and game board are updated accordingly in each iteration.
445+
*
446+
* @param currentBestScore The current best score achieved.
447+
* @param cm The competition mode settings.
448+
* @param gb The current game board state.
449+
* @return GameBoard The final state of the game board after the loop ends.
450+
*
451+
* @note Changes in the new version:
452+
* - Added checks to monitor if the current state is set to GAME or MENU.
453+
* - The loop will terminate if the user presses the M key and the state changes to MENU.
454+
*/
364455
GameBoard endlessGameLoop(ull currentBestScore, competition_mode_t cm,
365456
GameBoard gb) {
366457
auto loop_again{true};
367458
auto currentgamestatus =
368459
std::make_tuple(currentBestScore, cm, gamestatus_t{}, gb);
369-
370-
while (loop_again) {
460+
// Monitor the loop to check if the current state is still set to GAME
461+
// If not, then the M key was pressed, setting the current state to MENU
462+
// Thus, we return to the menu
463+
while (loop_again && ((mainmenustatus[FLAG_START_GAME] == true) || (mainmenustatus[FLAG_CONTINUE_GAME] == true))) {
371464
std::tie(loop_again, currentgamestatus) = soloGameLoop(currentgamestatus);
372465
}
373466

@@ -423,8 +516,45 @@ void startGame() {
423516
PreGameSetup::SetUpNewGame();
424517
}
425518

426-
void continueGame() {
427-
PreGameSetup::ContinueOldGame();
519+
/**
520+
* @brief Continue a previously saved game.
521+
*
522+
* The ContinueOldGame function has been updated to accept a filename directly.
523+
* This allows the user to load a specific save file instead of only the last saved game.
524+
*
525+
* @param filename The name of the file containing the saved game to load.
526+
*/
527+
void continueGame(const std::string& filename) {
528+
PreGameSetup::ContinueOldGame(filename);
529+
}
530+
531+
/**
532+
* @brief Randomly removes two tiles from a GameBoard by setting their values to 0.
533+
*
534+
* This function uses a random number generator to select and remove two non-empty tiles
535+
* from the given GameBoard by setting their values to 0. The process continues until
536+
* exactly two tiles are removed.
537+
*
538+
* @param gb The GameBoard object from which tiles will be removed.
539+
*/
540+
void removeTiles(GameBoard& gb) {
541+
// Seed with a real random value, if available
542+
std::random_device rd;
543+
std::mt19937 gen(rd());
544+
545+
auto& [playsize, tiles] = gb.gbda;
546+
std::uniform_int_distribution<> dis(0, tiles.size() - 1);
547+
548+
int tiles_to_remove = 2;
549+
while (tiles_to_remove > 0) {
550+
int random_index = dis(gen);
551+
auto& tile = tiles[random_index];
552+
553+
if (tile.value != 0) { // Ensure it's not already an empty tile
554+
tile.value = 0; // Remove the tile
555+
--tiles_to_remove;
556+
}
557+
}
428558
}
429559

430560
} // namespace Game

src/gameboard.cpp

+17-1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,19 @@ bool getTileBlockedOnGameboardDataArray(gameboard_data_array_t gbda,
6767
return gameboard_data_point_t{}(gbda, pt).blocked;
6868
}
6969

70+
/**
71+
* @brief Generates a string representation of the game board data array.
72+
*
73+
* This function creates a formatted string that represents the current state of the game board.
74+
* It includes the tile values and their blocked status for each position on the board.
75+
* The string representation ends with a "[" character to indicate the end of the data.
76+
*
77+
* @param gbda The game board data array to be printed.
78+
* @return std::string A formatted string representing the game board state.
79+
*
80+
* @note Changes in the new version:
81+
* - Added a "[" character at the end of the string to indicate the end of the data.
82+
*/
7083
std::string printStateOfGameBoardDataArray(gameboard_data_array_t gbda) {
7184
const int playsize = getPlaySizeOfGameboardDataArray(gbda);
7285
std::ostringstream os;
@@ -78,6 +91,7 @@ std::string printStateOfGameBoardDataArray(gameboard_data_array_t gbda) {
7891
}
7992
os << "\n";
8093
}
94+
os << "["; // Indicates the end of the game board data
8195
return os.str();
8296
}
8397

@@ -135,7 +149,9 @@ bool canMoveOnGameboardDataArray(gameboard_data_array_t gbda) {
135149
const auto offset_check = {
136150
current_point + offset, // Positive adjacent check
137151
current_point - offset}; // Negative adjacent Check
138-
for (const auto current_offset : offset_check) {
152+
153+
// Use reference to avoid unnecessary copying of complex structures
154+
for (const auto &current_offset : offset_check) {
139155
if (is_point_in_board_play_area(current_offset, playsize)) {
140156
return getTileValueOnGameboardDataArray(gbda, current_offset) ==
141157
current_point_value;

src/headers/game-input.hpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ enum {
4646
CODE_HOTKEY_QUIT_ENDLESS_MODE = 'X',
4747
CODE_HOTKEY_CHOICE_NO = 'N',
4848
CODE_HOTKEY_CHOICE_YES = 'Y',
49-
CODE_HOTKEY_PREGAMEMENU_BACK_TO_MAINMENU = 0
49+
CODE_HOTKEY_PREGAMEMENU_BACK_TO_MAINMENU = 0,
50+
CODE_RETURN_TO_MENU = 'M' // Press 'M' to return to menu
5051
};
5152

5253
} // namespace Code

0 commit comments

Comments
 (0)