This commit is contained in:
rattatwinko
2025-05-10 22:03:07 +02:00
commit b0c8fc83fe
4 changed files with 351 additions and 0 deletions

30
CMakeLists.txt Normal file
View 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
View 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
View 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
View 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;
}