200 lines
3.5 KiB
C
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);
|
|
}
|
|
}
|