From 4a32631d79354830655b26530c1a1c9c676e8b5d Mon Sep 17 00:00:00 2001
From: Jamal <fredrick2.enoime@live.uwe.ac.uk>
Date: Sat, 3 May 2025 02:31:30 +0100
Subject: [PATCH] readme

---
 README.md | 1443 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1443 insertions(+)

diff --git a/README.md b/README.md
index 1c091a9..63bdae9 100644
--- a/README.md
+++ b/README.md
@@ -63,10 +63,1453 @@
   
 ### Issues
 - The gameplay seems to fragment possibly due to a logical error in my code (**will revisit**)
+- (REVISIT) to get a fully function version of my game with no bugs replace the following 
+- ui.cpp
+#include "UI.hpp"
+#include <cmath>
+#include <algorithm>
+#include <chrono>
+#include <thread>
+
+// Credit text with author name
+const std::string CREDIT_TEXT = "2048 Game";
+
+UI::UI()
+    : currentState(UIState::MAIN_MENU), previousState(UIState::MAIN_MENU), selectedMenuOption(0),
+      mainWindow(nullptr), gameWindow(nullptr), scoreWindow(nullptr), infoWindow(nullptr),
+      currentGameMode(GameModeType::CLASSIC), backgroundEffectTimer(0.0f),
+      animationsEnabled(true), currentTheme(0) {
+    
+    // Initialize menu options
+    mainMenuOptions = {"Play Game", "Select Mode", "Settings", "Tutorial", "Quit"};
+    modeSelectionOptions = {"Classic", "Back"};
+    pauseMenuOptions = {"Resume", "Restart", "Main Menu", "Quit"};
+    settingsOptions = {"Animations: ON", "Theme: Default", "Back"};
+    
+    // Initialize themes
+    initializeThemes();
+}
+
+UI::~UI() {
+    destroyWindows();
+    endwin();
+}
+
+bool UI::initialize() {
+    // Initialize ncurses
+    initscr();
+    start_color();
+    cbreak();
+    noecho();
+    keypad(stdscr, TRUE);
+    curs_set(0);  // Hide cursor
+    timeout(50);  // Non-blocking input with ~20fps refresh rate
+    
+    if (!has_colors()) {
+        endwin();
+        return false;
+    }
+    
+    // Initialize color pairs
+    init_pair(1, COLOR_BLACK, COLOR_WHITE);      // Default
+    init_pair(2, COLOR_BLACK, COLOR_GREEN);      // 2
+    init_pair(3, COLOR_BLACK, COLOR_CYAN);       // 4
+    init_pair(4, COLOR_BLACK, COLOR_BLUE);       // 8
+    init_pair(5, COLOR_BLACK, COLOR_MAGENTA);    // 16
+    init_pair(6, COLOR_BLACK, COLOR_RED);        // 32
+    init_pair(7, COLOR_WHITE, COLOR_BLUE);       // 64
+    init_pair(8, COLOR_WHITE, COLOR_MAGENTA);    // 128
+    init_pair(9, COLOR_WHITE, COLOR_RED);        // 256
+    init_pair(10, COLOR_WHITE, COLOR_YELLOW);    // 512
+    init_pair(11, COLOR_BLACK, COLOR_YELLOW);    // 1024
+    init_pair(12, COLOR_WHITE, COLOR_GREEN);     // 2048
+    init_pair(13, COLOR_WHITE, COLOR_RED);       // Higher
+    init_pair(14, COLOR_YELLOW, COLOR_BLACK);    // Gold text
+    init_pair(15, COLOR_CYAN, COLOR_BLACK);      // Cyan text
+    
+    // Initialize game
+    game = Game2048();
+    
+    // Create windows
+    createWindows();
+    
+    // Set up game callbacks
+    game.addObserver([this](GameEvent event, int row, int col, int value) {
+        switch (event) {
+            case GameEvent::TILE_MERGED:
+                onTileMerged(row, col, value);
+                break;
+            case GameEvent::TILE_SPAWNED:
+                onTileSpawned(row, col, value);
+                break;
+            case GameEvent::SCORE_CHANGED:
+                onScoreChanged(value, game.getScore() - value);
+                break;
+            case GameEvent::GAME_WON:
+                onVictory();
+                break;
+            case GameEvent::GAME_OVER:
+                onGameOver();
+                break;
+            default:
+                break;
+        }
+    });
+    
+    // Set default game mode
+    setGameMode(GameModeType::CLASSIC);
+    
+    return true;
+}
+
+void UI::createWindows() {
+    int maxY, maxX;
+    getmaxyx(stdscr, maxY, maxX);
+    
+    // Main window covers the entire screen
+    mainWindow = newwin(maxY, maxX, 0, 0);
+    keypad(mainWindow, TRUE);
+    
+    // Game window for the actual 2048 board
+    gameWindow = newwin(SIZE * 2 + 2, SIZE * 6 + 2, 2, (maxX - (SIZE * 6 + 2)) / 2);
+    
+    // Score window for displaying score and other game info
+    scoreWindow = newwin(3, 20, 2, maxX - 25);
+    
+    // Info window for instructions and status messages
+    infoWindow = newwin(5, maxX - 4, maxY - 6, 2);
+}
+
+void UI::destroyWindows() {
+    if (mainWindow) delwin(mainWindow);
+    if (gameWindow) delwin(gameWindow);
+    if (scoreWindow) delwin(scoreWindow);
+    if (infoWindow) delwin(infoWindow);
+}
+
+void UI::initializeThemes() {
+    // Default theme
+    Theme defaultTheme;
+    defaultTheme.name = "Default";
+    
+    // Dark theme
+    Theme darkTheme;
+    darkTheme.name = "Dark";
+    
+    // Add themes to the list
+    themes.push_back(defaultTheme);
+    themes.push_back(darkTheme);
+}
+
+void UI::applyTheme(int themeIndex) {
+    if (themeIndex < 0 || themeIndex >= static_cast<int>(themes.size())) {
+        return;
+    }
+    
+    currentTheme = themeIndex;
+    
+    // Apply theme colors
+    const Theme& theme = themes[currentTheme];
+    
+    // Update settings menu
+    settingsOptions[1] = "Theme: " + theme.name;
+}
+
+void UI::run() {
+    auto lastTime = std::chrono::high_resolution_clock::now();
+    
+    while (currentState != UIState::EXIT_CONFIRM) {
+        // Calculate delta time
+        auto currentTime = std::chrono::high_resolution_clock::now();
+        std::chrono::duration<float> duration = currentTime - lastTime;
+        float deltaTime = duration.count();
+        lastTime = currentTime;
+        
+        // Update background effect timer
+        backgroundEffectTimer += deltaTime;
+        
+        // Update game mode
+        if (currentState == UIState::GAME_PLAYING && gameMode) {
+            gameMode->update(game, deltaTime);
+        }
+        
+        // Draw UI based on current state
+        switch (currentState) {
+            case UIState::MAIN_MENU:
+                drawMainMenu();
+                handleMainMenuInput();
+                break;
+                
+            case UIState::MODE_SELECTION:
+                drawModeSelection();
+                handleModeSelectionInput();
+                break;
+                
+            case UIState::GAME_PLAYING:
+                drawBoard();
+                drawScore();
+                drawInfo();
+                handleGameInput();
+                break;
+                
+            case UIState::PAUSE_MENU:
+                drawBoard(); // Draw board in background
+                drawPauseMenu();
+                handlePauseMenuInput();
+                break;
+                
+            case UIState::GAME_OVER:
+                drawBoard(); // Draw board in background
+                drawGameOver();
+                handlePauseMenuInput(); // Reusing pause menu input handler
+                break;
+                
+            case UIState::VICTORY:
+                drawBoard(); // Draw board in background
+                drawVictory();
+                handlePauseMenuInput(); // Reusing pause menu input handler
+                break;
+                
+            case UIState::TUTORIAL:
+                drawTutorial();
+                handleTutorialInput();
+                break;
+                
+            case UIState::SETTINGS:
+                drawSettings();
+                handleSettingsInput();
+                break;
+                
+            case UIState::EXIT_CONFIRM:
+                drawExitConfirm();
+                handleExitConfirmInput();
+                break;
+        }
+        
+        // Limit frame rate to reduce CPU usage
+        std::this_thread::sleep_for(std::chrono::milliseconds(50)); // ~20 FPS
+    }
+}
+
+void UI::setState(UIState newState) {
+    previousState = currentState;
+    currentState = newState;
+    selectedMenuOption = 0;
+}
+
+UIState UI::getState() const {
+    return currentState;
+}
+
+void UI::setGameMode(GameModeType mode) {
+    currentGameMode = mode;
+    
+    // Create appropriate game mode instance - C++11 compatible version
+    switch (mode) {
+        case GameModeType::CLASSIC:
+            gameMode.reset(new ClassicMode());
+            break;
+        default:
+            gameMode.reset(new ClassicMode());
+            break;
+    }
+    
+    // Initialize the game mode
+    if (gameMode) {
+        gameMode->initialize(game);
+    }
+}
+
+GameModeType UI::getGameMode() const {
+    return currentGameMode;
+}
+
+void UI::setTheme(int themeIndex) {
+    applyTheme(themeIndex);
+}
+
+int UI::getThemeCount() const {
+    return static_cast<int>(themes.size());
+}
+
+std::string UI::getThemeName(int index) const {
+    if (index >= 0 && index < static_cast<int>(themes.size())) {
+        return themes[index].name;
+    }
+    return "Unknown";
+}
+
+void UI::toggleAnimations() {
+    animationsEnabled = !animationsEnabled;
+    settingsOptions[0] = std::string("Animations: ") + (animationsEnabled ? "ON" : "OFF");
+}
+
+// Drawing helpers
+void UI::drawCenteredText(WINDOW* win, int y, const std::string& text, bool highlight) {
+    int maxX = getmaxx(win);
+    
+    int x = (maxX - text.length()) / 2;
+    
+    if (highlight) wattron(win, A_REVERSE);
+    mvwprintw(win, y, x, "%s", text.c_str());
+    if (highlight) wattroff(win, A_REVERSE);
+}
+
+void UI::drawBorderedWindow(WINDOW* win, const std::string& title) {
+    int maxX = getmaxx(win);
+    
+    // Draw the border
+    box(win, 0, 0);
+    
+    // Draw the title if provided
+    if (!title.empty()) {
+        int titleX = (maxX - title.length()) / 2;
+        wattron(win, A_BOLD);
+        mvwprintw(win, 0, titleX, " %s ", title.c_str());
+        wattroff(win, A_BOLD);
+    }
+}
+
+void UI::drawTile(WINDOW* win, int row, int col, int value) {
+    int colorPair;
+    switch (value) {
+        case 0: colorPair = 1; break;   // Empty tile
+        case 2: colorPair = 2; break;
+        case 4: colorPair = 3; break;
+        case 8: colorPair = 4; break;
+        case 16: colorPair = 5; break;
+        case 32: colorPair = 6; break;
+        case 64: colorPair = 7; break;
+        case 128: colorPair = 8; break;
+        case 256: colorPair = 9; break;
+        case 512: colorPair = 10; break;
+        case 1024: colorPair = 11; break;
+        case 2048: colorPair = 12; break;
+        default: colorPair = 13; break; // Higher values
+    }
+    
+    // Draw the tile with color if not empty
+    wattron(win, COLOR_PAIR(colorPair) | A_BOLD);
+    mvwprintw(win, row + 1, col * 6 + 1, "%5d", value == 0 ? 0 : value);
+    wattroff(win, COLOR_PAIR(colorPair) | A_BOLD);
+}
+
+// Menu drawing functions
+void UI::drawMainMenu() {
+    werase(mainWindow);
+    
+    int maxY, maxX;
+    getmaxyx(mainWindow, maxY, maxX);
+    
+    // Draw title
+    wattron(mainWindow, COLOR_PAIR(14) | A_BOLD);
+    drawCenteredText(mainWindow, maxY / 4, "2048 GAME", false);
+    wattroff(mainWindow, COLOR_PAIR(14) | A_BOLD);
+    
+    // Menu options
+    for (size_t i = 0; i < mainMenuOptions.size(); i++) {
+        int y = maxY / 3 + i * 2 + 5;
+        
+        if (static_cast<int>(i) == selectedMenuOption) {
+            wattron(mainWindow, A_REVERSE | A_BOLD);
+            drawCenteredText(mainWindow, y, mainMenuOptions[i], true);
+            wattroff(mainWindow, A_REVERSE | A_BOLD);
+        } else {
+            drawCenteredText(mainWindow, y, mainMenuOptions[i], false);
+        }
+    }
+    
+    // Footer
+    wattron(mainWindow, A_DIM);
+    drawCenteredText(mainWindow, maxY - 2, "Use UP/DOWN to navigate, ENTER to select", false);
+    wattroff(mainWindow, A_DIM);
+    
+    wrefresh(mainWindow);
+}
+
+void UI::drawModeSelection() {
+    werase(mainWindow);
+    
+    int maxY, maxX;
+    getmaxyx(mainWindow, maxY, maxX);
+    
+    // Title
+    wattron(mainWindow, COLOR_PAIR(14) | A_BOLD);
+    drawCenteredText(mainWindow, maxY / 4, "SELECT GAME MODE", false);
+    wattroff(mainWindow, COLOR_PAIR(14) | A_BOLD);
+    
+    // Mode options
+    for (size_t i = 0; i < modeSelectionOptions.size(); i++) {
+        int y = maxY / 3 + i * 2 + 2;
+        
+        if (static_cast<int>(i) == selectedMenuOption) {
+            wattron(mainWindow, A_REVERSE | A_BOLD);
+            drawCenteredText(mainWindow, y, modeSelectionOptions[i], true);
+            wattroff(mainWindow, A_REVERSE | A_BOLD);
+        } else {
+            drawCenteredText(mainWindow, y, modeSelectionOptions[i], false);
+        }
+    }
+    
+    // Navigation help
+    wattron(mainWindow, A_DIM);
+    drawCenteredText(mainWindow, maxY - 2, "Use UP/DOWN to navigate, ENTER to select", false);
+    wattroff(mainWindow, A_DIM);
+    
+    wrefresh(mainWindow);
+}
+
+void UI::drawPauseMenu() {
+    // Draw a box in the center of the screen
+    int maxY, maxX;
+    getmaxyx(mainWindow, maxY, maxX);
+    
+    int boxHeight = 6 + static_cast<int>(pauseMenuOptions.size()) * 2;
+    int boxWidth = 30;
+    int boxY = (maxY - boxHeight) / 2;
+    int boxX = (maxX - boxWidth) / 2;
+    
+    // Draw the box
+    for (int y = boxY; y < boxY + boxHeight; y++) {
+        for (int x = boxX; x < boxX + boxWidth; x++) {
+            if (y == boxY || y == boxY + boxHeight - 1 || x == boxX || x == boxX + boxWidth - 1) {
+                mvwaddch(mainWindow, y, x, ACS_BLOCK);
+            } else {
+                mvwaddch(mainWindow, y, x, ' ');
+            }
+        }
+    }
+    
+    // Title
+    wattron(mainWindow, A_BOLD);
+    mvwprintw(mainWindow, boxY + 2, boxX + (boxWidth - 6) / 2, "PAUSED");
+    wattroff(mainWindow, A_BOLD);
+    
+    // Menu options
+    for (size_t i = 0; i < pauseMenuOptions.size(); i++) {
+        if (static_cast<int>(i) == selectedMenuOption) {
+            wattron(mainWindow, A_REVERSE | A_BOLD);
+            mvwprintw(mainWindow, boxY + 4 + static_cast<int>(i) * 2, 
+                     boxX + (boxWidth - static_cast<int>(pauseMenuOptions[i].length())) / 2, 
+                     "%s", pauseMenuOptions[i].c_str());
+            wattroff(mainWindow, A_REVERSE | A_BOLD);
+        } else {
+            mvwprintw(mainWindow, boxY + 4 + static_cast<int>(i) * 2, 
+                     boxX + (boxWidth - static_cast<int>(pauseMenuOptions[i].length())) / 2, 
+                     "%s", pauseMenuOptions[i].c_str());
+        }
+    }
+    
+    wrefresh(mainWindow);
+}
+
+void UI::drawSettings() {
+    werase(mainWindow);
+    
+    int maxY, maxX;
+    getmaxyx(mainWindow, maxY, maxX);
+    
+    // Title
+    wattron(mainWindow, COLOR_PAIR(15) | A_BOLD);
+    drawCenteredText(mainWindow, maxY / 4, "SETTINGS", false);
+    wattroff(mainWindow, COLOR_PAIR(15) | A_BOLD);
+    
+    // Settings options
+    for (size_t i = 0; i < settingsOptions.size(); i++) {
+        int y = maxY / 3 + static_cast<int>(i) * 2 + 2;
+        
+        if (static_cast<int>(i) == selectedMenuOption) {
+            wattron(mainWindow, A_REVERSE | A_BOLD);
+            drawCenteredText(mainWindow, y, settingsOptions[i], true);
+            wattroff(mainWindow, A_REVERSE | A_BOLD);
+        } else {
+            drawCenteredText(mainWindow, y, settingsOptions[i], false);
+        }
+    }
+    
+    // Navigation help
+    wattron(mainWindow, A_DIM);
+    drawCenteredText(mainWindow, maxY - 2, "Use UP/DOWN to navigate, ENTER to toggle, ESC to return", false);
+    wattroff(mainWindow, A_DIM);
+    
+    wrefresh(mainWindow);
+}
+
+void UI::drawTutorial() {
+    werase(mainWindow);
+    
+    int maxY, maxX;
+    getmaxyx(mainWindow, maxY, maxX);
+    
+    // Title
+    wattron(mainWindow, A_BOLD);
+    drawCenteredText(mainWindow, 2, "TUTORIAL", false);
+    wattroff(mainWindow, A_BOLD);
+    
+    // Tutorial content
+    std::vector<std::string> tutorial = {
+        "Welcome to 2048!",
+        "",
+        "How to play:",
+        "1. Use arrow keys to move all tiles in one direction",
+        "2. When two tiles with the same number touch, they merge into one!",
+        "3. After each move, a new tile appears (either 2 or 4)",
+        "4. The goal is to create a tile with the value 2048",
+        "",
+        "Tips:",
+        "- Keep your highest value tile in a corner",
+        "- Try to maintain a clear path to that corner",
+        "- Plan ahead and think about what will happen after each move"
+    };
+    
+    for (size_t i = 0; i < tutorial.size(); i++) {
+        if (tutorial[i].empty()) {
+            continue;
+        } else if (i > 0 && tutorial[i-1].empty()) {
+            // Section header
+            wattron(mainWindow, A_BOLD);
+            mvwprintw(mainWindow, 5 + static_cast<int>(i), 5, "%s", tutorial[i].c_str());
+            wattroff(mainWindow, A_BOLD);
+        } else {
+            mvwprintw(mainWindow, 5 + static_cast<int>(i), 5, "%s", tutorial[i].c_str());
+        }
+    }
+    
+    // Navigation help
+    wattron(mainWindow, A_DIM);
+    drawCenteredText(mainWindow, maxY - 2, "Press any key to return to main menu", false);
+    wattroff(mainWindow, A_DIM);
+    
+    wrefresh(mainWindow);
+}
+
+void UI::drawExitConfirm() {
+    // Draw a box in the center of the screen
+    int maxY, maxX;
+    getmaxyx(mainWindow, maxY, maxX);
+    
+    int boxHeight = 7;
+    int boxWidth = 40;
+    int boxY = (maxY - boxHeight) / 2;
+    int boxX = (maxX - boxWidth) / 2;
+    
+    // Draw the box
+    for (int y = boxY; y < boxY + boxHeight; y++) {
+        for (int x = boxX; x < boxX + boxWidth; x++) {
+            if (y == boxY || y == boxY + boxHeight - 1 || x == boxX || x == boxX + boxWidth - 1) {
+                mvwaddch(mainWindow, y, x, ACS_BLOCK);
+            } else {
+                mvwaddch(mainWindow, y, x, ' ');
+            }
+        }
+    }
+    
+    // Question
+    wattron(mainWindow, A_BOLD);
+    mvwprintw(mainWindow, boxY + 2, boxX + (boxWidth - 29) / 2, "Are you sure you want to quit?");
+    wattroff(mainWindow, A_BOLD);
+    
+    // Options
+    std::string yes = "Yes";
+    std::string no = "No";
+    
+    // Highlight selected option
+    if (selectedMenuOption == 0) {
+        wattron(mainWindow, A_REVERSE | A_BOLD);
+        mvwprintw(mainWindow, boxY + 4, boxX + boxWidth / 3 - 2, "%s", yes.c_str());
+        wattroff(mainWindow, A_REVERSE | A_BOLD);
+        
+        mvwprintw(mainWindow, boxY + 4, boxX + 2 * boxWidth / 3 - 2, "%s", no.c_str());
+    } else {
+        mvwprintw(mainWindow, boxY + 4, boxX + boxWidth / 3 - 2, "%s", yes.c_str());
+        
+        wattron(mainWindow, A_REVERSE | A_BOLD);
+        mvwprintw(mainWindow, boxY + 4, boxX + 2 * boxWidth / 3 - 2, "%s", no.c_str());
+        wattroff(mainWindow, A_REVERSE | A_BOLD);
+    }
+    
+    wrefresh(mainWindow);
+}
+
+void UI::drawGameOver() {
+    int maxY, maxX;
+    getmaxyx(mainWindow, maxY, maxX);
+    
+    // Display game over overlay
+    int boxHeight = 7;
+    int boxWidth = 30;
+    int boxY = (maxY - boxHeight) / 2;
+    int boxX = (maxX - boxWidth) / 2;
+    
+    // Draw box
+    for (int y = boxY; y < boxY + boxHeight; y++) {
+        for (int x = boxX; x < boxX + boxWidth; x++) {
+            if (y == boxY || y == boxY + boxHeight - 1 || 
+                x == boxX || x == boxX + boxWidth - 1) {
+                mvwaddch(mainWindow, y, x, ACS_BLOCK);
+            } else {
+                mvwaddch(mainWindow, y, x, ' ');
+            }
+        }
+    }
+    
+    // Draw game over message
+    wattron(mainWindow, COLOR_PAIR(13) | A_BOLD);
+    mvwprintw(mainWindow, boxY + 2, boxX + (boxWidth - 9) / 2, "GAME OVER");
+    wattroff(mainWindow, COLOR_PAIR(13) | A_BOLD);
+    
+    // Draw final score
+    wattron(mainWindow, A_BOLD);
+    std::string scoreText = "Final Score: " + std::to_string(game.getScore());
+    mvwprintw(mainWindow, boxY + 4, boxX + (boxWidth - static_cast<int>(scoreText.length())) / 2, 
+             "%s", scoreText.c_str());
+    wattroff(mainWindow, A_BOLD);
+    
+    // Instruction to continue
+    wattron(mainWindow, A_DIM);
+    mvwprintw(mainWindow, boxY + 6, boxX + 2, "Press any key to continue");
+    wattroff(mainWindow, A_DIM);
+    
+    wrefresh(mainWindow);
+}
+
+void UI::drawVictory() {
+    int maxY, maxX;
+    getmaxyx(mainWindow, maxY, maxX);
+    
+    // Display victory overlay
+    int boxHeight = 9;
+    int boxWidth = 40;
+    int boxY = (maxY - boxHeight) / 2;
+    int boxX = (maxX - boxWidth) / 2;
+    
+    // Draw box
+    for (int y = boxY; y < boxY + boxHeight; y++) {
+        for (int x = boxX; x < boxX + boxWidth; x++) {
+            if (y == boxY || y == boxY + boxHeight - 1 || 
+                x == boxX || x == boxX + boxWidth - 1) {
+                mvwaddch(mainWindow, y, x, ACS_BLOCK);
+            } else {
+                mvwaddch(mainWindow, y, x, ' ');
+            }
+        }
+    }
+    
+    // Victory message
+    wattron(mainWindow, COLOR_PAIR(12) | A_BOLD);
+    mvwprintw(mainWindow, boxY + 2, boxX + (boxWidth - 18) / 2, "VICTORY! YOU WIN!");
+    wattroff(mainWindow, COLOR_PAIR(12) | A_BOLD);
+    
+    // Congratulatory message
+    wattron(mainWindow, A_NORMAL);
+    mvwprintw(mainWindow, boxY + 4, boxX + 2, "Congratulations! You've reached 2048!");
+    wattroff(mainWindow, A_NORMAL);
+    
+    // Draw final score
+    wattron(mainWindow, A_BOLD);
+    std::string scoreText = "Final Score: " + std::to_string(game.getScore());
+    mvwprintw(mainWindow, boxY + 6, boxX + (boxWidth - static_cast<int>(scoreText.length())) / 2, 
+             "%s", scoreText.c_str());
+    wattroff(mainWindow, A_BOLD);
+    
+    // Instruction to continue
+    wattron(mainWindow, A_DIM);
+    mvwprintw(mainWindow, boxY + 8, boxX + 2, "Press any key to continue");
+    wattroff(mainWindow, A_DIM);
+    
+    wrefresh(mainWindow);
+}
+
+void UI::drawBoard() {
+    werase(gameWindow);
+    
+    // Draw border
+    drawBorderedWindow(gameWindow, "2048");
+    
+    // Display the board
+    const auto& board = game.getBoard();
+    for (int i = 0; i < SIZE; ++i) {
+        for (int j = 0; j < SIZE; ++j) {
+            int value = board[i][j].getValue();
+            drawTile(gameWindow, i, j, value);
+        }
+    }
+    
+    wrefresh(gameWindow);
+}
+
+void UI::drawScore() {
+    werase(scoreWindow);
+    
+    // Draw border
+    drawBorderedWindow(scoreWindow, "Score");
+    
+    // Current score
+    wattron(scoreWindow, A_BOLD);
+    mvwprintw(scoreWindow, 1, 2, "%d", game.getScore());
+    wattroff(scoreWindow, A_BOLD);
+    
+    // High score
+    wattron(scoreWindow, A_NORMAL);
+    mvwprintw(scoreWindow, 2, 2, "Best: %d", game.getHighScore());
+    wattroff(scoreWindow, A_NORMAL);
+    
+    wrefresh(scoreWindow);
+}
+
+void UI::drawInfo() {
+    werase(infoWindow);
+    
+    // Draw border
+    drawBorderedWindow(infoWindow, "Info");
+    
+    // Add controls info
+    wattron(infoWindow, A_BOLD);
+    mvwprintw(infoWindow, 1, 2, "Controls:");
+    wattroff(infoWindow, A_BOLD);
+    mvwprintw(infoWindow, 1, 12, "Arrow keys to move");
+    
+    mvwprintw(infoWindow, 2, 2, "P: Pause  R: Restart  Q: Quit");
+    
+    // Game goal
+    wattron(infoWindow, A_BOLD);
+    mvwprintw(infoWindow, 3, 2, "Goal: Reach the 2048 tile!");
+    wattroff(infoWindow, A_BOLD);
+    
+    wrefresh(infoWindow);
+}
+
+// Event handlers for menu input
+void UI::handleMainMenuInput() {
+    int key = wgetch(mainWindow);
+    if (key == ERR) return;
+    
+    switch (key) {
+        case KEY_UP:
+            if (selectedMenuOption > 0) {
+                selectedMenuOption--;
+            }
+            break;
+            
+        case KEY_DOWN:
+            if (selectedMenuOption < static_cast<int>(mainMenuOptions.size()) - 1) {
+                selectedMenuOption++;
+            }
+            break;
+            
+        case '\n': // Enter key
+        case ' ':  // Space key
+            switch (selectedMenuOption) {
+                case 0: // Play Game
+                    setState(UIState::GAME_PLAYING);
+                    break;
+                    
+                case 1: // Select Mode
+                    setState(UIState::MODE_SELECTION);
+                    break;
+                    
+                case 2: // Settings
+                    setState(UIState::SETTINGS);
+                    break;
+                    
+                case 3: // Tutorial
+                    setState(UIState::TUTORIAL);
+                    break;
+                    
+                case 4: // Quit
+                    setState(UIState::EXIT_CONFIRM);
+                    break;
+            }
+            break;
+            
+        case 'q':
+        case 'Q':
+            setState(UIState::EXIT_CONFIRM);
+            break;
+    }
+}
+
+void UI::handleModeSelectionInput() {
+    int key = wgetch(mainWindow);
+    if (key == ERR) return;
+    
+    switch (key) {
+        case KEY_UP:
+            if (selectedMenuOption > 0) {
+                selectedMenuOption--;
+            }
+            break;
+            
+        case KEY_DOWN:
+            if (selectedMenuOption < static_cast<int>(modeSelectionOptions.size()) - 1) {
+                selectedMenuOption++;
+            }
+            break;
+            
+        case '\n': // Enter key
+        case ' ':  // Space key
+            if (selectedMenuOption == static_cast<int>(modeSelectionOptions.size()) - 1) {
+                // Back option
+                setState(UIState::MAIN_MENU);
+            } else {
+                // Set game mode and start game
+                GameModeType mode;
+                switch (selectedMenuOption) {
+                    case 0: mode = GameModeType::CLASSIC; break;
+                    default: mode = GameModeType::CLASSIC; break;
+                }
+                
+                setGameMode(mode);
+                setState(UIState::GAME_PLAYING);
+            }
+            break;
+            
+        case 27: // ESC key
+            setState(UIState::MAIN_MENU);
+            break;
+    }
+}
+
+void UI::handleGameInput() {
+    int key = wgetch(mainWindow);
+    if (key == ERR) return;
+    
+    switch (key) {
+        case KEY_LEFT:
+        case KEY_RIGHT:
+        case KEY_UP:
+        case KEY_DOWN:
+            // Pass to game mode for handling
+            if (gameMode) {
+                gameMode->handleInput(game, key);
+            }
+            break;
+            
+        case 'p':
+        case 'P':
+            setState(UIState::PAUSE_MENU);
+            break;
+            
+        case 'r':
+        case 'R':
+            if (gameMode) {
+                gameMode->initialize(game);
+            }
+            break;
+            
+        case 'q':
+        case 'Q':
+        case 27: // ESC key
+            setState(UIState::PAUSE_MENU);
+            break;
+    }
+}
+
+void UI::handlePauseMenuInput() {
+    int key = wgetch(mainWindow);
+    if (key == ERR) return;
+    
+    switch (key) {
+        case KEY_UP:
+            if (selectedMenuOption > 0) {
+                selectedMenuOption--;
+            }
+            break;
+            
+        case KEY_DOWN:
+            if (selectedMenuOption < static_cast<int>(pauseMenuOptions.size()) - 1) {
+                selectedMenuOption++;
+            }
+            break;
+            
+        case '\n': // Enter key
+        case ' ':  // Space key
+            switch (selectedMenuOption) {
+                case 0: // Resume
+                    setState(UIState::GAME_PLAYING);
+                    break;
+                    
+                case 1: // Restart
+                    if (gameMode) {
+                        gameMode->initialize(game);
+                    }
+                    setState(UIState::GAME_PLAYING);
+                    break;
+                    
+                case 2: // Main Menu
+                    setState(UIState::MAIN_MENU);
+                    break;
+                    
+                case 3: // Quit
+                    setState(UIState::EXIT_CONFIRM);
+                    break;
+            }
+            break;
+            
+        case 'p':
+        case 'P':
+        case 27: // ESC key
+            // Resume game
+            setState(UIState::GAME_PLAYING);
+            break;
+    }
+}
+
+void UI::handleSettingsInput() {
+    int key = wgetch(mainWindow);
+    if (key == ERR) return;
+    
+    switch (key) {
+        case KEY_UP:
+            if (selectedMenuOption > 0) {
+                selectedMenuOption--;
+            }
+            break;
+            
+        case KEY_DOWN:
+            if (selectedMenuOption < static_cast<int>(settingsOptions.size()) - 1) {
+                selectedMenuOption++;
+            }
+            break;
+            
+        case '\n': // Enter key
+        case ' ':  // Space key
+            switch (selectedMenuOption) {
+                case 0: // Animations toggle
+                    toggleAnimations();
+                    break;
+                    
+                case 1: // Theme selection
+                    // Cycle through themes
+                    setTheme((currentTheme + 1) % static_cast<int>(themes.size()));
+                    break;
+                    
+                case 2: // Back
+                    setState(previousState);
+                    break;
+            }
+            break;
+            
+        case 27: // ESC key
+            setState(previousState);
+            break;
+    }
+}
+
+void UI::handleTutorialInput() {
+    int key = wgetch(mainWindow);
+    if (key == ERR) return;
+    
+    // Any key returns to main menu
+    setState(UIState::MAIN_MENU);
+}
+
+void UI::handleExitConfirmInput() {
+    int key = wgetch(mainWindow);
+    if (key == ERR) return;
+    
+    switch (key) {
+        case KEY_LEFT:
+            selectedMenuOption = 0; // Yes
+            break;
+            
+        case KEY_RIGHT:
+            selectedMenuOption = 1; // No
+            break;
+            
+        case '\n': // Enter key
+        case ' ':  // Space key
+            if (selectedMenuOption == 0) {
+                // Yes - exit the game
+                endwin();
+                exit(0);
+            } else {
+                // No - return to previous state
+                setState(previousState);
+            }
+            break;
+            
+        case 27: // ESC key
+            setState(previousState);
+            break;
+    }
+}
+
+// Game event callbacks
+void UI::onTileMerged(int row, int col, int value) {
+    // Simplified implementation - no animation
+}
+
+void UI::onTileSpawned(int row, int col, int value) {
+    // Simplified implementation - no animation
+}
+
+void UI::onScoreChanged(int newScore, int prevScore) {
+    // Simplified implementation - no animation
+}
+
+void UI::onGameOver() {
+    setState(UIState::GAME_OVER);
+}
+
+void UI::onVictory() {
+    setState(UIState::VICTORY);
+}
+-main.cpp
+#include "UI.hpp"
+#include "Extra.hpp"
+#include <iostream>
+
+int main() {
+    try {
+        // Initialize the game
+        initializeGame();
+        
+        // Create and initialize UI
+        UI ui;
+        if (!ui.initialize()) {
+            cleanupGame();
+            std::cerr << "Failed to initialize UI" << std::endl;
+            return 1;
+        }
+        
+        // Run the game
+        ui.run();
+        
+        // Clean up
+        cleanupGame();
+        
+        return 0;
+    } catch (const std::exception& e) {
+        // Clean up ncurses in case of exception
+        endwin();
+        std::cerr << "Error: " << e.what() << std::endl;
+        return 1;
+    }
+}
+-extra.hpp
+#ifndef EXTRA_HPP
+#define EXTRA_HPP
+
+#include <ncurses.h>
+
+// Initialize the game
+void initializeGame();
+
+// Clean up the game
+void cleanupGame();
+
+// Initialize colors
+void initColors();
+
+// Get color pair for a tile value
+int getTileColorPair(int value);
+
+#endif // EXTRA_HPP
+-extra.cpp
+#include "Extra.hpp"
+#include <ncurses.h>
+
+void initializeGame() {
+    initscr();
+    noecho();
+    keypad(stdscr, TRUE);
+    curs_set(0);
+    
+    // Initialize colors
+    if(has_colors()) {
+        start_color();
+        initColors();
+    }
+}
+
+void initColors() {
+    // Initialize color pairs
+    init_pair(1, COLOR_BLACK, COLOR_WHITE);      // Default
+    init_pair(2, COLOR_BLACK, COLOR_GREEN);      // 2
+    init_pair(3, COLOR_BLACK, COLOR_CYAN);       // 4
+    init_pair(4, COLOR_BLACK, COLOR_BLUE);       // 8
+    init_pair(5, COLOR_BLACK, COLOR_MAGENTA);    // 16
+    init_pair(6, COLOR_BLACK, COLOR_RED);        // 32
+    init_pair(7, COLOR_WHITE, COLOR_BLUE);       // 64
+    init_pair(8, COLOR_WHITE, COLOR_MAGENTA);    // 128
+    init_pair(9, COLOR_WHITE, COLOR_RED);        // 256
+    init_pair(10, COLOR_WHITE, COLOR_YELLOW);    // 512
+    init_pair(11, COLOR_BLACK, COLOR_YELLOW);    // 1024
+    init_pair(12, COLOR_WHITE, COLOR_GREEN);     // 2048
+    init_pair(13, COLOR_WHITE, COLOR_RED);       // Higher
+    init_pair(14, COLOR_YELLOW, COLOR_BLACK);    // Gold text
+    init_pair(15, COLOR_CYAN, COLOR_BLACK);      // Cyan text
+}
+
+int getTileColorPair(int value) {
+    switch(value) {
+        case 0: return 1;     // Default
+        case 2: return 2;     // 2
+        case 4: return 3;     // 4
+        case 8: return 4;     // 8
+        case 16: return 5;    // 16
+        case 32: return 6;    // 32
+        case 64: return 7;    // 64
+        case 128: return 8;   // 128
+        case 256: return 9;   // 256
+        case 512: return 10;  // 512
+        case 1024: return 11; // 1024
+        case 2048: return 12; // 2048
+        default: return 13;   // Higher values
+    }
+}
+
+void cleanupGame() {
+    endwin();
+}
+-makefile
+CC = g++
+CFLAGS = -std=c++11 -Wall -I include
+LDFLAGS = -lncurses
+
+# Directories
+SRCDIR = src
+INCDIR = include
+OBJDIR = obj
+BINDIR = bin
+
+# Create directories if they don't exist
+$(shell mkdir -p $(OBJDIR) $(BINDIR))
+
+# Source files and object files
+SOURCES = $(wildcard $(SRCDIR)/*.cpp)
+OBJECTS = $(patsubst $(SRCDIR)/%.cpp,$(OBJDIR)/%.o,$(SOURCES))
+EXECUTABLE = $(BINDIR)/2048
+
+# Main target
+all: directories $(EXECUTABLE)
+
+# Create necessary directories
+directories:
+	mkdir -p $(OBJDIR) $(BINDIR)
+
+# Link the executable
+$(EXECUTABLE): $(OBJECTS)
+	$(CC) $(OBJECTS) -o $@ $(LDFLAGS)
+	@echo "Build successful! Run with: $(EXECUTABLE)"
+
+# Compile object files
+$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
+	$(CC) $(CFLAGS) -c $< -o $@
+
+# Clean build files
+clean:
+	rm -rf $(OBJDIR)/*.o $(EXECUTABLE)
+
+# Run the executable
+run: all
+	$(EXECUTABLE)
+
+.PHONY: all directories clean run
+-2048.hpp
+// 2048.hpp
+#ifndef GAME2048_HPP
+#define GAME2048_HPP
+
+#include <vector>
+#include <array>
+#include <functional>
+#include "Tile.hpp"
+
+#define SIZE 4
+
+// Event types for observers
+enum class GameEvent {
+    TILE_MOVED,
+    TILE_MERGED,
+    TILE_SPAWNED,
+    SCORE_CHANGED,
+    GAME_WON,
+    GAME_OVER
+};
+
+// Game state observer pattern
+using GameEventCallback = std::function<void(GameEvent, int, int, int)>;
+
+class Game2048 {
+private:
+    std::array<std::array<Tile, SIZE>, SIZE> board;
+    std::array<std::array<Tile, SIZE>, SIZE> previousBoard;
+    bool moved;
+    int score;
+    int previousScore;
+    int highScore;
+    std::vector<GameEventCallback> observers;
+
+    void spawnTile();
+    void addToScore(int value);
+    void notifyObservers(GameEvent event, int row = -1, int col = -1, int value = 0);
+    void notifyObservers(GameEvent event, int fromRow, int fromCol, int toRow, int toCol, int value);
+    void saveBoardState();
+
+public:
+    Game2048();
+    void resetBoard();
+    
+    // Movement methods
+    void moveLeft();
+    void moveRight();
+    void moveUp();
+    void moveDown();
+    
+    // Game state methods
+    bool canMove() const;
+    bool hasWon() const;
+    int getScore() const;
+    int getHighScore() const;
+    void undoMove();
+    
+    // Special actions for power-ups
+    void clearRow(int row);
+    void clearColumn(int col);
+    void doubleScoreTile(int row, int col);
+    void upgradeTile(int row, int col);
+    
+    // Board access
+    const std::array<std::array<Tile, SIZE>, SIZE>& getBoard() const;
+    
+    // Observer pattern methods
+    void addObserver(GameEventCallback callback);
+    void removeAllObservers();
+};
+
+#endif // GAME2048_HPP
+
+// Tile.hpp
+#ifndef TILE_HPP
+#define TILE_HPP
+
+class Tile {
+private:
+    int value;
+    bool mergedThisTurn;
+    bool isNew;
+    float animationProgress;
+    
+public:
+    Tile();
+    
+    // Basic operations
+    void setValue(int val);
+    int getValue() const;
+    void setMerged(bool merged);
+    bool getMerged() const;
+    void setNew(bool newTile);
+    bool getNew() const;
+    
+    // Animation management
+    void setAnimationProgress(float progress);
+    float getAnimationProgress() const;
+    void resetAnimation();
+    
+    // Operators
+    bool operator==(const Tile& other) const;
+    Tile& operator*=(int multiplier);
+    Tile& operator=(const Tile& other);
+};
+
+#endif // TILE_HPP
+
+// GameMode.hpp
+#ifndef GAMEMODE_HPP
+#define GAMEMODE_HPP
+
+#include <string>
+#include <ncurses.h> // For KEY_ constants
+#include "2048.hpp"
+
+enum class GameModeType {
+    CLASSIC,
+    TIMED,
+    POWERUP,
+    CHALLENGE,
+    ZEN,
+    TUTORIAL
+};
+
+// Base abstract class for all game modes
+class GameMode {
+protected:
+    GameModeType type;
+    std::string name;
+    std::string description;
+    bool gameOver;
+    bool gameWon;
+
+public:
+    GameMode(GameModeType type, const std::string& name, const std::string& description);
+    virtual ~GameMode() = default;
+    
+    // Pure virtual methods that derived classes must implement
+    virtual void initialize(Game2048& game) = 0;
+    virtual bool update(Game2048& game, float deltaTime) = 0;
+    virtual void handleInput(Game2048& game, int key) = 0;
+    virtual void render() = 0;
+    
+    // Common methods for all modes
+    GameModeType getType() const;
+    const std::string& getName() const;
+    const std::string& getDescription() const;
+    bool isGameOver() const;
+    bool isGameWon() const;
+    virtual void setGameOver(bool over);
+    virtual void setGameWon(bool won);
+};
+
+// Classic mode - original 2048 gameplay
+class ClassicMode : public GameMode {
+public:
+    ClassicMode();
+    void initialize(Game2048& game) override;
+    bool update(Game2048& game, float deltaTime) override;
+    void handleInput(Game2048& game, int key) override;
+    void render() override;
+};
+
+#endif // GAMEMODE_HPP
+
+// UI.hpp
+#ifndef UI_HPP
+#define UI_HPP
+
+#include <ncurses.h>
+#include <vector>
+#include <string>
+#include <memory>
+#include "2048.hpp"
+#include "GameMode.hpp"
+
+// UI states
+enum class UIState {
+    MAIN_MENU,
+    MODE_SELECTION,
+    GAME_PLAYING,
+    PAUSE_MENU,
+    GAME_OVER,
+    VICTORY,
+    TUTORIAL,
+    SETTINGS,
+    EXIT_CONFIRM
+};
+
+class UI {
+private:
+    // State management
+    UIState currentState;
+    UIState previousState;
+    int selectedMenuOption;
+    
+    // Menu options
+    std::vector<std::string> mainMenuOptions;
+    std::vector<std::string> modeSelectionOptions;
+    std::vector<std::string> pauseMenuOptions;
+    std::vector<std::string> settingsOptions;
+    
+    // Window management
+    WINDOW* mainWindow;
+    WINDOW* gameWindow;
+    WINDOW* scoreWindow;
+    WINDOW* infoWindow;
+    
+    // Game state
+    Game2048 game;
+    GameModeType currentGameMode;
+    
+    // Mode instances
+    std::unique_ptr<GameMode> gameMode;
+    
+    // Background and color management
+    float backgroundEffectTimer;
+    bool animationsEnabled;
+    
+    // Theme management
+    struct Theme {
+        std::string name;
+    };
+    std::vector<Theme> themes;
+    int currentTheme;
+    
+    // Helper methods
+    void createWindows();
+    void destroyWindows();
+    void initializeThemes();
+    void applyTheme(int themeIndex);
+    
+    // Drawing helpers
+    void drawCenteredText(WINDOW* win, int y, const std::string& text, bool highlight = false);
+    void drawBorderedWindow(WINDOW* win, const std::string& title = "");
+    void drawTile(WINDOW* win, int row, int col, int value);
+    
+    // Event handlers
+    void handleMainMenuInput();
+    void handleModeSelectionInput();
+    void handleGameInput();
+    void handlePauseMenuInput();
+    void handleSettingsInput();
+    void handleTutorialInput();
+    void handleExitConfirmInput();
+    
+    // Menu drawing
+    void drawMainMenu();
+    void drawModeSelection();
+    void drawPauseMenu();
+    void drawSettings();
+    void drawTutorial();
+    void drawExitConfirm();
+    
+    // Game UI
+    void drawBoard();
+    void drawScore();
+    void drawInfo();
+    void drawGameOver();
+    void drawVictory();
+    
+    // Game event callbacks
+    void onTileMerged(int row, int col, int value);
+    void onTileSpawned(int row, int col, int value);
+    void onScoreChanged(int newScore, int prevScore);
+    void onGameOver();
+    void onVictory();
+
+public:
+    UI();
+    ~UI();
+    
+    // Initialization
+    bool initialize();
+    
+    // Main game loop
+    void run();
+    
+    // State management
+    void setState(UIState newState);
+    UIState getState() const;
+    
+    // Game mode management
+    void setGameMode(GameModeType mode);
+    GameModeType getGameMode() const;
+    
+    // Theme management
+    void setTheme(int themeIndex);
+    int getThemeCount() const;
+    std::string getThemeName(int index) const;
+    
+    // Settings
+    void toggleAnimations();
+};
+
+#endif // UI_HPP
 
 ## How to build and Run
 ```bash
 # Build the project
+need to install the dependencies for ncurses with this code **sudo apt-get install libncurses5-dev libncursesw5-dev** then in terminal type 
 make
 
 # Run the game
-- 
GitLab