From 8f3177ab054f573a16ce2d83ef7f9426fb5dc914 Mon Sep 17 00:00:00 2001 From: Matthew Kousoulas Date: Tue, 2 Jan 2024 21:59:27 -0500 Subject: [PATCH] Initial Commit --- Makefile | 29 +++++++++ src/board.c | 104 +++++++++++++++++++++++++++++ src/board.h | 27 ++++++++ src/main.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/term.c | 54 ++++++++++++++++ src/term.h | 13 ++++ src/util.c | 10 +++ src/util.h | 7 ++ 8 files changed, 427 insertions(+) create mode 100644 Makefile create mode 100644 src/board.c create mode 100644 src/board.h create mode 100644 src/main.c create mode 100644 src/term.c create mode 100644 src/term.h create mode 100644 src/util.c create mode 100644 src/util.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b3344ba --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +TARGET := rogue +BIN_DIR := . +BUILD_DIR := ./build +SRC_DIR := ./src + +SRC := $(shell find $(SRC_DIR) -name '*.c') +OBJ := $(SRC:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) +DEP := $(OBJ:.o=.d) + +CFLAGS := -Wall -Wextra -Wpedantic -pedantic +CPPFLAGS := $(addprefix -I,$(shell find $(SRC_DIR) -type d)) -MMD -MP +LDFLAGS := +LDLIBS := + +.SECONDEXPANSION: +$(BIN_DIR)/$(TARGET): $(OBJ) + $(CC) $(LDFLAGS) $(LDLIBS) $^ -o $@ + +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c + mkdir -p $(BUILD_DIR) + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +-include $(DEP) + +.PHONY: clean +clean: + $(RM) -r $(BUILD_DIR) + $(RM) $(BIN_DIR)/$(TARGET) + diff --git a/src/board.c b/src/board.c new file mode 100644 index 0000000..6111cc7 --- /dev/null +++ b/src/board.c @@ -0,0 +1,104 @@ +#include + +#include "board.h" + +board* make_board(int mines, int width, int height) +{ + board *b = malloc(sizeof(board)); + + b->board_x = width; + b->board_y = height; + b->mines = mines; + b->grid = calloc(width * height, sizeof(tile)); + b->neighbors = calloc(width * height, sizeof(char)); + + for (int n = 0; n < b->mines;) + { + int x = rand() % b->board_x; + int y = rand() % b->board_y; + if (!(b->grid[INDEX(b, x, y)] & MINED)) + { + b->grid[INDEX(b, x, y)] |= MINED; + ++n; + } + } + + for (int x = 0; x < b->board_x; ++x) + for (int y = 0; y < b->board_y; ++y) + { + char c = '0'; + + if (x + 1 < b->board_x) + { + if (y + 1 < b->board_y) + c += b->grid[INDEX(b, x+1, y+1)] & MINED ? 1 : 0; + c += b->grid[INDEX(b, x+1, y)] & MINED ? 1 : 0; + if (y > 0) + c += b->grid[INDEX(b, x+1, y-1)] & MINED ? 1 : 0; + } + if (y + 1 < b->board_y) + c += b->grid[INDEX(b, x, y+1)] & MINED ? 1 : 0; + if (y > 0) + c += b->grid[INDEX(b, x, y-1)] & MINED ? 1 : 0; + if (x > 0) + { + if (y + 1 < b->board_y) + c += b->grid[INDEX(b, x-1, y+1)] & MINED ? 1 : 0; + c += b->grid[INDEX(b, x-1, y)] & MINED ? 1 : 0; + if (y > 0) + c += b->grid[INDEX(b, x-1, y-1)] & MINED ? 1 : 0; + } + + if (c == '0') + c = '.'; + + b->neighbors[INDEX(b, x, y)] = c; + } + + return b; +} + +void destruct_board(board *b) +{ + free(b->grid); + free(b->neighbors); + free(b); +} + +void clear_tile(board *b, int x, int y) +{ + if (x < 0 || x >= b->board_x + || y < 0 || y >= b->board_y) + return; + + tile t = b->grid[INDEX(b, x, y)]; + char n = b->neighbors[INDEX(b, x, y)]; + + /* if (n == '.' && !(t & MINED)) */ + if (1) + { + b->grid[INDEX(b, b->cursor_x, b->cursor_y)] |= CLEARED; + + if (x + 1 < b->board_x) + { + /* if (y + 1 < b->board_y) */ + /* clear_tile(b, x+1, y+1); */ + /* clear_tile(b, x+1, y); */ + /* if (y > 0) */ + /* clear_tile(b, x+1, y-1); */ + } + /* if (y + 1 < b->board_y) */ + /* clear_tile(b, x, y+1); */ + if (y > 0) + clear_tile(b, x, y-1); + if (x > 0) + { + /* if (y + 1 < b->board_y) */ + /* clear_tile(b, x-1, y+1); */ + clear_tile(b, x-1, y); + if (y > 0) + clear_tile(b, x-1, y-1); + } + } +} + diff --git a/src/board.h b/src/board.h new file mode 100644 index 0000000..94eafb1 --- /dev/null +++ b/src/board.h @@ -0,0 +1,27 @@ +#ifndef BOARD_H +#define BOARD_H + +#define CLEARED 0000001 +#define MINED 0000002 +#define FLAGGED 0000004 + +#define INDEX(B, X, Y) (((Y) * B->board_y) + (X)) + +typedef unsigned char tile; + +typedef struct board { + int board_x; + int board_y; + int cursor_x; + int cursor_y; + int mines; + tile *grid; + char *neighbors; +} board; + +board* make_board(int mines, int width, int height); +void destruct_board(board *b); +void clear_tile(board *b, int x, int y); + +#endif + diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..3bf06a3 --- /dev/null +++ b/src/main.c @@ -0,0 +1,183 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "term.h" +#include "board.h" + +typedef enum +{ + nop, + quit, + up, + down, + left, + right, + flag, + clear, +} action; + +action proc_key(char c) +{ + action a; + switch (c) + { + case 'f': + a = flag; + break; + case ' ': + a = clear; + break; + case 'h': + a = left; + break; + case 'j': + a = down; + break; + case 'k': + a = up; + break; + case 'l': + a = right; + break; + case CTRL_KEY('q'): + a = quit; + break; + default: + a = nop; + } + return a; +} + +void take_action(action a, board *b) +{ + switch(a) + { + case nop: + break; + case quit: + exit(0); + break; + case up: + if (b->cursor_y > 0) + b->cursor_y -= 1; + break; + case down: + if (b->cursor_y + 1 < b->board_y) + b->cursor_y += 1; + break; + case left: + if (b->cursor_x > 0) + b->cursor_x -= 1; + break; + case right: + if (b->cursor_x + 1 < b->board_x) + b->cursor_x += 1; + break; + case flag: + b->grid[INDEX(b, b->cursor_x, b->cursor_y)] ^= FLAGGED; + break; + case clear: + clear_tile(b, b->cursor_x, b->cursor_y); + break; + } +} + +void draw_grid(board *b) +{ + for (int y = 0; y < b->board_y; ++y) + { + for (int x = 0; x < b->board_x; ++x) + { + if (x == b->cursor_x && y == b->cursor_y) + WRITE_CTRL("[7m"); + + tile t = b->grid[INDEX(b, x, y)]; + if (t & FLAGGED) + { + write(STDOUT_FILENO, "?", 1); + } + else if (t & CLEARED) + { + if (t & MINED) + { + write(STDOUT_FILENO, "*", 1); + } + else + { + write(STDOUT_FILENO, b->neighbors + INDEX(b, x, y), 1); + } + } + else + { + write(STDOUT_FILENO, "#", 1); + } + + if (x == b->cursor_x && y == b->cursor_y) + WRITE_CTRL("[27m"); + } + write(STDOUT_FILENO, "\n\r", 2); + } + + write(STDOUT_FILENO, "\n\rDebug: ", 9); + + char buf[16]; + sprintf(buf, "(%d,%d) %d", b->cursor_x, b->cursor_y, INDEX(b, b->cursor_x, b->cursor_y)); + write(STDOUT_FILENO, buf, 16); + + write(STDOUT_FILENO, "\n\r\n\r", 4); + + int x = b->cursor_x; + int y = b->cursor_y; + + if (x + 1 < b->board_x) + { + if (y + 1 < b->board_y) + write(STDOUT_FILENO, "1", 1); + write(STDOUT_FILENO, "2", 1); + if (y > 0) + write(STDOUT_FILENO, "3", 1); + } + if (y + 1 < b->board_y) + write(STDOUT_FILENO, "4", 1); + if (y > 0) + write(STDOUT_FILENO, "5", 1); + if (x > 0) + { + if (y + 1 < b->board_y) + write(STDOUT_FILENO, "6", 1); + write(STDOUT_FILENO, "7", 1); + if (y > 0) + write(STDOUT_FILENO, "8", 1); + } +} + +int main(int argc, char** argv) +{ + init_term(); + srand(time(NULL)); + + board *b = make_board(10, 10, 10); + + char c = '\0'; + action a = nop; + + while (true) + { + clear_screen(); + draw_grid(b); + + c = read_key(); + a = proc_key(c); + take_action(a, b); + } + + destruct_board(b); + + return argc; +} diff --git a/src/term.c b/src/term.c new file mode 100644 index 0000000..29d7b95 --- /dev/null +++ b/src/term.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include + +#include "term.h" +#include "util.h" + +struct termios orig_termios; +void reset_term() +{ + tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios); + WRITE_CTRL("[?47l"); + WRITE_CTRL("8"); +} + +void init_term() +{ + tcgetattr(STDIN_FILENO, &orig_termios); + atexit(reset_term); + + struct termios raw = orig_termios; + raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + raw.c_oflag &= ~(OPOST); + raw.c_cflag |= (CS8); + raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + raw.c_cc[VMIN] = 0; + raw.c_cc[VTIME] = 1; + + tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw); + + WRITE_CTRL("[2J"); + WRITE_CTRL("[H"); + WRITE_CTRL("7"); + WRITE_CTRL("[?47h"); +} + +char read_key() +{ + int nread; + char c; + /* nread = read(STDIN_FILENO, &c, 1); */ + while ((nread = read(STDIN_FILENO, &c, 1)) != 1) + if (nread == -1 && errno != EAGAIN) die("read"); + + return c; +} + +void clear_screen() +{ + WRITE_CTRL("[2J"); + WRITE_CTRL("[H"); +} + diff --git a/src/term.h b/src/term.h new file mode 100644 index 0000000..1fa08aa --- /dev/null +++ b/src/term.h @@ -0,0 +1,13 @@ +#ifndef TERM_H +#define TERM_H + +#define ESC(S) "\x1b" S +#define WRITE_CTRL(S) write(STDOUT_FILENO, ESC(S), sizeof (S)) +#define CTRL_KEY(K) ((K) & 0x1f) + +void reset_term(); +void init_term(); +char read_key(); +void clear_screen(); + +#endif diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..4e033e3 --- /dev/null +++ b/src/util.c @@ -0,0 +1,10 @@ +#include +#include + +#include "util.h" + +void die(const char* s) +{ + perror(s); + exit(1); +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..7e3071b --- /dev/null +++ b/src/util.h @@ -0,0 +1,7 @@ +#ifndef UTIL_H +#define UTIL_H + +void die(const char* s); + +#endif + -- 2.45.3