sandbox/sandbox.c
2025-04-27 09:05:51 +00:00

200 lines
3.5 KiB
C

#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <ncurses.h>
#include <sys/ioctl.h>
enum {
COLOR_FONT,
COLOR_SAND
};
enum {
ADD,
UNDO
};
struct SAND {
int x;
int y;
};
WINDOW *win;
struct winsize w_size;
int px = 1, py = 1;
struct SAND *sand_array;
size_t array_index;
void clear_scr(WINDOW *win) {
clear();
refresh();
if (win != NULL) {
wclear(win);
wrefresh(win);
}
}
void clean_up(int sig) {
if (sig == SIGWINCH) {
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w_size) < 0)
perror("TIOCGWINSZ");
if (px >= w_size.ws_col)
px = w_size.ws_col - 2;
if (py >= w_size.ws_row)
py = w_size.ws_row - 2;
endwin();
initscr();
delwin(win);
win = newwin(w_size.ws_row, w_size.ws_col, 0, 0);
}
else {
clear_scr(win);
delwin(win);
endwin();
if (sand_array != NULL)
free(sand_array);
exit((sig == -1) ? 1 : 0);
}
}
int placed_on(int y, int x) {
for (size_t i = 0; i < array_index; i++)
if (sand_array[i].y == y && sand_array[i].x == x)
return i;
return -1;
}
void sand_ctl(char flag) {
if (sand_array == NULL) {
sand_array = malloc(sizeof(struct SAND));
if (sand_array == NULL) {
perror("malloc");
clean_up(-1);
}
}
if (flag == UNDO && array_index > 0) {
array_index--;
if (array_index == 0) {
free(sand_array);
sand_array = NULL;
return;
}
}
else if (flag == ADD) {
for (size_t i = 0; i < array_index; i++)
if (sand_array[i].x == px && sand_array[i].y == py)
return;
array_index++;
}
struct SAND *tmp = realloc(sand_array, array_index * sizeof(struct SAND));
if (tmp == NULL) {
perror("realloc");
clean_up(-1);
}
if (flag == ADD) {
tmp[array_index - 1].x = px;
tmp[array_index - 1].y = py;
}
sand_array = tmp;
}
void move_sand(void) {
for (size_t i = 0; i < array_index; i++) {
if (placed_on(sand_array[i].y + 1, sand_array[i].x) == -1 && sand_array[i].y < w_size.ws_row - 2)
sand_array[i].y++;
else if (sand_array[i].y < w_size.ws_row - 3) {
if (sand_array[i].x + 1 < w_size.ws_col - 1 && placed_on(sand_array[i].y + 1, sand_array[i].x + 1) == -1)
sand_array[i].x++;
else if (sand_array[i].x - 1 > 0 && placed_on(sand_array[i].y + 1, sand_array[i].x - 1) == -1)
sand_array[i].x--;
}
}
}
void draw(void) {
wattron(win, COLOR_PAIR(COLOR_FONT));
for (size_t y = 1; y < w_size.ws_row - 1; y++)
for (size_t x = 1; x < w_size.ws_col - 1; x++)
if (!(x % 2))
mvwprintw(win, y, x, ".");
mvwprintw(win, py, px, "+");
wattroff(win, COLOR_PAIR(COLOR_FONT));
wattron(win, COLOR_PAIR(COLOR_SAND));
for (size_t i = 0; i < array_index; i++)
mvwprintw(win, sand_array[i].y, sand_array[i].x, "#");
wattroff(win, COLOR_PAIR(COLOR_SAND));
box(win, 0, 0);
wrefresh(win);
}
int main(void) {
signal(SIGINT, clean_up);
signal(SIGWINCH, clean_up);
initscr();
noecho();
cbreak();
curs_set(0);
timeout(1000);
keypad(stdscr, TRUE);
if (has_colors() == FALSE) {
endwin();
fputs("Your terminal does not support color", stderr);
exit(1);
}
start_color();
init_pair(COLOR_FONT, COLOR_RED, COLOR_BLACK);
init_pair(COLOR_SAND, COLOR_YELLOW, COLOR_YELLOW);
/* Init screen size */
clean_up(SIGWINCH);
while (1) {
clear_scr(win);
move_sand();
draw();
int k = getch();
if (k == KEY_UP && py - 1 > 0)
py--;
else if (k == KEY_DOWN && py + 1 < w_size.ws_row - 1)
py++;
else if (k == KEY_RIGHT && px + 1 < w_size.ws_col - 1)
px++;
else if (k == KEY_LEFT && px - 1 > 0)
px--;
else if (k == ' ')
sand_ctl(ADD);
else if (k == 'u')
sand_ctl(UNDO);
}
}