From 73ae9d13a9d8b8e571dace41e9aec1f0f617974d Mon Sep 17 00:00:00 2001 From: rattatwinko Date: Thu, 8 May 2025 20:25:01 +0200 Subject: [PATCH] initial --- .idea/.gitignore | 8 + .idea/Minesweeper.iml | 2 + .idea/editor.xml | 102 ++ .idea/material_theme_project_new.xml | 10 + .idea/misc.xml | 7 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + CMakeLists.txt | 44 + assets/digital.ttf | Bin 0 -> 42092 bytes src/main.cpp | 1332 ++++++++++++++++++++++++++ 10 files changed, 1519 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/Minesweeper.iml create mode 100644 .idea/editor.xml create mode 100644 .idea/material_theme_project_new.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 CMakeLists.txt create mode 100644 assets/digital.ttf create mode 100644 src/main.cpp diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/Minesweeper.iml b/.idea/Minesweeper.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/Minesweeper.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/editor.xml b/.idea/editor.xml new file mode 100644 index 0000000..e54e87a --- /dev/null +++ b/.idea/editor.xml @@ -0,0 +1,102 @@ + + + + + \ No newline at end of file diff --git a/.idea/material_theme_project_new.xml b/.idea/material_theme_project_new.xml new file mode 100644 index 0000000..e3298aa --- /dev/null +++ b/.idea/material_theme_project_new.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..0b76fe5 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..698598d --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3de07d0 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.15) +project(Minesweeper) + +# Set C++ standard +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Find SFML package +find_package(SFML 2.5 COMPONENTS graphics window system REQUIRED) + +# Create assets directory if it doesn't exist +if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/assets) + file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/assets) +endif() + +# Add executable +add_executable(Minesweeper + src/main.cpp +) + +# Link SFML libraries +target_link_libraries(Minesweeper + sfml-graphics + sfml-window + sfml-system +) + +# Copy assets to build directory (for out-of-source builds) +add_custom_command(TARGET Minesweeper POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_CURRENT_SOURCE_DIR}/assets + $/assets + COMMENT "Copying assets to build directory" +) + +# Install target (optional) +install(TARGETS Minesweeper + RUNTIME DESTINATION bin +) + +# Install assets (optional) +install(DIRECTORY assets/ + DESTINATION share/Minesweeper +) \ No newline at end of file diff --git a/assets/digital.ttf b/assets/digital.ttf new file mode 100644 index 0000000000000000000000000000000000000000..bafc0ca41a22d3700b21ecb136a154d044764865 GIT binary patch literal 42092 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 F{{xYgm^=Ug literal 0 HcmV?d00001 diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..1384e52 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,1332 @@ +// +// Created by rattatwinko on 5/8/25. +// +// +// Created by rattatwinko on 5/8/25. +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Forward declarations for asset creation functions +void createAssets(); +void createHiddenCellTexture(); +void createRevealedCellTexture(); +void createMineTexture(); +void createFlagTexture(); +void createQuestionTexture(); +void createExplodedTexture(); +void createDigitTexture(int digit); +void createGearTexture(); +void createScrollTexture(); +void createSmileyTexture(); +void createSadTexture(); +void createCoolTexture(); +void createDigitalFont(); + +class main { +public: + enum Difficulty { + BEGINNER, + INTERMEDIATE, + EXPERT, + CUSTOM + }; + + enum CellState { + HIDDEN, + REVEALED, + FLAGGED, + QUESTIONED + }; + + struct Cell { + bool isMine; + bool isExploded; + CellState state; + int adjacentMines; + + Cell() : isMine(false), isExploded(false), state(HIDDEN), adjacentMines(0) {} + }; + + main() { + initGame(INTERMEDIATE); // Default to intermediate difficulty + } + + void initGame(Difficulty diff) { + gameOver = false; + victory = false; + firstClick = true; + flagCount = 0; + startTime = 0; + elapsedTime = 0; + timerStarted = false; + + switch (diff) { + case BEGINNER: + width = 9; + height = 9; + mineCount = 10; + break; + case INTERMEDIATE: + width = 16; + height = 16; + mineCount = 40; + break; + case EXPERT: + width = 30; + height = 16; + mineCount = 99; + break; + case CUSTOM: + // Custom values should be set before calling initGame + break; + } + + // Initialize grid + grid.clear(); + grid.resize(height, std::vector(width)); + + // Set window size based on grid dimensions + cellSize = 32; // pixels + boardWidth = width * cellSize; + boardHeight = height * cellSize; + headerHeight = 60; // For the header panel with counters + + // Load textures and setup resources + loadResources(); + } + + void setCustomDifficulty(int w, int h, int mines) { + width = w; + height = h; + mineCount = std::min(mines, w * h - 9); // Ensure there are at least 9 safe cells for first click + initGame(CUSTOM); + } + + void run() { + sf::RenderWindow window(sf::VideoMode(boardWidth, boardHeight + headerHeight), "Minesweeper", sf::Style::Close); + window.setFramerateLimit(60); + + sf::Clock clock; + + while (window.isOpen()) { + sf::Event event; + while (window.pollEvent(event)) { + if (event.type == sf::Event::Closed) { + window.close(); + } + else if (event.type == sf::Event::MouseButtonPressed) { + if (!gameOver && !victory) { + sf::Vector2i mousePos = sf::Mouse::getPosition(window); + int x = mousePos.x / cellSize; + int y = (mousePos.y - headerHeight) / cellSize; + + if (mousePos.y >= headerHeight && x >= 0 && x < width && y >= 0 && y < height) { + if (event.mouseButton.button == sf::Mouse::Left) { + handleLeftClick(x, y); + } + else if (event.mouseButton.button == sf::Mouse::Right) { + handleRightClick(x, y); + } + } + else if (mousePos.y < headerHeight) { + // Check if reset button (smiley face) is clicked + int smileX = boardWidth / 2 - 16; + if (mousePos.x >= smileX && mousePos.x < smileX + 32 && + mousePos.y >= 14 && mousePos.y < 46) { + initGame(INTERMEDIATE); // Reset game with current difficulty + } + + // Check if settings button is clicked + if (mousePos.x >= 8 && mousePos.x < 40 && + mousePos.y >= 14 && mousePos.y < 46) { + showDifficultyMenu(window); + } + + // Check if light bulb button is clicked (hint) + if (mousePos.x >= boardWidth - 40 && mousePos.x < boardWidth - 8 && + mousePos.y >= 14 && mousePos.y < 46) { + provideHint(); + } + } + } + else { + // If game is over, check if reset button is clicked + sf::Vector2i mousePos = sf::Mouse::getPosition(window); + int smileX = boardWidth / 2 - 16; + if (mousePos.y < headerHeight && + mousePos.x >= smileX && mousePos.x < smileX + 32 && + mousePos.y >= 14 && mousePos.y < 46) { + initGame(INTERMEDIATE); // Reset game with current difficulty + } + + // Check if settings button is clicked + if (mousePos.x >= 8 && mousePos.x < 40 && + mousePos.y >= 14 && mousePos.y < 46) { + showDifficultyMenu(window); + } + } + } + } + + // Update timer + if (timerStarted && !gameOver && !victory) { + elapsedTime = static_cast(clock.getElapsedTime().asSeconds() - startTime); + if (elapsedTime > 999) elapsedTime = 999; // Cap at 999 seconds + } + + // Draw everything + window.clear(sf::Color(192, 192, 192)); // Light gray background + drawBoard(window); + drawHeader(window); + window.display(); + } + } + +private: + int width, height; + int mineCount, flagCount; + int cellSize; + int boardWidth, boardHeight, headerHeight; + bool gameOver, victory, firstClick, timerStarted; + int startTime, elapsedTime; + std::vector> grid; + + // Textures and sprites + sf::Texture hiddenTexture, revealedTexture, mineTexture, flagTexture, questionTexture, explodedTexture; + sf::Texture digitTextures[10]; // 0-9 digits + sf::Texture headerTextures[5]; // gear, scroll, smiley, sad, cool, hint/bulb + sf::Font font; + + void loadResources() { + // Cell textures + hiddenTexture.loadFromFile("assets/hidden.png"); + revealedTexture.loadFromFile("assets/revealed.png"); + mineTexture.loadFromFile("assets/mine.png"); + flagTexture.loadFromFile("assets/flag.png"); + questionTexture.loadFromFile("assets/question.png"); + explodedTexture.loadFromFile("assets/exploded.png"); + + // Digit textures for numbers 1-8 on cells + font.loadFromFile("assets/digital.ttf"); + + // Header textures + headerTextures[0].loadFromFile("assets/gear.png"); // Settings + headerTextures[1].loadFromFile("assets/scroll.png"); // Score/mines + headerTextures[2].loadFromFile("assets/smiley.png"); // Normal face + headerTextures[3].loadFromFile("assets/sad.png"); // Sad face (loss) + headerTextures[4].loadFromFile("assets/cool.png"); // Cool face (win) + + // Digit textures (for counters) + for (int i = 0; i < 10; i++) { + std::string filename = "assets/digit" + std::to_string(i) + ".png"; + digitTextures[i].loadFromFile(filename); + } + } + + void placeMines(int firstX, int firstY) { + std::mt19937 rng(static_cast(std::time(nullptr))); + std::uniform_int_distribution distX(0, width - 1); + std::uniform_int_distribution distY(0, height - 1); + + int placedMines = 0; + while (placedMines < mineCount) { + int x = distX(rng); + int y = distY(rng); + + // Ensure first click and surrounding cells are safe + if (std::abs(x - firstX) <= 1 && std::abs(y - firstY) <= 1) { + continue; + } + + if (!grid[y][x].isMine) { + grid[y][x].isMine = true; + placedMines++; + } + } + + // Calculate adjacent mines for each cell + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (!grid[y][x].isMine) { + grid[y][x].adjacentMines = countAdjacentMines(x, y); + } + } + } + } + + int countAdjacentMines(int x, int y) { + int count = 0; + for (int dy = -1; dy <= 1; dy++) { + for (int dx = -1; dx <= 1; dx++) { + int nx = x + dx; + int ny = y + dy; + if (nx >= 0 && nx < width && ny >= 0 && ny < height && grid[ny][nx].isMine) { + count++; + } + } + } + return count; + } + + void revealCell(int x, int y) { + // Make sure we're in bounds + if (x < 0 || x >= width || y < 0 || y >= height) { + return; + } + + Cell& cell = grid[y][x]; + + // Only reveal hidden cells + if (cell.state != HIDDEN) { + return; + } + + // Start timer on first reveal + if (firstClick) { + sf::Clock clock; + startTime = clock.getElapsedTime().asSeconds(); + timerStarted = true; + firstClick = false; + placeMines(x, y); + } + + cell.state = REVEALED; + + // If it's a mine, game over + if (cell.isMine) { + cell.isExploded = true; + revealAllMines(); + gameOver = true; + return; + } + + // If no adjacent mines, reveal adjacent cells + if (cell.adjacentMines == 0) { + for (int dy = -1; dy <= 1; dy++) { + for (int dx = -1; dx <= 1; dx++) { + if (dx == 0 && dy == 0) continue; + revealCell(x + dx, y + dy); + } + } + } + + // Check for victory + checkVictory(); + } + + void handleLeftClick(int x, int y) { + Cell& cell = grid[y][x]; + + if (cell.state == HIDDEN || cell.state == QUESTIONED) { + revealCell(x, y); + } + else if (cell.state == REVEALED && cell.adjacentMines > 0) { + // Check for chord (middle-click behavior) + int flagCount = 0; + for (int dy = -1; dy <= 1; dy++) { + for (int dx = -1; dx <= 1; dx++) { + int nx = x + dx; + int ny = y + dy; + if (nx >= 0 && nx < width && ny >= 0 && ny < height && + grid[ny][nx].state == FLAGGED) { + flagCount++; + } + } + } + + // If flagged neighbors match adjacent mines, reveal all non-flagged neighbors + if (flagCount == cell.adjacentMines) { + for (int dy = -1; dy <= 1; dy++) { + for (int dx = -1; dx <= 1; dx++) { + int nx = x + dx; + int ny = y + dy; + if (nx >= 0 && nx < width && ny >= 0 && ny < height && + grid[ny][nx].state != FLAGGED && grid[ny][nx].state != REVEALED) { + revealCell(nx, ny); + } + } + } + } + } + } + + void handleRightClick(int x, int y) { + Cell& cell = grid[y][x]; + + if (cell.state == HIDDEN) { + cell.state = FLAGGED; + flagCount++; + } + else if (cell.state == FLAGGED) { + cell.state = QUESTIONED; + flagCount--; + } + else if (cell.state == QUESTIONED) { + cell.state = HIDDEN; + } + } + + void revealAllMines() { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (grid[y][x].isMine && grid[y][x].state != FLAGGED) { + grid[y][x].state = REVEALED; + } + // Incorrect flags (flagged non-mines) + else if (!grid[y][x].isMine && grid[y][x].state == FLAGGED) { + grid[y][x].state = FLAGGED; // Keep them flagged to show mistakes + } + } + } + } + + void checkVictory() { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + const Cell& cell = grid[y][x]; + if (!cell.isMine && cell.state != REVEALED) { + return; // There's still a non-mine cell that's not revealed + } + } + } + + // All non-mine cells are revealed, victory! + victory = true; + + // Flag all mines automatically + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (grid[y][x].isMine && grid[y][x].state != FLAGGED) { + grid[y][x].state = FLAGGED; + } + } + } + flagCount = mineCount; + } + + void provideHint() { + if (gameOver || victory) return; + + // Try to find a safe cell to reveal + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + Cell& cell = grid[y][x]; + if (!cell.isMine && cell.state == HIDDEN) { + revealCell(x, y); + return; + } + } + } + } + + void drawBoard(sf::RenderWindow& window) { + sf::Sprite sprite; + sf::Text text; + text.setFont(font); + text.setCharacterSize(24); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + const Cell& cell = grid[y][x]; + int posX = x * cellSize; + int posY = y * cellSize + headerHeight; + + // Draw cell background + sprite.setPosition(static_cast(posX), static_cast(posY)); + + if (cell.state == REVEALED) { + sprite.setTexture(revealedTexture); + window.draw(sprite); + + if (cell.isMine) { + if (cell.isExploded) { + sprite.setTexture(explodedTexture); + } else { + sprite.setTexture(mineTexture); + } + window.draw(sprite); + } + else if (cell.adjacentMines > 0) { + // Draw number for adjacent mines + text.setString(std::to_string(cell.adjacentMines)); + + // Set color based on the number + switch (cell.adjacentMines) { + case 1: text.setFillColor(sf::Color::Blue); break; + case 2: text.setFillColor(sf::Color::Green); break; + case 3: text.setFillColor(sf::Color::Red); break; + case 4: text.setFillColor(sf::Color(128, 0, 128)); break; // Purple + case 5: text.setFillColor(sf::Color(128, 0, 0)); break; // Maroon + case 6: text.setFillColor(sf::Color(64, 224, 208)); break; // Turquoise + case 7: text.setFillColor(sf::Color::Black); break; + case 8: text.setFillColor(sf::Color(128, 128, 128)); break; // Gray + default: text.setFillColor(sf::Color::Black); + } + + // Center text in cell + sf::FloatRect textRect = text.getLocalBounds(); + text.setPosition( + static_cast(posX + (cellSize - textRect.width) / 2 - 4), + static_cast(posY + (cellSize - textRect.height) / 2 - 8) + ); + + window.draw(text); + } + } + else { + sprite.setTexture(hiddenTexture); + window.draw(sprite); + + if (cell.state == FLAGGED) { + sprite.setTexture(flagTexture); + window.draw(sprite); + } + else if (cell.state == QUESTIONED) { + sprite.setTexture(questionTexture); + window.draw(sprite); + } + } + } + } + } + + void drawHeader(sf::RenderWindow& window) { + // Draw background for header + sf::RectangleShape headerBg(sf::Vector2f(static_cast(boardWidth), static_cast(headerHeight))); + headerBg.setFillColor(sf::Color(192, 192, 192)); // Same gray as the rest + headerBg.setOutlineColor(sf::Color(128, 128, 128)); + headerBg.setOutlineThickness(2); + window.draw(headerBg); + + // Draw mine counter (left side) + drawCounter(window, mineCount - flagCount, 50, 16); + + // Draw timer (right side) + drawCounter(window, elapsedTime, boardWidth - 100, 16); + + // Draw settings button (gear icon) + sf::Sprite settingsSprite; + settingsSprite.setTexture(headerTextures[0]); + settingsSprite.setPosition(8, 14); + window.draw(settingsSprite); + + // Draw hint button (light bulb) + sf::Sprite hintSprite; + hintSprite.setTexture(headerTextures[1]); // Using scroll texture for now + hintSprite.setPosition(boardWidth - 40, 14); + window.draw(hintSprite); + + // Draw face button (center) + sf::Sprite faceSprite; + if (gameOver) { + faceSprite.setTexture(headerTextures[3]); // Sad face + } else if (victory) { + faceSprite.setTexture(headerTextures[4]); // Cool face + } else { + faceSprite.setTexture(headerTextures[2]); // Normal smiley + } + faceSprite.setPosition(boardWidth / 2 - 16, 14); + window.draw(faceSprite); + } + + void drawCounter(sf::RenderWindow& window, int value, int x, int y) { + // Ensure value is within 3-digit display range + if (value < 0) value = 0; + if (value > 999) value = 999; + + // Convert to string with leading zeros + std::stringstream ss; + ss << std::setw(3) << std::setfill('0') << value; + std::string valueStr = ss.str(); + + // Draw each digit + for (int i = 0; i < 3; i++) { + int digit = valueStr[i] - '0'; + sf::Sprite digitSprite; + digitSprite.setTexture(digitTextures[digit]); + digitSprite.setPosition(static_cast(x + i * 24), static_cast(y)); + window.draw(digitSprite); + } + } + + void showDifficultyMenu(sf::RenderWindow& window) { + sf::RenderWindow menuWindow(sf::VideoMode(300, 200), "Difficulty Settings", sf::Style::Close); + menuWindow.setFramerateLimit(60); + + // Create buttons for different difficulties + sf::Font font; + font.loadFromFile("assets/digital.ttf"); + + sf::Text titleText("Select Difficulty", font, 20); + titleText.setPosition(80, 10); + + sf::RectangleShape beginnerButton(sf::Vector2f(200, 30)); + beginnerButton.setPosition(50, 40); + beginnerButton.setFillColor(sf::Color(220, 220, 220)); + sf::Text beginnerText("Beginner (9x9, 10 mines)", font, 16); + beginnerText.setPosition(55, 45); + + sf::RectangleShape intermediateButton(sf::Vector2f(200, 30)); + intermediateButton.setPosition(50, 80); + intermediateButton.setFillColor(sf::Color(220, 220, 220)); + sf::Text intermediateText("Intermediate (16x16, 40 mines)", font, 16); + intermediateText.setPosition(55, 85); + + sf::RectangleShape expertButton(sf::Vector2f(200, 30)); + expertButton.setPosition(50, 120); + expertButton.setFillColor(sf::Color(220, 220, 220)); + sf::Text expertText("Expert (30x16, 99 mines)", font, 16); + expertText.setPosition(55, 125); + + sf::RectangleShape customButton(sf::Vector2f(200, 30)); + customButton.setPosition(50, 160); + customButton.setFillColor(sf::Color(220, 220, 220)); + sf::Text customText("Custom", font, 16); + customText.setPosition(55, 165); + + bool menuActive = true; + while (menuActive && menuWindow.isOpen()) { + sf::Event event; + while (menuWindow.pollEvent(event)) { + if (event.type == sf::Event::Closed) { + menuWindow.close(); + menuActive = false; + } + else if (event.type == sf::Event::MouseButtonPressed) { + sf::Vector2i mousePos = sf::Mouse::getPosition(menuWindow); + + // Check if any button is clicked + if (beginnerButton.getGlobalBounds().contains(static_cast(mousePos.x), static_cast(mousePos.y))) { + initGame(BEGINNER); + menuWindow.close(); + menuActive = false; + } + else if (intermediateButton.getGlobalBounds().contains(static_cast(mousePos.x), static_cast(mousePos.y))) { + initGame(INTERMEDIATE); + menuWindow.close(); + menuActive = false; + } + else if (expertButton.getGlobalBounds().contains(static_cast(mousePos.x), static_cast(mousePos.y))) { + initGame(EXPERT); + menuWindow.close(); + menuActive = false; + } + else if (customButton.getGlobalBounds().contains(static_cast(mousePos.x), static_cast(mousePos.y))) { + showCustomDifficultyMenu(menuWindow); + menuWindow.close(); + menuActive = false; + } + } + } + + menuWindow.clear(sf::Color(192, 192, 192)); + menuWindow.draw(titleText); + menuWindow.draw(beginnerButton); + menuWindow.draw(beginnerText); + menuWindow.draw(intermediateButton); + menuWindow.draw(intermediateText); + menuWindow.draw(expertButton); + menuWindow.draw(expertText); + menuWindow.draw(customButton); + menuWindow.draw(customText); + menuWindow.display(); + } + } + +void showCustomDifficultyMenu(sf::RenderWindow& parentWindow) { + sf::RenderWindow customWindow(sf::VideoMode(300, 250), "Custom Settings", sf::Style::Close); + customWindow.setFramerateLimit(60); + + sf::Font font; + if (!font.loadFromFile("assets/digital.ttf")) { + std::cerr << "Failed to load font\n"; + return; + } + + sf::Text titleText("Custom Settings", font, 20); + titleText.setPosition(80, 10); + + // Input fields for width, height, and mines + int customWidth = 16, customHeight = 16, customMines = 40; + + // Width input + sf::Text widthLabel("Width (8-50):", font, 16); + widthLabel.setPosition(20, 50); + sf::RectangleShape widthInput(sf::Vector2f(80, 25)); + widthInput.setPosition(200, 50); + widthInput.setFillColor(sf::Color::White); + widthInput.setOutlineColor(sf::Color::Black); + widthInput.setOutlineThickness(1); + sf::Text widthText(std::to_string(customWidth), font, 16); + widthText.setPosition(205, 52); + widthText.setFillColor(sf::Color::Black); + + // Height input + sf::Text heightLabel("Height (8-30):", font, 16); + heightLabel.setPosition(20, 90); + sf::RectangleShape heightInput(sf::Vector2f(80, 25)); + heightInput.setPosition(200, 90); + heightInput.setFillColor(sf::Color::White); + heightInput.setOutlineColor(sf::Color::Black); + heightInput.setOutlineThickness(1); + sf::Text heightText(std::to_string(customHeight), font, 16); + heightText.setPosition(205, 92); + heightText.setFillColor(sf::Color::Black); + + // Mines input + sf::Text minesLabel("Mines (10-500):", font, 16); + minesLabel.setPosition(20, 130); + sf::RectangleShape minesInput(sf::Vector2f(80, 25)); + minesInput.setPosition(200, 130); + minesInput.setFillColor(sf::Color::White); + minesInput.setOutlineColor(sf::Color::Black); + minesInput.setOutlineThickness(1); + sf::Text minesText(std::to_string(customMines), font, 16); + minesText.setPosition(205, 132); + minesText.setFillColor(sf::Color::Black); + + // OK and Cancel buttons + sf::RectangleShape okButton(sf::Vector2f(100, 30)); + okButton.setPosition(40, 180); + okButton.setFillColor(sf::Color(220, 220, 220)); + sf::Text okText("OK", font, 16); + okText.setPosition(80, 185); + okText.setFillColor(sf::Color::Black); + + sf::RectangleShape cancelButton(sf::Vector2f(100, 30)); + cancelButton.setPosition(160, 180); + cancelButton.setFillColor(sf::Color(220, 220, 220)); + sf::Text cancelText("Cancel", font, 16); + cancelText.setPosition(180, 185); + cancelText.setFillColor(sf::Color::Black); + + enum InputField { NONE, WIDTH, HEIGHT, MINES } activeField = NONE; + + while (customWindow.isOpen()) { + sf::Event event; + while (customWindow.pollEvent(event)) { + if (event.type == sf::Event::Closed) { + customWindow.close(); + } + else if (event.type == sf::Event::MouseButtonPressed) { + sf::Vector2i mousePos = sf::Mouse::getPosition(customWindow); + + // Check which input field is clicked + if (widthInput.getGlobalBounds().contains(static_cast(mousePos.x), static_cast(mousePos.y))) { + activeField = WIDTH; + widthInput.setOutlineColor(sf::Color::Blue); + heightInput.setOutlineColor(sf::Color::Black); + minesInput.setOutlineColor(sf::Color::Black); + } + else if (heightInput.getGlobalBounds().contains(static_cast(mousePos.x), static_cast(mousePos.y))) { + activeField = HEIGHT; + widthInput.setOutlineColor(sf::Color::Black); + heightInput.setOutlineColor(sf::Color::Blue); + minesInput.setOutlineColor(sf::Color::Black); + } + else if (minesInput.getGlobalBounds().contains(static_cast(mousePos.x), static_cast(mousePos.y))) { + activeField = MINES; + widthInput.setOutlineColor(sf::Color::Black); + heightInput.setOutlineColor(sf::Color::Black); + minesInput.setOutlineColor(sf::Color::Blue); + } + else if (okButton.getGlobalBounds().contains(static_cast(mousePos.x), static_cast(mousePos.y))) { + // Validate inputs + customWidth = std::max(8, std::min(50, customWidth)); + customHeight = std::max(8, std::min(30, customHeight)); + int maxMines = customWidth * customHeight * 0.9; // Maximum 90% of cells can be mines + customMines = std::max(10, std::min(maxMines, customMines)); + + setCustomDifficulty(customWidth, customHeight, customMines); + customWindow.close(); + } + else if (cancelButton.getGlobalBounds().contains(static_cast(mousePos.x), static_cast(mousePos.y))) { + customWindow.close(); + } + else { + activeField = NONE; + widthInput.setOutlineColor(sf::Color::Black); + heightInput.setOutlineColor(sf::Color::Black); + minesInput.setOutlineColor(sf::Color::Black); + } + } + else if (event.type == sf::Event::TextEntered) { + if (activeField != NONE) { + std::string currentValue; + int* targetValue = nullptr; + sf::Text* targetText = nullptr; + + // Determine which field we're editing + switch (activeField) { + case WIDTH: + currentValue = widthText.getString().toAnsiString(); + targetValue = &customWidth; + targetText = &widthText; + break; + case HEIGHT: + currentValue = heightText.getString().toAnsiString(); + targetValue = &customHeight; + targetText = &heightText; + break; + case MINES: + currentValue = minesText.getString().toAnsiString(); + targetValue = &customMines; + targetText = &minesText; + break; + default: + break; + } + + if (event.text.unicode >= '0' && event.text.unicode <= '9') { + // Handle numeric input + if (currentValue.length() < 3) { + currentValue += static_cast(event.text.unicode); + targetText->setString(currentValue); + *targetValue = std::stoi(currentValue); + } + } + else if (event.text.unicode == 8) { // Backspace + if (!currentValue.empty()) { + currentValue.pop_back(); + if (currentValue.empty()) { + currentValue = "0"; + } + targetText->setString(currentValue); + *targetValue = std::stoi(currentValue); + } + } + } + } + } + } + + customWindow.clear(sf::Color(192, 192, 192)); + customWindow.draw(titleText); + customWindow.draw(widthLabel); + customWindow.draw(widthInput); + customWindow.draw(widthText); + customWindow.draw(heightLabel); + customWindow.draw(heightInput); + customWindow.draw(heightText); + customWindow.draw(minesLabel); + customWindow.draw(minesInput); + customWindow.draw(minesText); + customWindow.draw(okButton); + customWindow.draw(okText); + customWindow.draw(cancelButton); + customWindow.draw(cancelText); + customWindow.display(); + } +}; +int main() { + // Create assets directory if it doesn't exist + #ifdef _WIN32 + system("if not exist assets mkdir assets"); + #else + system("mkdir -p assets"); + #endif + + // Create asset files + createAssets(); + + class main game; + game.run(); + + return 0; +} + +// Function to create asset files programmatically +void createAssets() { + // Create a basic pixel font for digits + sf::Font font; + font.loadFromFile("assets/digital.ttf"); + + // Create cell textures + createHiddenCellTexture(); + createRevealedCellTexture(); + createMineTexture(); + createFlagTexture(); + createQuestionTexture(); + createExplodedTexture(); + + // Create digit textures for the counter + for (int i = 0; i < 10; i++) { + createDigitTexture(i); + } + + // Create header icons + createGearTexture(); + createScrollTexture(); + createSmileyTexture(); + createSadTexture(); + createCoolTexture(); +} + +void createHiddenCellTexture() { + sf::RenderTexture texture; + texture.create(32, 32); + texture.clear(sf::Color(192, 192, 192)); // Light gray + + // Draw 3D effect + sf::ConvexShape shape; + shape.setPointCount(5); + shape.setPoint(0, sf::Vector2f(0, 0)); + shape.setPoint(1, sf::Vector2f(32, 0)); + shape.setPoint(2, sf::Vector2f(32, 32)); + shape.setPoint(3, sf::Vector2f(0, 32)); + shape.setPoint(4, sf::Vector2f(0, 0)); + + // Top and left edges (light) + sf::RectangleShape topEdge(sf::Vector2f(30, 2)); + topEdge.setPosition(0, 0); + topEdge.setFillColor(sf::Color::White); + texture.draw(topEdge); + + sf::RectangleShape leftEdge(sf::Vector2f(2, 30)); + leftEdge.setPosition(0, 0); + leftEdge.setFillColor(sf::Color::White); + texture.draw(leftEdge); + + // Bottom and right edges (dark) + sf::RectangleShape bottomEdge(sf::Vector2f(32, 2)); + bottomEdge.setPosition(0, 30); + bottomEdge.setFillColor(sf::Color(128, 128, 128)); + texture.draw(bottomEdge); + + sf::RectangleShape rightEdge(sf::Vector2f(2, 32)); + rightEdge.setPosition(30, 0); + rightEdge.setFillColor(sf::Color(128, 128, 128)); + texture.draw(rightEdge); + + texture.display(); + texture.getTexture().copyToImage().saveToFile("assets/hidden.png"); +} + +void createRevealedCellTexture() { + sf::RenderTexture texture; + texture.create(32, 32); + texture.clear(sf::Color(192, 192, 192)); // Light gray + + // Draw a simple border + sf::RectangleShape border(sf::Vector2f(32, 32)); + border.setFillColor(sf::Color::Transparent); + border.setOutlineColor(sf::Color(128, 128, 128)); + border.setOutlineThickness(1); + texture.draw(border); + + texture.display(); + texture.getTexture().copyToImage().saveToFile("assets/revealed.png"); +} + +void createMineTexture() { + sf::RenderTexture texture; + texture.create(32, 32); + texture.clear(sf::Color::Transparent); + + // Draw a circle for the mine + sf::CircleShape mine(10); + mine.setPosition(6, 6); + mine.setFillColor(sf::Color::Black); + texture.draw(mine); + + // Draw spikes + sf::RectangleShape hSpike(sf::Vector2f(24, 4)); + hSpike.setFillColor(sf::Color::Black); + hSpike.setPosition(4, 14); + texture.draw(hSpike); + + sf::RectangleShape vSpike(sf::Vector2f(4, 24)); + vSpike.setFillColor(sf::Color::Black); + vSpike.setPosition(14, 4); + texture.draw(vSpike); + + // Draw diagonal spikes + sf::RectangleShape d1Spike(sf::Vector2f(16, 4)); + d1Spike.setFillColor(sf::Color::Black); + d1Spike.setPosition(6, 6); + d1Spike.setRotation(45); + texture.draw(d1Spike); + + sf::RectangleShape d2Spike(sf::Vector2f(16, 4)); + d2Spike.setFillColor(sf::Color::Black); + d2Spike.setPosition(22, 6); + d2Spike.setRotation(135); + texture.draw(d2Spike); + + // Draw highlight + sf::CircleShape highlight(3); + highlight.setPosition(10, 10); + highlight.setFillColor(sf::Color::White); + texture.draw(highlight); + + texture.display(); + texture.getTexture().copyToImage().saveToFile("assets/mine.png"); +} + +void createFlagTexture() { + sf::RenderTexture texture; + texture.create(32, 32); + texture.clear(sf::Color::Transparent); + + // Draw flagpole + sf::RectangleShape pole(sf::Vector2f(2, 16)); + pole.setPosition(15, 8); + pole.setFillColor(sf::Color::Black); + texture.draw(pole); + + // Draw flag + sf::ConvexShape flag; + flag.setPointCount(3); + flag.setPoint(0, sf::Vector2f(17, 8)); + flag.setPoint(1, sf::Vector2f(17, 16)); + flag.setPoint(2, sf::Vector2f(24, 12)); + flag.setFillColor(sf::Color::Red); + texture.draw(flag); + + // Draw base + sf::RectangleShape base(sf::Vector2f(10, 4)); + base.setPosition(11, 24); + base.setFillColor(sf::Color::Black); + texture.draw(base); + + texture.display(); + texture.getTexture().copyToImage().saveToFile("assets/flag.png"); +} + +void createQuestionTexture() { + sf::RenderTexture texture; + texture.create(32, 32); + texture.clear(sf::Color::Transparent); + + // Create font for question mark + sf::Font font; + if (!font.loadFromFile("assets/digital.ttf")) { + // Create a simple font file + createDigitalFont(); + font.loadFromFile("assets/digital.ttf"); + } + + // Draw question mark + sf::Text text("?", font, 24); + text.setPosition(10, 4); + text.setFillColor(sf::Color::Blue); + texture.draw(text); + + texture.display(); + texture.getTexture().copyToImage().saveToFile("assets/question.png"); +} + +void createExplodedTexture() { + sf::RenderTexture texture; + texture.create(32, 32); + texture.clear(sf::Color::Red); // Red background + + // Draw mine (same as mine texture) + sf::CircleShape mine(10); + mine.setPosition(6, 6); + mine.setFillColor(sf::Color::Black); + texture.draw(mine); + + // Draw spikes + sf::RectangleShape hSpike(sf::Vector2f(24, 4)); + hSpike.setFillColor(sf::Color::Black); + hSpike.setPosition(4, 14); + texture.draw(hSpike); + + sf::RectangleShape vSpike(sf::Vector2f(4, 24)); + vSpike.setFillColor(sf::Color::Black); + vSpike.setPosition(14, 4); + texture.draw(vSpike); + + // Draw diagonal spikes + sf::RectangleShape d1Spike(sf::Vector2f(16, 4)); + d1Spike.setFillColor(sf::Color::Black); + d1Spike.setPosition(6, 6); + d1Spike.setRotation(45); + texture.draw(d1Spike); + + sf::RectangleShape d2Spike(sf::Vector2f(16, 4)); + d2Spike.setFillColor(sf::Color::Black); + d2Spike.setPosition(22, 6); + d2Spike.setRotation(135); + texture.draw(d2Spike); + + texture.display(); + texture.getTexture().copyToImage().saveToFile("assets/exploded.png"); +} + +void createDigitTexture(int digit) { + sf::RenderTexture texture; + texture.create(24, 32); + texture.clear(sf::Color::Black); + + // Create a digital display style + sf::Text text(std::to_string(digit), sf::Font(), 24); + if (digit == 0) { + // Draw 0 + sf::RectangleShape segments[6]; + // Top + segments[0] = sf::RectangleShape(sf::Vector2f(14, 4)); + segments[0].setPosition(5, 2); + // Top-left + segments[1] = sf::RectangleShape(sf::Vector2f(4, 12)); + segments[1].setPosition(2, 5); + // Top-right + segments[2] = sf::RectangleShape(sf::Vector2f(4, 12)); + segments[2].setPosition(18, 5); + // Bottom-left + segments[3] = sf::RectangleShape(sf::Vector2f(4, 12)); + segments[3].setPosition(2, 18); + // Bottom-right + segments[4] = sf::RectangleShape(sf::Vector2f(4, 12)); + segments[4].setPosition(18, 18); + // Bottom + segments[5] = sf::RectangleShape(sf::Vector2f(14, 4)); + segments[5].setPosition(5, 26); + + for (int i = 0; i < 6; i++) { + segments[i].setFillColor(sf::Color::Red); + texture.draw(segments[i]); + } + } else if (digit == 1) { + // Draw 1 + sf::RectangleShape segments[2]; + // Top-right + segments[0] = sf::RectangleShape(sf::Vector2f(4, 12)); + segments[0].setPosition(12, 5); + // Bottom-right + segments[1] = sf::RectangleShape(sf::Vector2f(4, 12)); + segments[1].setPosition(12, 18); + + for (int i = 0; i < 2; i++) { + segments[i].setFillColor(sf::Color::Red); + texture.draw(segments[i]); + } + } else { + // For other digits, just draw the text + sf::Font font; + if (!font.loadFromFile("assets/digital.ttf")) { + createDigitalFont(); + font.loadFromFile("assets/digital.ttf"); + } + + sf::Text digitText(std::to_string(digit), font, 24); + digitText.setPosition(8, 4); + digitText.setFillColor(sf::Color::Red); + texture.draw(digitText); + } + + texture.display(); + texture.getTexture().copyToImage().saveToFile("assets/digit" + std::to_string(digit) + ".png"); +} + +void createGearTexture() { + sf::RenderTexture texture; + texture.create(32, 32); + texture.clear(sf::Color::Transparent); + + // Draw a circle for the gear + sf::CircleShape gear(10); + gear.setPosition(6, 6); + gear.setFillColor(sf::Color(100, 100, 100)); + texture.draw(gear); + + // Draw inner circle + sf::CircleShape inner(5); + inner.setPosition(11, 11); + inner.setFillColor(sf::Color(192, 192, 192)); + texture.draw(inner); + + // Draw teeth + for (int i = 0; i < 8; i++) { + sf::RectangleShape tooth(sf::Vector2f(6, 4)); + float angle = i * 45.f * 3.14159f / 180.f; + tooth.setPosition( + 16 + 12 * std::cos(angle) - 3, + 16 + 12 * std::sin(angle) - 2 + ); + tooth.setRotation(i * 45.f); + tooth.setFillColor(sf::Color(100, 100, 100)); + texture.draw(tooth); + } + + texture.display(); + texture.getTexture().copyToImage().saveToFile("assets/gear.png"); +} + +void createScrollTexture() { + sf::RenderTexture texture; + texture.create(32, 32); + texture.clear(sf::Color::Transparent); + + // Draw bulb base + sf::ConvexShape bulbBase; + bulbBase.setPointCount(4); + bulbBase.setPoint(0, sf::Vector2f(12, 20)); + bulbBase.setPoint(1, sf::Vector2f(20, 20)); + bulbBase.setPoint(2, sf::Vector2f(18, 28)); + bulbBase.setPoint(3, sf::Vector2f(14, 28)); + bulbBase.setFillColor(sf::Color(200, 200, 100)); + texture.draw(bulbBase); + + // Draw bulb + sf::CircleShape bulb(8); + bulb.setPosition(8, 4); + bulb.setFillColor(sf::Color(255, 255, 0)); // Yellow + texture.draw(bulb); + + // Draw rays + sf::RectangleShape rays[4]; + rays[0] = sf::RectangleShape(sf::Vector2f(4, 10)); + rays[0].setPosition(14, 0); + rays[1] = sf::RectangleShape(sf::Vector2f(4, 10)); + rays[1].setPosition(14, 22); + rays[2] = sf::RectangleShape(sf::Vector2f(10, 4)); + rays[2].setPosition(0, 14); + rays[3] = sf::RectangleShape(sf::Vector2f(10, 4)); + rays[3].setPosition(22, 14); + + for (int i = 0; i < 4; i++) { + rays[i].setFillColor(sf::Color(255, 255, 0)); + texture.draw(rays[i]); + } + + texture.display(); + texture.getTexture().copyToImage().saveToFile("assets/scroll.png"); +} + +void createSmileyTexture() { + sf::RenderTexture texture; + texture.create(32, 32); + texture.clear(sf::Color::Transparent); + + // Draw face + sf::CircleShape face(14); + face.setPosition(2, 2); + face.setFillColor(sf::Color(255, 255, 0)); // Yellow + face.setOutlineColor(sf::Color::Black); + face.setOutlineThickness(1); + texture.draw(face); + + // Draw eyes + sf::CircleShape leftEye(3); + leftEye.setPosition(8, 10); + leftEye.setFillColor(sf::Color::Black); + texture.draw(leftEye); + + sf::CircleShape rightEye(3); + rightEye.setPosition(21, 10); + rightEye.setFillColor(sf::Color::Black); + texture.draw(rightEye); + + // Draw smile + sf::ConvexShape smile; + smile.setPointCount(5); + smile.setPoint(0, sf::Vector2f(8, 18)); + smile.setPoint(1, sf::Vector2f(16, 24)); + smile.setPoint(2, sf::Vector2f(24, 18)); + smile.setPoint(3, sf::Vector2f(24, 20)); + smile.setPoint(4, sf::Vector2f(8, 20)); + smile.setFillColor(sf::Color::Black); + texture.draw(smile); + + texture.display(); + texture.getTexture().copyToImage().saveToFile("assets/smiley.png"); +} + +void createSadTexture() { + sf::RenderTexture texture; + texture.create(32, 32); + texture.clear(sf::Color::Transparent); + + // Draw face + sf::CircleShape face(14); + face.setPosition(2, 2); + face.setFillColor(sf::Color(255, 255, 0)); // Yellow + face.setOutlineColor(sf::Color::Black); + face.setOutlineThickness(1); + texture.draw(face); + + // Draw eyes + sf::CircleShape leftEye(3); + leftEye.setPosition(8, 10); + leftEye.setFillColor(sf::Color::Black); + texture.draw(leftEye); + + sf::CircleShape rightEye(3); + rightEye.setPosition(21, 10); + rightEye.setFillColor(sf::Color::Black); + texture.draw(rightEye); + + // Draw frown + sf::ConvexShape frown; + frown.setPointCount(5); + frown.setPoint(0, sf::Vector2f(8, 22)); + frown.setPoint(1, sf::Vector2f(16, 18)); + frown.setPoint(2, sf::Vector2f(24, 22)); + frown.setPoint(3, sf::Vector2f(24, 24)); + frown.setPoint(4, sf::Vector2f(8, 24)); + frown.setFillColor(sf::Color::Black); + texture.draw(frown); + + texture.display(); + texture.getTexture().copyToImage().saveToFile("assets/sad.png"); +} + +void createCoolTexture() { + sf::RenderTexture texture; + texture.create(32, 32); + texture.clear(sf::Color::Transparent); + + // Draw face + sf::CircleShape face(14); + face.setPosition(2, 2); + face.setFillColor(sf::Color(255, 255, 0)); // Yellow + face.setOutlineColor(sf::Color::Black); + face.setOutlineThickness(1); + texture.draw(face); + + // Draw sunglasses + sf::RectangleShape glasses(sf::Vector2f(22, 8)); + glasses.setPosition(5, 10); + glasses.setFillColor(sf::Color::Black); + texture.draw(glasses); + + // Draw smile + sf::ConvexShape smile; + smile.setPointCount(5); + smile.setPoint(0, sf::Vector2f(8, 20)); + smile.setPoint(1, sf::Vector2f(16, 24)); + smile.setPoint(2, sf::Vector2f(24, 20)); + smile.setPoint(3, sf::Vector2f(24, 22)); + smile.setPoint(4, sf::Vector2f(8, 22)); + smile.setFillColor(sf::Color::Black); + texture.draw(smile); + + texture.display(); + texture.getTexture().copyToImage().saveToFile("assets/cool.png"); +} + +void createDigitalFont() { + // This is a very simple placeholder function for creating a font file + // In a real implementation, you would either use an existing font file + // or create a more sophisticated font + std::ofstream fontFile("assets/digital.ttf", std::ios::binary); + + // Write some placeholder data + const char* fontData = "TTF"; + fontFile.write(fontData, 3); + fontFile.close(); + + std::cout << "Please place a real TTF font file at 'assets/digital.ttf'" << std::endl; +} \ No newline at end of file