commit b234ed5039dfd96005138828ece341da3638d216
parent 7a164b1a54368a57b92b5e920bcb2f74db2d9c5f
Author: Sophie <info@soophie.de>
Date: Tue, 13 May 2025 13:07:42 +0000
feat: Windows support & small improvements
Diffstat:
M | Makefile | | | 27 | ++++++++++++++++++++------- |
M | src/main.c | | | 102 | +++++++++++++++++++++++++++++++++++++++++-------------------------------------- |
2 files changed, 73 insertions(+), 56 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,10 +1,23 @@
-CC=cc
-CLFAGS=-Wall -Wextra -Werror -pendatic
-LIBS=-lm
-TARGET=cmine
+TARGET = cmine
+SOURCE := $(wildcard src/*.c)
-build: src/*.c
- $(CC) $(CFLAGS) -o $(TARGET) $^ $(LIBS)
+POSIX_CC = cc
+POSIX_CFLAGS = -Wall -Wextra -Werror -pedantic
+POSIX_LIBS = -lm
+
+WINDOWS_CC = x86_64-w64-mingw32-gcc
+WINDOWS_CFLAGS = -Wall -Wextra -Werror -pedantic
+WINDOWS_LIBS = -static -lm -I/usr/local/include/
+
+.PHONY: all build-posix build-windows clean
+
+all: build-posix
+
+build-posix:
+ $(POSIX_CC) $(POSIX_CFLAGS) -o $(TARGET) -DLIB_TERM_POSIX $(SOURCE) $(POSIX_LIBS)
+
+build-windows:
+ $(WINDOWS_CC) $(WINDOWS_CFLAGS) -o $(TARGET).exe -DLIB_TERM_WINDOWS $(SOURCE) $(WINDOWS_LIBS)
clean:
- rm ./$(TARGET)
+ rm -f ./$(TARGET) ./$(TARGET).exe
diff --git a/src/main.c b/src/main.c
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include <getopt.h>
+#include <time.h>
#define LIB_TERM_IMPL
#include <libterm.h>
@@ -59,7 +60,6 @@ static level_t LEVEL_EASY = { "EASY", 9, 9, 10 };
static level_t LEVEL_MEDIUM = { "MEDIUM", 16, 16, 40 };
static level_t LEVEL_HARD = { "HARD", 16, 30, 99 };
-static const u32_t COLOR_NONE = 0x000000;
static const u32_t COLOR_CURSOR = 0xffffff;
static const u32_t COLOR_COVER = 0xcccccc;
static const u32_t COLOR_BOMB = 0xff0000;
@@ -76,11 +76,11 @@ static const u32_t COLOR_DIGITS[9] = {
0xaaaaaa,
};
-int is_valid(cmine_t *self, int y, int x) {
+int cm_is_valid(cmine_t *self, int y, int x) {
return y >= 0 && y < self->size.y && x >= 0 && x < self->size.x;
}
-int is_flag(u8_t cell, int flag) {
+int cm_is_flag(u8_t cell, int flag) {
return (cell & flag) != 0;
}
@@ -88,16 +88,16 @@ u8_t *cell_at(cmine_t *self, int y, int x) {
return &self->board[y * self->size.x + x];
}
-void victory(cmine_t *self) {
+void cm_victory(cmine_t *self) {
self->state = STATE_VICTORY;
// flag all bombs
for (int y = 0; y < self->size.y; y++) {
for (int x = 0; x < self->size.x; x++) {
u8_t *cell = cell_at(self, y, x);
- if (!is_flag(*cell, FLAG_BOMB)) {
+ if (!cm_is_flag(*cell, FLAG_BOMB)) {
continue;
}
- if (is_flag(*cell, FLAG_FLAG)) {
+ if (cm_is_flag(*cell, FLAG_FLAG)) {
continue;
}
*cell |= FLAG_FLAG;
@@ -106,16 +106,16 @@ void victory(cmine_t *self) {
}
}
-void defeat(cmine_t *self) {
+void cm_defeat(cmine_t *self) {
self->state = STATE_DEFEAT;
// reveal all bombs
for (int y = 0; y < self->size.y; y++) {
for (int x = 0; x < self->size.x; x++) {
u8_t *cell = cell_at(self, y, x);
- if (!is_flag(*cell, FLAG_BOMB)) {
+ if (!cm_is_flag(*cell, FLAG_BOMB)) {
continue;
}
- if (is_flag(*cell, FLAG_OPEN)) {
+ if (cm_is_flag(*cell, FLAG_OPEN)) {
continue;
}
*cell |= FLAG_OPEN;
@@ -124,18 +124,18 @@ void defeat(cmine_t *self) {
}
}
-void open(cmine_t *self, int y, int x) {
+void cm_open(cmine_t *self, int y, int x) {
if (self->state != STATE_PLAYING) {
return;
}
u8_t *cell = cell_at(self, y, x);
// ignore flags
- if (is_flag(*cell, FLAG_FLAG)) {
+ if (cm_is_flag(*cell, FLAG_FLAG)) {
return;
}
// handle open cells
// chord opening
- if (is_flag(*cell, FLAG_OPEN)) {
+ if (cm_is_flag(*cell, FLAG_OPEN)) {
int digit = *cell & MASK_DIGIT;
if (digit == 0) {
return;
@@ -143,14 +143,14 @@ void open(cmine_t *self, int y, int x) {
int flags = 0;
for (int ly = -1; ly <= 1; ly++) {
for (int lx = -1; lx <= 1; lx++) {
- if (!is_valid(self, y + ly, x + lx)) {
+ if (!cm_is_valid(self, y + ly, x + lx)) {
continue;
}
if (ly == 0 && lx == 0) {
continue;
}
u8_t *l_cell = cell_at(self, y + ly, x + lx);
- if (is_flag(*l_cell, FLAG_FLAG)) {
+ if (cm_is_flag(*l_cell, FLAG_FLAG)) {
flags++;
}
}
@@ -158,15 +158,15 @@ void open(cmine_t *self, int y, int x) {
if (flags == digit) {
for (int ly = -1; ly <= 1; ly++) {
for (int lx = -1; lx <= 1; lx++) {
- if (!is_valid(self, y + ly, x + lx)) {
+ if (!cm_is_valid(self, y + ly, x + lx)) {
continue;
}
if (ly == 0 && lx == 0) {
continue;
}
u8_t *l_cell = cell_at(self, y + ly, x + lx);
- if (!is_flag(*l_cell, FLAG_OPEN)) {
- open(self, y + ly, x + lx);
+ if (!cm_is_flag(*l_cell, FLAG_OPEN)) {
+ cm_open(self, y + ly, x + lx);
}
}
}
@@ -177,8 +177,8 @@ void open(cmine_t *self, int y, int x) {
*cell |= FLAG_OPEN;
*cell |= FLAG_DIRTY;
// check if bomb
- if (is_flag(*cell, FLAG_BOMB)) {
- defeat(self);
+ if (cm_is_flag(*cell, FLAG_BOMB)) {
+ cm_defeat(self);
return;
}
int digit = *cell & MASK_DIGIT;
@@ -186,13 +186,13 @@ void open(cmine_t *self, int y, int x) {
if (digit == 0) {
for (int ly = -1; ly <= 1; ly++) {
for (int lx = -1; lx <= 1; lx++) {
- if (!is_valid(self, y + ly, x + lx)) {
+ if (!cm_is_valid(self, y + ly, x + lx)) {
continue;
}
if (ly == 0 && lx == 0) {
continue;
}
- open(self, y + ly, x + lx);
+ cm_open(self, y + ly, x + lx);
}
}
}
@@ -201,26 +201,26 @@ void open(cmine_t *self, int y, int x) {
for (int y = 0; y < self->size.y; y++) {
for (int x = 0; x < self->size.x; x++) {
u8_t *l_cell = cell_at(self, y, x);
- if (!is_flag(*l_cell, FLAG_BOMB) && !is_flag(*l_cell, FLAG_OPEN)) {
+ if (!cm_is_flag(*l_cell, FLAG_BOMB) && !cm_is_flag(*l_cell, FLAG_OPEN)) {
return;
}
}
}
- victory(self);
+ cm_victory(self);
}
-void flag(cmine_t *self, int y, int x) {
+void cm_flag(cmine_t *self, int y, int x) {
if (self->state != STATE_PLAYING) {
return;
}
u8_t *cell = cell_at(self, y, x);
// ignore open
- if (is_flag(*cell, FLAG_OPEN)) {
+ if (cm_is_flag(*cell, FLAG_OPEN)) {
return;
}
*cell |= FLAG_DIRTY;
// unset flag
- if (is_flag(*cell, FLAG_FLAG)) {
+ if (cm_is_flag(*cell, FLAG_FLAG)) {
*cell &= ~FLAG_FLAG;
self->count++;
}
@@ -231,11 +231,11 @@ void flag(cmine_t *self, int y, int x) {
}
}
-void move(cmine_t *self, int dy, int dx) {
+void cm_move(cmine_t *self, int dy, int dx) {
if (self->state != STATE_PLAYING) {
return;
}
- if (!is_valid(self, self->cursor.y + dy, self->cursor.x + dx)) {
+ if (!cm_is_valid(self, self->cursor.y + dy, self->cursor.x + dx)) {
return;
}
*cell_at(self, self->cursor.y, self->cursor.x) |= FLAG_DIRTY;
@@ -243,7 +243,7 @@ void move(cmine_t *self, int dy, int dx) {
*cell_at(self, self->cursor.y, self->cursor.x) |= FLAG_DIRTY;
}
-void generate(cmine_t *self, level_t level, int seed) {
+void cm_generate(cmine_t *self, level_t level, int seed) {
// init self
(*self) = (cmine_t) {
.state = STATE_PLAYING,
@@ -271,7 +271,7 @@ void generate(cmine_t *self, level_t level, int seed) {
int y = rand() % self->size.y;
int x = rand() % self->size.x;
u8_t *cell = cell_at(self, y, x);
- if (!is_flag(*cell, FLAG_BOMB)) {
+ if (!cm_is_flag(*cell, FLAG_BOMB)) {
*cell |= FLAG_BOMB;
bombs--;
}
@@ -282,14 +282,14 @@ void generate(cmine_t *self, level_t level, int seed) {
u8_t *cell = cell_at(self, y, x);
for (int ly = -1; ly <= 1; ly++) {
for (int lx = -1; lx <= 1; lx++) {
- if (!is_valid(self, y + ly, x + lx)) {
+ if (!cm_is_valid(self, y + ly, x + lx)) {
continue;
}
if (ly == 0 && lx == 0) {
continue;
}
u8_t *l_cell = cell_at(self, y + ly, x + lx);
- if (is_flag(*l_cell, FLAG_BOMB)) {
+ if (cm_is_flag(*l_cell, FLAG_BOMB)) {
(*cell)++;
}
}
@@ -303,7 +303,7 @@ void generate(cmine_t *self, level_t level, int seed) {
for (int x = 0; x < self->size.x; x++) {
u8_t *cell = cell_at(self, y, x);
int digit = *cell & MASK_DIGIT;
- if (is_flag(*cell, FLAG_BOMB) || digit != 0) {
+ if (cm_is_flag(*cell, FLAG_BOMB) || digit != 0) {
continue;
}
count++;
@@ -319,15 +319,15 @@ void generate(cmine_t *self, level_t level, int seed) {
}
self->cursor = sel;
// uncover starting position
- open(self, self->cursor.y, self->cursor.x);
+ cm_open(self, self->cursor.y, self->cursor.x);
}
-void update(term_t *term, cmine_t *self) {
+void cm_update(term_t *term, cmine_t *self) {
// check window resize
size_t new_height;
size_t new_width;
term_read_window(term, &new_height, &new_width);
- int is_resize = new_height != self->window.y || new_width != self->window.x;
+ int is_resize = (int) new_height != self->window.y || (int) new_width != self->window.x;
term_write(term, "\x1b[?25l");
if (is_resize) {
self->window = (vec2_t) { new_height, new_width };
@@ -354,17 +354,17 @@ void update(term_t *term, cmine_t *self) {
for (int x = 0; x < self->size.x; x++) {
u8_t *cell = cell_at(self, y, x);
// ignore non-dirty cells
- if (!is_resize && !is_flag(*cell, FLAG_DIRTY)) {
+ if (!is_resize && !cm_is_flag(*cell, FLAG_DIRTY)) {
continue;
}
*cell &= ~ FLAG_DIRTY;
// determine color and symbol
- int is_bomb = is_flag(*cell, FLAG_BOMB);
- int is_open = is_flag(*cell, FLAG_OPEN);
+ int is_bomb = cm_is_flag(*cell, FLAG_BOMB);
+ int is_open = cm_is_flag(*cell, FLAG_OPEN);
int digit = *cell & MASK_DIGIT;
char symbol = '?';
u32_t color = COLOR_COVER;
- if (!is_open && is_flag(*cell, FLAG_FLAG)) {
+ if (!is_open && cm_is_flag(*cell, FLAG_FLAG)) {
symbol = 'F';
color = COLOR_FLAG;
}
@@ -434,41 +434,45 @@ int main(int argc, char *argv[]) {
term_t term = term_init();
term_rawmode_enable(&term);
cmine_t self;
- generate(&self, *level, seed);
+ cm_generate(&self, *level, seed);
term_write(&term, "\x1b[?1049h");
term_flush(&term);
int quit = 0;
while (!quit) {
- update(&term, &self);
+ cm_update(&term, &self);
int key = term_poll_key(&term, 100);
switch (key) {
case 'q':
quit = 1;
break;
case KEY_ESC:
- generate(&self, *level, ++seed);
+ cm_generate(&self, *level, ++seed);
break;
case 'j':
- move(&self, 1, 0);
+ case KEY_ARROW_DOWN:
+ cm_move(&self, 1, 0);
break;
case 'k':
- move(&self, -1, 0);
+ case KEY_ARROW_UP:
+ cm_move(&self, -1, 0);
break;
case 'l':
- move(&self, 0, 1);
+ case KEY_ARROW_RIGHT:
+ cm_move(&self, 0, 1);
break;
case 'h':
- move(&self, 0, -1);
+ case KEY_ARROW_LEFT:
+ cm_move(&self, 0, -1);
break;
case ' ':
// start timer
if (self.time == -1) {
self.time = time(NULL);
}
- open(&self, self.cursor.y, self.cursor.x);
+ cm_open(&self, self.cursor.y, self.cursor.x);
break;
case 'f':
- flag(&self, self.cursor.y, self.cursor.x);
+ cm_flag(&self, self.cursor.y, self.cursor.x);
break;
default:
break;