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