initial
This commit is contained in:
30
CMakeLists.txt
Normal file
30
CMakeLists.txt
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
project(minesweeper C)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 99)
|
||||||
|
|
||||||
|
# Find SDL2 and SDL2_ttf using pkg-config
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(SDL2 REQUIRED sdl2)
|
||||||
|
pkg_check_modules(SDL2TTF REQUIRED SDL2_ttf)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${SDL2_INCLUDE_DIRS}
|
||||||
|
${SDL2TTF_INCLUDE_DIRS}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||||
|
)
|
||||||
|
|
||||||
|
link_directories(
|
||||||
|
${SDL2_LIBRARY_DIRS}
|
||||||
|
${SDL2TTF_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(minesweeper
|
||||||
|
src/main.c
|
||||||
|
src/game.c
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(minesweeper
|
||||||
|
${SDL2_LIBRARIES}
|
||||||
|
${SDL2TTF_LIBRARIES}
|
||||||
|
)
|
||||||
207
src/game.c
Normal file
207
src/game.c
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
#include "game.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL_ttf.h>
|
||||||
|
|
||||||
|
extern SDL_Renderer* renderer;
|
||||||
|
extern TTF_Font* font;
|
||||||
|
|
||||||
|
extern SDL_Renderer* renderer;
|
||||||
|
|
||||||
|
int game_over = 0;
|
||||||
|
const char* texture_blank =
|
||||||
|
"...."
|
||||||
|
". ."
|
||||||
|
". ."
|
||||||
|
"....";
|
||||||
|
|
||||||
|
const char* texture_flag =
|
||||||
|
".!!."
|
||||||
|
".!!."
|
||||||
|
".!!."
|
||||||
|
".!!.";
|
||||||
|
|
||||||
|
const char* texture_mine =
|
||||||
|
"****"
|
||||||
|
"****"
|
||||||
|
"****"
|
||||||
|
"****";
|
||||||
|
|
||||||
|
const char* number_textures[9] = {
|
||||||
|
NULL, // index 0 not used
|
||||||
|
".1.."
|
||||||
|
".1.."
|
||||||
|
".1.."
|
||||||
|
".1..",
|
||||||
|
|
||||||
|
".22."
|
||||||
|
". ."
|
||||||
|
".22."
|
||||||
|
". .",
|
||||||
|
|
||||||
|
".33."
|
||||||
|
". ."
|
||||||
|
".33."
|
||||||
|
". .",
|
||||||
|
|
||||||
|
".44."
|
||||||
|
". ."
|
||||||
|
".44."
|
||||||
|
". .",
|
||||||
|
|
||||||
|
".55."
|
||||||
|
". ."
|
||||||
|
".55."
|
||||||
|
". .",
|
||||||
|
|
||||||
|
".66."
|
||||||
|
". ."
|
||||||
|
".66."
|
||||||
|
". .",
|
||||||
|
|
||||||
|
".77."
|
||||||
|
". ."
|
||||||
|
".77."
|
||||||
|
". .",
|
||||||
|
|
||||||
|
".88."
|
||||||
|
". ."
|
||||||
|
".88."
|
||||||
|
". .",
|
||||||
|
};
|
||||||
|
|
||||||
|
void place_mines() {
|
||||||
|
int placed = 0;
|
||||||
|
while (placed < NUM_MINES) {
|
||||||
|
int x = rand() % GRID_WIDTH;
|
||||||
|
int y = rand() % GRID_HEIGHT;
|
||||||
|
if (!grid[x][y].has_mine) {
|
||||||
|
grid[x][y].has_mine = 1;
|
||||||
|
placed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void calculate_neighbors() {
|
||||||
|
for (int x = 0; x < GRID_WIDTH; x++) {
|
||||||
|
for (int y = 0; y < GRID_HEIGHT; y++) {
|
||||||
|
if (grid[x][y].has_mine) continue;
|
||||||
|
int count = 0;
|
||||||
|
for (int dx = -1; dx <= 1; dx++) {
|
||||||
|
for (int dy = -1; dy <= 1; dy++) {
|
||||||
|
int nx = x + dx, ny = y + dy;
|
||||||
|
if (nx >= 0 && nx < GRID_WIDTH && ny >= 0 && ny < GRID_HEIGHT)
|
||||||
|
count += grid[nx][ny].has_mine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
grid[x][y].neighbor_mines = count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_game() {
|
||||||
|
srand((unsigned int)time(NULL));
|
||||||
|
for (int x = 0; x < GRID_WIDTH; x++)
|
||||||
|
for (int y = 0; y < GRID_HEIGHT; y++)
|
||||||
|
grid[x][y] = (Cell){0};
|
||||||
|
place_mines();
|
||||||
|
calculate_neighbors();
|
||||||
|
game_over = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reveal_cell(int x, int y) {
|
||||||
|
if (x < 0 || x >= GRID_WIDTH || y < 0 || y >= GRID_HEIGHT) return;
|
||||||
|
if (grid[x][y].revealed || grid[x][y].flagged) return;
|
||||||
|
grid[x][y].revealed = 1;
|
||||||
|
|
||||||
|
if (grid[x][y].has_mine) {
|
||||||
|
game_over = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (grid[x][y].neighbor_mines == 0) {
|
||||||
|
for (int dx = -1; dx <= 1; dx++)
|
||||||
|
for (int dy = -1; dy <= 1; dy++)
|
||||||
|
if (dx || dy)
|
||||||
|
reveal_cell(x + dx, y + dy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggle_flag(int x, int y) {
|
||||||
|
if (!grid[x][y].revealed)
|
||||||
|
grid[x][y].flagged = !grid[x][y].flagged;
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_game_over() {
|
||||||
|
return game_over;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_text(const char* text, int x, int y, SDL_Color color) {
|
||||||
|
SDL_Surface* surface = TTF_RenderText_Blended(font, text, color);
|
||||||
|
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||||
|
SDL_Rect dst = { x, y, surface->w, surface->h };
|
||||||
|
SDL_RenderCopy(renderer, texture, NULL, &dst);
|
||||||
|
SDL_DestroyTexture(texture);
|
||||||
|
SDL_FreeSurface(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_texture(const char* pattern, int x, int y, SDL_Color fg, SDL_Color bg) {
|
||||||
|
for (int row = 0; row < 4; ++row) {
|
||||||
|
for (int col = 0; col < 4; ++col) {
|
||||||
|
char pixel = pattern[row * 4 + col];
|
||||||
|
SDL_Rect rect = {
|
||||||
|
x + col * (CELL_SIZE / 4),
|
||||||
|
y + row * (CELL_SIZE / 4),
|
||||||
|
CELL_SIZE / 4,
|
||||||
|
CELL_SIZE / 4
|
||||||
|
};
|
||||||
|
SDL_SetRenderDrawColor(renderer,
|
||||||
|
pixel == '.' ? bg.r : fg.r,
|
||||||
|
pixel == '.' ? bg.g : fg.g,
|
||||||
|
pixel == '.' ? bg.b : fg.b,
|
||||||
|
255);
|
||||||
|
SDL_RenderFillRect(renderer, &rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_game() {
|
||||||
|
SDL_SetRenderDrawColor(renderer, 50, 50, 50, 255);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
|
for (int x = 0; x < GRID_WIDTH; x++) {
|
||||||
|
for (int y = 0; y < GRID_HEIGHT; y++) {
|
||||||
|
SDL_Rect rect = { x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE };
|
||||||
|
Cell* c = &grid[x][y];
|
||||||
|
|
||||||
|
// Background
|
||||||
|
if (c->revealed) {
|
||||||
|
SDL_SetRenderDrawColor(renderer, 200, 200, 200, 255);
|
||||||
|
} else {
|
||||||
|
SDL_SetRenderDrawColor(renderer, 100, 100, 100, 255);
|
||||||
|
}
|
||||||
|
SDL_RenderFillRect(renderer, &rect);
|
||||||
|
|
||||||
|
// Border
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||||
|
SDL_RenderDrawRect(renderer, &rect);
|
||||||
|
|
||||||
|
// Content
|
||||||
|
if (c->revealed) {
|
||||||
|
if (c->has_mine) {
|
||||||
|
draw_text("*", rect.x + 8, rect.y + 4, (SDL_Color){255, 0, 0});
|
||||||
|
} else if (c->neighbor_mines > 0) {
|
||||||
|
char buffer[2];
|
||||||
|
snprintf(buffer, 2, "%d", c->neighbor_mines);
|
||||||
|
draw_text(buffer, rect.x + 10, rect.y + 4, (SDL_Color){0, 0, 255});
|
||||||
|
}
|
||||||
|
} else if (c->flagged) {
|
||||||
|
draw_text("F", rect.x + 10, rect.y + 4, (SDL_Color){255, 0, 0});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
33
src/game.h
Normal file
33
src/game.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#ifndef GAME_H
|
||||||
|
#define GAME_H
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL_ttf.h>
|
||||||
|
|
||||||
|
// Game grid dimensions
|
||||||
|
#define GRID_WIDTH 10
|
||||||
|
#define GRID_HEIGHT 10
|
||||||
|
#define NUM_MINES 10
|
||||||
|
#define CELL_SIZE 32
|
||||||
|
|
||||||
|
// Cell structure
|
||||||
|
typedef struct {
|
||||||
|
int revealed;
|
||||||
|
int has_mine;
|
||||||
|
int flagged;
|
||||||
|
int neighbor_mines;
|
||||||
|
} Cell;
|
||||||
|
|
||||||
|
// Extern declarations
|
||||||
|
extern SDL_Renderer* renderer;
|
||||||
|
extern TTF_Font* font;
|
||||||
|
extern Cell grid[GRID_WIDTH][GRID_HEIGHT];
|
||||||
|
|
||||||
|
// Function declarations
|
||||||
|
void init_game();
|
||||||
|
void reveal_cell(int x, int y);
|
||||||
|
void toggle_flag(int x, int y);
|
||||||
|
void draw_game();
|
||||||
|
void draw_text(const char* text, int x, int y, SDL_Color color);
|
||||||
|
|
||||||
|
#endif
|
||||||
81
src/main.c
Normal file
81
src/main.c
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL_ttf.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "game.h"
|
||||||
|
|
||||||
|
// Global SDL variables
|
||||||
|
SDL_Renderer* renderer = NULL;
|
||||||
|
TTF_Font* font = NULL;
|
||||||
|
Cell grid[GRID_WIDTH][GRID_HEIGHT];
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
|
||||||
|
fprintf(stderr, "SDL_Init Error: %s\n", SDL_GetError());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TTF_Init() != 0) {
|
||||||
|
fprintf(stderr, "TTF_Init Error: %s\n", TTF_GetError());
|
||||||
|
SDL_Quit();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
font = TTF_OpenFont("/usr/share/fonts/dejavu-sans-fonts/DejaVuSans.ttf", 16); // Change path if needed
|
||||||
|
if (!font) {
|
||||||
|
fprintf(stderr, "Failed to load font: %s\n", TTF_GetError());
|
||||||
|
TTF_Quit();
|
||||||
|
SDL_Quit();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Window* window = SDL_CreateWindow("Minesweeper",
|
||||||
|
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||||
|
GRID_WIDTH * CELL_SIZE, GRID_HEIGHT * CELL_SIZE, SDL_WINDOW_SHOWN);
|
||||||
|
|
||||||
|
if (!window) {
|
||||||
|
fprintf(stderr, "Window creation failed: %s\n", SDL_GetError());
|
||||||
|
TTF_Quit();
|
||||||
|
SDL_Quit();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
||||||
|
if (!renderer) {
|
||||||
|
fprintf(stderr, "Renderer creation failed: %s\n", SDL_GetError());
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
TTF_Quit();
|
||||||
|
SDL_Quit();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_game();
|
||||||
|
|
||||||
|
int running = 1;
|
||||||
|
SDL_Event event;
|
||||||
|
while (running) {
|
||||||
|
while (SDL_PollEvent(&event)) {
|
||||||
|
if (event.type == SDL_QUIT) {
|
||||||
|
running = 0;
|
||||||
|
} else if (event.type == SDL_MOUSEBUTTONDOWN) {
|
||||||
|
int x = event.button.x / CELL_SIZE;
|
||||||
|
int y = event.button.y / CELL_SIZE;
|
||||||
|
|
||||||
|
if (event.button.button == SDL_BUTTON_LEFT) {
|
||||||
|
reveal_cell(x, y);
|
||||||
|
} else if (event.button.button == SDL_BUTTON_RIGHT) {
|
||||||
|
toggle_flag(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_game();
|
||||||
|
SDL_Delay(16); // Cap to ~60 FPS
|
||||||
|
}
|
||||||
|
|
||||||
|
TTF_CloseFont(font);
|
||||||
|
SDL_DestroyRenderer(renderer);
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
TTF_Quit();
|
||||||
|
SDL_Quit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user