seems to be working
This commit is contained in:
commit
98a655d315
8 changed files with 594 additions and 0 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
.cache
|
||||||
|
build
|
||||||
|
.zed
|
||||||
|
.clang-format
|
||||||
|
.DS_Store
|
||||||
13
CmakeLists.txt
Normal file
13
CmakeLists.txt
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
project(minesweeper_sdl)
|
||||||
|
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
set(EXECUTABLE_NAME bin)
|
||||||
|
|
||||||
|
file(GLOB SOURCES "src/*.c")
|
||||||
|
add_executable(${EXECUTABLE_NAME} ${SOURCES})
|
||||||
|
target_include_directories(${EXECUTABLE_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
|
find_package(SDL3 REQUIRED COMPONENTS SDL3)
|
||||||
|
target_link_libraries(${EXECUTABLE_NAME} SDL3::SDL3)
|
||||||
9
README.md
Normal file
9
README.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
A simple minesweeper game I made, 'cause train rides to school are boring.
|
||||||
|
|
||||||
|
Requires cmake and SDL3 to compile.
|
||||||
|
|
||||||
|
Compile, and run with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -B build/ && cmake --build build/ && ./build/bin
|
||||||
|
```
|
||||||
36
include/board.h
Normal file
36
include/board.h
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
} Vector2;
|
||||||
|
Vector2 random_vector2(Vector2 bounds);
|
||||||
|
// returns size of the output, doesn't check if the output will fit
|
||||||
|
int get_neighbours(Vector2 input, Vector2 bounds, Vector2* output);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool has_mine;
|
||||||
|
bool has_flag;
|
||||||
|
bool is_revealed;
|
||||||
|
// -1 means it hasn't been calculated
|
||||||
|
char revealed_value;
|
||||||
|
} Cell;
|
||||||
|
Cell new_cell();
|
||||||
|
// returns true if there isn't a mine, cells with flags can't be revealed
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
// x, y
|
||||||
|
Cell** cells;
|
||||||
|
Vector2 bounds;
|
||||||
|
Vector2 hover;
|
||||||
|
bool game_over;
|
||||||
|
bool game_started;
|
||||||
|
} Board;
|
||||||
|
Board generate_board(Vector2 bounds, int mine_count);
|
||||||
|
Cell* get_cell(Board* board, Vector2* position);
|
||||||
|
void shift_board(Board* board, Vector2* direction);
|
||||||
|
void destroy_board(Board);
|
||||||
|
void right_click(Board*);
|
||||||
|
void left_click(Board*);
|
||||||
12
include/graphics.h
Normal file
12
include/graphics.h
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
#include "board.h"
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
void draw_circle(SDL_Renderer* target, Vector2 position, int radius);
|
||||||
|
void draw_grid(SDL_Renderer* target, Vector2 size);
|
||||||
|
void draw_mines(SDL_Renderer* target, Board board);
|
||||||
|
void draw_flags(SDL_Renderer* target, Board board);
|
||||||
|
void draw_hover(SDL_Renderer* targer, Board board);
|
||||||
|
void draw_revealed(SDL_Renderer* target, Board board);
|
||||||
|
void draw_numbers(SDL_Renderer* target, Board* board);
|
||||||
|
Vector2 get_resolution(SDL_Renderer* renderer, Vector2 size);
|
||||||
226
src/board.c
Normal file
226
src/board.c
Normal file
|
|
@ -0,0 +1,226 @@
|
||||||
|
#include "board.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
Vector2 random_vector2(Vector2 bounds)
|
||||||
|
{
|
||||||
|
Vector2 output = { -1, -1 };
|
||||||
|
output.x = SDL_rand(bounds.x);
|
||||||
|
output.y = SDL_rand(bounds.y);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_neighbours(Vector2 input, Vector2 bounds, Vector2* output)
|
||||||
|
{
|
||||||
|
int length = 0;
|
||||||
|
Vector2 tmp = { -1, -1 };
|
||||||
|
if (input.x > 0 && input.y > 0) {
|
||||||
|
tmp.x = input.x - 1;
|
||||||
|
tmp.y = input.y - 1;
|
||||||
|
output[length] = tmp;
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
if (input.x > 0 && input.y < bounds.y - 1) {
|
||||||
|
tmp.x = input.x - 1;
|
||||||
|
tmp.y = input.y + 1;
|
||||||
|
output[length] = tmp;
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
if (input.x > 0) {
|
||||||
|
tmp.x = input.x - 1;
|
||||||
|
tmp.y = input.y;
|
||||||
|
output[length] = tmp;
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
if (input.x < bounds.x - 1 && input.y > 0) {
|
||||||
|
tmp.x = input.x + 1;
|
||||||
|
tmp.y = input.y - 1;
|
||||||
|
output[length] = tmp;
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
if (input.x < bounds.x - 1 && input.y < bounds.y - 1) {
|
||||||
|
tmp.x = input.x + 1;
|
||||||
|
tmp.y = input.y + 1;
|
||||||
|
output[length] = tmp;
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
if (input.x < bounds.x - 1) {
|
||||||
|
tmp.x = input.x + 1;
|
||||||
|
tmp.y = input.y;
|
||||||
|
output[length] = tmp;
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
if (input.y > 0) {
|
||||||
|
tmp.x = input.x;
|
||||||
|
tmp.y = input.y - 1;
|
||||||
|
output[length] = tmp;
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
if (input.y < bounds.y - 1) {
|
||||||
|
tmp.x = input.x;
|
||||||
|
tmp.y = input.y + 1;
|
||||||
|
output[length] = tmp;
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell new_cell()
|
||||||
|
{
|
||||||
|
Cell output;
|
||||||
|
output.has_mine = false;
|
||||||
|
output.has_flag = false;
|
||||||
|
output.is_revealed = false;
|
||||||
|
output.revealed_value = -1;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
char cell_value(Board* board, Vector2 position)
|
||||||
|
{
|
||||||
|
char out = 0;
|
||||||
|
Vector2 neighbours[8];
|
||||||
|
if (get_cell(board, &position)->has_mine) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int n = get_neighbours(position, board->bounds, neighbours);
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
if (get_cell(board, &neighbours[i])->has_mine) {
|
||||||
|
out++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 find_empty_cell(Board* board)
|
||||||
|
{
|
||||||
|
for (int i = 1; i < board->bounds.x - 1; i++) {
|
||||||
|
for (int j = 1; j < board->bounds.y - 1; j++) {
|
||||||
|
Vector2 position = { i, j };
|
||||||
|
if (cell_value(board, position) == 0) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Vector2 out = { -1, -1 };
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
Board generate_board(Vector2 bounds, int mine_count)
|
||||||
|
{
|
||||||
|
Cell** cells = malloc(sizeof(Cell*) * bounds.x);
|
||||||
|
for (int i = 0; i < bounds.x; i++) {
|
||||||
|
cells[i] = malloc(sizeof(Cell) * bounds.y);
|
||||||
|
for (int j = 0; j < bounds.y; j++) {
|
||||||
|
cells[i][j] = new_cell();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Board output = { cells, bounds };
|
||||||
|
output.hover.x = -1;
|
||||||
|
output.hover.y = -1;
|
||||||
|
output.game_over = false;
|
||||||
|
output.game_started = false;
|
||||||
|
while (mine_count > 0) {
|
||||||
|
const Vector2 mine_position = random_vector2(bounds);
|
||||||
|
if (cells[mine_position.x][mine_position.y].has_mine) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mine_count--;
|
||||||
|
cells[mine_position.x][mine_position.y].has_mine = true;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell* get_cell(Board* board, Vector2* position)
|
||||||
|
{
|
||||||
|
return &board->cells[position->x][position->y];
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_board(Board board)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < board.bounds.x; i++) {
|
||||||
|
free(board.cells[i]);
|
||||||
|
}
|
||||||
|
free(board.cells);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reveal_cell(Board* board, Vector2* position)
|
||||||
|
{
|
||||||
|
Cell* cell = get_cell(board, position);
|
||||||
|
if (cell->is_revealed == true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cell->is_revealed = true;
|
||||||
|
cell->revealed_value = cell_value(board, *position);
|
||||||
|
|
||||||
|
if (cell->revealed_value != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Vector2 neighbours[8];
|
||||||
|
int n = get_neighbours(*position, board->bounds, neighbours);
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
Cell* neighbour = get_cell(board, &neighbours[i]);
|
||||||
|
if (neighbour->has_mine) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
reveal_cell(board, &neighbours[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void right_click(Board* board)
|
||||||
|
{
|
||||||
|
board->cells[board->hover.x][board->hover.y].has_flag
|
||||||
|
= !board->cells[board->hover.x][board->hover.y].has_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void left_click(Board* board)
|
||||||
|
{
|
||||||
|
if (board->cells[board->hover.x][board->hover.y].has_flag) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!board->game_started) {
|
||||||
|
board->game_started = true;
|
||||||
|
if (cell_value(board, board->hover) == 0) {
|
||||||
|
reveal_cell(board, &board->hover);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Vector2 anchor_position = find_empty_cell(board);
|
||||||
|
anchor_position.x = board->hover.x - anchor_position.x;
|
||||||
|
anchor_position.y = board->hover.y - anchor_position.y;
|
||||||
|
shift_board(board, &anchor_position);
|
||||||
|
reveal_cell(board, &board->hover);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (board->cells[board->hover.x][board->hover.y].has_mine) {
|
||||||
|
board->game_over = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reveal_cell(board, &board->hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 sub_modulo(Vector2 a, Vector2 b, Vector2 bounds)
|
||||||
|
{
|
||||||
|
Vector2 out = {
|
||||||
|
(bounds.x + a.x - b.x) % bounds.x,
|
||||||
|
(bounds.y + a.y - b.y) % bounds.y
|
||||||
|
};
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shift_board(Board* board, Vector2* direction)
|
||||||
|
{
|
||||||
|
Cell** new_board = malloc(sizeof(Cell*) * board->bounds.x);
|
||||||
|
for (int i = 0; i < board->bounds.x; i++) {
|
||||||
|
new_board[i] = malloc(sizeof(Cell) * board->bounds.y);
|
||||||
|
for (int j = 0; j < board->bounds.y; j++) {
|
||||||
|
Vector2 position = { i, j };
|
||||||
|
position = sub_modulo(position, *direction, board->bounds);
|
||||||
|
new_board[i][j] = *get_cell(board, &position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < board->bounds.x; i++) {
|
||||||
|
for (int j = 0; j < board->bounds.y; j++) {
|
||||||
|
board->cells[i][j] = new_board[i][j];
|
||||||
|
}
|
||||||
|
free(new_board[i]);
|
||||||
|
}
|
||||||
|
free(new_board);
|
||||||
|
}
|
||||||
178
src/graphics.c
Normal file
178
src/graphics.c
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
#include "graphics.h"
|
||||||
|
#include "board.h"
|
||||||
|
|
||||||
|
const SDL_Color light_green = { 170, 215, 81, SDL_ALPHA_OPAQUE };
|
||||||
|
const SDL_Color dark_green = { 162, 209, 73, SDL_ALPHA_OPAQUE };
|
||||||
|
const SDL_Color light_yellow = { 229, 194, 159, SDL_ALPHA_OPAQUE };
|
||||||
|
const SDL_Color dark_yellow = { 215, 184, 153, SDL_ALPHA_OPAQUE };
|
||||||
|
const SDL_Color hover_dark_green = { 185, 221, 119, SDL_ALPHA_OPAQUE };
|
||||||
|
const SDL_Color black = { 0, 0, 0, SDL_ALPHA_OPAQUE };
|
||||||
|
const SDL_Color red = { 255, 0, 0, SDL_ALPHA_OPAQUE };
|
||||||
|
|
||||||
|
void set_color(SDL_Renderer* target, SDL_Color color)
|
||||||
|
{
|
||||||
|
SDL_SetRenderDrawColor(target, color.r, color.g, color.b, color.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_circle(SDL_Renderer* target, Vector2 position, int radius)
|
||||||
|
{
|
||||||
|
int x = radius;
|
||||||
|
int y = 0;
|
||||||
|
int radius_error = 1 - x;
|
||||||
|
|
||||||
|
while (x >= y) {
|
||||||
|
for (int i = position.x - x; i < position.x + x; i++) {
|
||||||
|
SDL_RenderPoint(target, i, position.y + y);
|
||||||
|
SDL_RenderPoint(target, i, position.y - y);
|
||||||
|
}
|
||||||
|
for (int i = position.x - y; i < position.x + y; i++) {
|
||||||
|
SDL_RenderPoint(target, i, position.y + x);
|
||||||
|
SDL_RenderPoint(target, i, position.y - x);
|
||||||
|
}
|
||||||
|
y++;
|
||||||
|
if (radius_error < 0) {
|
||||||
|
radius_error += 2 * y + 1;
|
||||||
|
} else {
|
||||||
|
x--;
|
||||||
|
radius_error += 2 * (y - x + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 get_resolution(SDL_Renderer* renderer, Vector2 size)
|
||||||
|
{
|
||||||
|
SDL_Rect viewport;
|
||||||
|
Vector2 resolution;
|
||||||
|
bool darker_color = false;
|
||||||
|
SDL_GetRenderViewport(renderer, &viewport);
|
||||||
|
resolution.x = viewport.w / size.x;
|
||||||
|
resolution.y = viewport.h / size.y;
|
||||||
|
return resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_grid(SDL_Renderer* target, Vector2 size)
|
||||||
|
{
|
||||||
|
Vector2 resolution = get_resolution(target, size);
|
||||||
|
bool darker_color = false;
|
||||||
|
for (int i = 0; i < size.x; i++) {
|
||||||
|
for (int j = 0; j < size.y; j++) {
|
||||||
|
SDL_FRect rectangle;
|
||||||
|
rectangle.x = resolution.x * i;
|
||||||
|
rectangle.y = resolution.y * j;
|
||||||
|
rectangle.w = resolution.x;
|
||||||
|
rectangle.h = resolution.y;
|
||||||
|
if (darker_color) {
|
||||||
|
set_color(target, dark_green);
|
||||||
|
} else {
|
||||||
|
set_color(target, light_green);
|
||||||
|
}
|
||||||
|
SDL_RenderFillRect(target, &rectangle);
|
||||||
|
darker_color = !darker_color;
|
||||||
|
}
|
||||||
|
darker_color = !darker_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_mines(SDL_Renderer* target, Board board)
|
||||||
|
{
|
||||||
|
set_color(target, black);
|
||||||
|
Vector2 resolution = get_resolution(target, board.bounds);
|
||||||
|
int radius = resolution.x / 4;
|
||||||
|
for (int i = 0; i < board.bounds.x; i++) {
|
||||||
|
// SDL_Log("i: %d", i);
|
||||||
|
for (int j = 0; j < board.bounds.y; j++) {
|
||||||
|
// SDL_Log("j: %d", j);
|
||||||
|
if (!board.cells[i][j].has_mine) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Vector2 position = {
|
||||||
|
resolution.x * i + resolution.x / 2,
|
||||||
|
resolution.y * j + resolution.y / 2
|
||||||
|
};
|
||||||
|
draw_circle(target, position, radius);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_flags(SDL_Renderer* target, Board board)
|
||||||
|
{
|
||||||
|
set_color(target, red);
|
||||||
|
Vector2 resolution = get_resolution(target, board.bounds);
|
||||||
|
int radius = resolution.x / 4;
|
||||||
|
for (int i = 0; i < board.bounds.x; i++) {
|
||||||
|
// SDL_Log("i: %d", i);
|
||||||
|
for (int j = 0; j < board.bounds.y; j++) {
|
||||||
|
// SDL_Log("j: %d", j);
|
||||||
|
if (!board.cells[i][j].has_flag) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Vector2 position = {
|
||||||
|
resolution.x * i + resolution.x / 2,
|
||||||
|
resolution.y * j + resolution.y / 2
|
||||||
|
};
|
||||||
|
draw_circle(target, position, radius);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_hover(SDL_Renderer* target, Board board)
|
||||||
|
{
|
||||||
|
Vector2 resolution = get_resolution(target, board.bounds);
|
||||||
|
set_color(target, hover_dark_green);
|
||||||
|
SDL_FRect rectangle;
|
||||||
|
rectangle.x = resolution.x * board.hover.x;
|
||||||
|
rectangle.y = resolution.y * board.hover.y;
|
||||||
|
rectangle.w = resolution.x;
|
||||||
|
rectangle.h = resolution.y;
|
||||||
|
SDL_RenderFillRect(target, &rectangle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_revealed(SDL_Renderer* target, Board board)
|
||||||
|
{
|
||||||
|
set_color(target, red);
|
||||||
|
Vector2 resolution = get_resolution(target, board.bounds);
|
||||||
|
int radius = resolution.x / 4;
|
||||||
|
bool darker_color = true;
|
||||||
|
for (int i = 0; i < board.bounds.x; i++) {
|
||||||
|
// SDL_Log("i: %d", i);
|
||||||
|
for (int j = 0; j < board.bounds.y; j++) {
|
||||||
|
// SDL_Log("j: %d", j);
|
||||||
|
darker_color = !darker_color;
|
||||||
|
if (!board.cells[i][j].is_revealed) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SDL_FRect rectangle;
|
||||||
|
rectangle.x = resolution.x * i;
|
||||||
|
rectangle.y = resolution.y * j;
|
||||||
|
rectangle.w = resolution.x;
|
||||||
|
rectangle.h = resolution.y;
|
||||||
|
if (darker_color) {
|
||||||
|
set_color(target, dark_yellow);
|
||||||
|
} else {
|
||||||
|
set_color(target, light_yellow);
|
||||||
|
}
|
||||||
|
SDL_RenderFillRect(target, &rectangle);
|
||||||
|
}
|
||||||
|
darker_color = !darker_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_numbers(SDL_Renderer* target, Board* board)
|
||||||
|
{
|
||||||
|
set_color(target, black);
|
||||||
|
Vector2 resolution = get_resolution(target, board->bounds);
|
||||||
|
int radius = resolution.x / 4;
|
||||||
|
for (int i = 0; i < board->bounds.x; i++) {
|
||||||
|
for (int j = 0; j < board->bounds.y; j++) {
|
||||||
|
Vector2 position = { i, j };
|
||||||
|
char text[2] = { get_cell(board, &position)->revealed_value, '\0' };
|
||||||
|
if (text[0] < 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
text[0] += '0';
|
||||||
|
int x = resolution.x * i + resolution.x / 2;
|
||||||
|
int y = resolution.y * j + resolution.y / 2;
|
||||||
|
SDL_RenderDebugText(target, x, y, text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
115
src/main.c
Normal file
115
src/main.c
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
#include "board.h"
|
||||||
|
#include "graphics.h"
|
||||||
|
|
||||||
|
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3/SDL_main.h>
|
||||||
|
|
||||||
|
const int GRID_WIDTH = 18;
|
||||||
|
const int GRID_HEIGHT = 14;
|
||||||
|
const int CELL_RESOLUTION = 30;
|
||||||
|
const Vector2 BOARD_SIZE = { 18, 14 };
|
||||||
|
const int MINE_COUNT = 40;
|
||||||
|
|
||||||
|
static SDL_Window* window = NULL;
|
||||||
|
static SDL_Renderer* renderer = NULL;
|
||||||
|
static Board board;
|
||||||
|
static Vector2 resolution = { -1, -1 };
|
||||||
|
static bool debug_draw_mines = false;
|
||||||
|
|
||||||
|
SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
||||||
|
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
|
||||||
|
return SDL_APP_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_CreateWindowAndRenderer("minesweeper", GRID_WIDTH * CELL_RESOLUTION, GRID_HEIGHT * CELL_RESOLUTION, 0, &window, &renderer);
|
||||||
|
|
||||||
|
SDL_Log("created renderer");
|
||||||
|
SDL_Rect vp;
|
||||||
|
bool status = SDL_GetRenderViewport(renderer, &vp);
|
||||||
|
if (status)
|
||||||
|
SDL_Log("x: %d, y: %d", vp.w, vp.h);
|
||||||
|
else
|
||||||
|
SDL_Log("couldn't get vp");
|
||||||
|
|
||||||
|
Vector2 grid_bounds = { GRID_WIDTH, GRID_HEIGHT };
|
||||||
|
SDL_Log("generating board");
|
||||||
|
board = generate_board(grid_bounds, MINE_COUNT);
|
||||||
|
SDL_Log("generated board");
|
||||||
|
|
||||||
|
resolution = get_resolution(renderer, board.bounds);
|
||||||
|
return SDL_APP_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
|
||||||
|
{
|
||||||
|
switch (event->type) {
|
||||||
|
case SDL_EVENT_QUIT:
|
||||||
|
return SDL_APP_SUCCESS;
|
||||||
|
case SDL_EVENT_MOUSE_MOTION:
|
||||||
|
board.hover.x = event->motion.x / resolution.x;
|
||||||
|
board.hover.y = event->motion.y / resolution.y;
|
||||||
|
// SDL_Log("%d %d", mouse_position.x, mouse_position.y);
|
||||||
|
break;
|
||||||
|
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||||
|
if (event->button.button == 3) {
|
||||||
|
right_click(&board);
|
||||||
|
} else if (event->button.button == 1) {
|
||||||
|
left_click(&board);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_EVENT_KEY_DOWN:
|
||||||
|
if (event->key.key == SDLK_H) {
|
||||||
|
// debug_draw_mines = !debug_draw_mines;
|
||||||
|
}
|
||||||
|
if (event->key.key == SDLK_UP) {
|
||||||
|
Vector2 position = { 0, -1 };
|
||||||
|
shift_board(&board, &position);
|
||||||
|
}
|
||||||
|
if (event->key.key == SDLK_DOWN) {
|
||||||
|
Vector2 position = { 0, 1 };
|
||||||
|
shift_board(&board, &position);
|
||||||
|
}
|
||||||
|
if (event->key.key == SDLK_LEFT) {
|
||||||
|
Vector2 position = { -1, 0 };
|
||||||
|
shift_board(&board, &position);
|
||||||
|
}
|
||||||
|
if (event->key.key == SDLK_RIGHT) {
|
||||||
|
Vector2 position = { 1, 0 };
|
||||||
|
shift_board(&board, &position);
|
||||||
|
}
|
||||||
|
if (event->key.key == SDLK_R) {
|
||||||
|
destroy_board(board);
|
||||||
|
Vector2 grid_bounds = { GRID_WIDTH, GRID_HEIGHT };
|
||||||
|
board = generate_board(grid_bounds, MINE_COUNT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SDL_APP_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_AppResult SDL_AppIterate(void* appstate)
|
||||||
|
{
|
||||||
|
SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
|
draw_grid(renderer, BOARD_SIZE);
|
||||||
|
draw_hover(renderer, board);
|
||||||
|
draw_revealed(renderer, board);
|
||||||
|
draw_flags(renderer, board);
|
||||||
|
if (board.game_over || debug_draw_mines) {
|
||||||
|
draw_mines(renderer, board);
|
||||||
|
}
|
||||||
|
draw_numbers(renderer, &board);
|
||||||
|
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
|
||||||
|
return SDL_APP_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDL_AppQuit(void* appstate, SDL_AppResult result)
|
||||||
|
{
|
||||||
|
destroy_board(board);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue