From 96e64b9d6984629ae602db2a47e9f49425f262d4 Mon Sep 17 00:00:00 2001 From: Sadeep Madurange Date: Sun, 31 Jul 2022 17:06:30 +0800 Subject: Initial commit. --- src/main.c | 261 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 src/main.c (limited to 'src') diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..338cc3a --- /dev/null +++ b/src/main.c @@ -0,0 +1,261 @@ +#define _XOPEN_SOURCE 700 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ANSI_COL_DROP "\x1b[97m" +#define ANSI_CUR_HIDE "\e[?25l" +#define ANSI_CUR_SHOW "\e[?25h" +#define ANSI_CUR_RESET "\x1b[H" +#define ANSI_SCRN_CLEAR "\x1b[2J" +#define ANSI_FONT_RESET "\x1b[0m" + +typedef struct matrix_tag { + int rows; + int cols; + wchar_t *code; +} matrix; + +static int mat_index(const matrix *mat, int row, int col) { + return mat->cols * row + col; +} + +static int mat_init(matrix *mat, struct winsize *ws) { + int i, j; + + static wchar_t code[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; + + static int codelen = sizeof(code) / sizeof(code[0]); + + mat->rows = ws->ws_row + 1; + mat->cols = ws->ws_col; + mat->code = realloc(mat->code, sizeof mat->code[0] * mat->rows * mat->cols); + if (mat->code) { + for (i = 0; i < mat->rows; i++) { + for (j = 0; j < mat->cols; j++) + mat->code[mat_index(mat, i, j)] = code[rand() % codelen]; + } + return 1; + } + return 0; +} + +typedef struct table_tag { + int len; // number of columns + int *cols; // column indices + int *rows; // row indices ((rows[i], cols[i]) points to a cell in the matrix) + int *attr; // cell attributes +} table; + +static void shuffle(int *a, int n) { + int i, j, tmp; + + for (i = n - 1; i > 0; i--) { + j = rand() % (i + 1); + tmp = a[j]; + a[j] = a[i]; + a[i] = tmp; + } +} + +static int tab_init(table *tab, const matrix *mat) { + size_t i; + + tab->len = mat->cols; + tab->cols = realloc(tab->cols, sizeof tab->cols[0] * tab->len); + tab->rows = realloc(tab->rows, sizeof tab->rows[0] * tab->len); + tab->attr = realloc(tab->attr, sizeof tab->attr[0] * tab->len); + + if (tab->cols && tab->rows && tab->attr) { + for (i = 0; i < mat->cols; i++) { + tab->rows[i] = 0; + tab->cols[i] = i; + tab->attr[i] = 0; + } + shuffle(tab->cols, tab->len); + return 1; + } + return 0; +} + +static void tab_free(table *tab) { + free(tab->cols); + free(tab->rows); + free(tab->attr); +} + +static int term_init() { + struct termios ta; + + if (tcgetattr(STDIN_FILENO, &ta) == 0) { + ta.c_lflag &= ~ECHO; + if (tcsetattr(STDIN_FILENO, TCSANOW, &ta) == 0) { + wprintf(L"%s", ANSI_CUR_HIDE); + wprintf(L"%s", ANSI_CUR_RESET); + wprintf(L"%s", ANSI_SCRN_CLEAR); + setvbuf(stdout, 0, _IOFBF, 0); + return 1; + } + } + return 0; +} + +static void term_reset() { + struct termios ta; + + wprintf(L"%s", ANSI_FONT_RESET); + wprintf(L"%s", ANSI_CUR_SHOW); + wprintf(L"%s", ANSI_SCRN_CLEAR); + wprintf(L"%s", ANSI_CUR_RESET); + + if (tcgetattr(STDIN_FILENO, &ta) == 0) { + ta.c_lflag |= ECHO; + if (tcsetattr(STDIN_FILENO, TCSANOW, &ta) != 0) + perror("term_reset()"); + } + setvbuf(stdout, 0, _IOLBF, 0); +} + +static void term_size(struct winsize *ws) { + ioctl(STDOUT_FILENO, TIOCGWINSZ, ws); +} + +static void term_clear_cell(int row, int col) { + wprintf(L"\x1b[%d;%dH ", row, col); +} + +static void term_reset_cell(const matrix *mat, int row, int col) { + wprintf(L"\x1b[%d;%dH\x1b[39m%lc", row, col, + mat->code[mat_index(mat, row, col)]); +} + +static void term_print(const matrix *mat, int row, int col) { + wprintf(L"\x1b[%d;%dH%s%lc", row, col, ANSI_COL_DROP, + mat->code[mat_index(mat, row, col)]); +} + +static void term_glitch(int row, int col) { + static wchar_t code[] = { + 0x0413, // Г + 0x0418, // И + 0x042F, // Я + 0x2200, // ∀ + 0x04D9, // ә + 0x0500, // Ԁ + 0x2203, // ∃ + 0x2132, // Ⅎ + 0x0245, // Ʌ + 0x037B, // ͻ + 0x03FD, // Ͻ + 0x041F, // П + 0x04D4, // Ӕ + 0x0424, // Ф + }; + + static int codelen = sizeof(code) / sizeof(code[0]); + + wprintf(L"\x1b[%d;%dH\x1b[39m%lc", row, col, code[rand() % codelen]); +} + +static volatile int run; + +static void handle_signal(int sa) { + switch (sa) { + case SIGINT: + case SIGQUIT: + case SIGTERM: + run = 0; + break; + } +} + +int main(int argc, char *argv[]) { + matrix mat; + table tab; + struct winsize ws; + struct timespec ts; + struct sigaction sa; + int i, cols, blank, delay, tmp; + + setlocale(LC_CTYPE, ""); + + sa.sa_handler = handle_signal; + sigaction(SIGINT, &sa, 0); + sigaction(SIGQUIT, &sa, 0); + sigaction(SIGTERM, &sa, 0); + + srand(time(0)); + + if (!term_init()) + return 1; + + term_size(&ws); + mat = (matrix){0}; + if (!mat_init(&mat, &ws)) { + term_reset(); + return 1; + } + + tab = (table){0}; + if (!tab_init(&tab, &mat)) { + term_reset(); + return 1; + } + + delay = 75; + ts.tv_sec = delay / 1000; + ts.tv_nsec = (delay % 1000) * 1000000; + + run = cols = 1; + blank = tab.cols[tab.len - 1]; + while (run) { + for (i = 0; run && i < cols; i++) { + if (tab.rows[i] == mat.rows) { + tab.rows[i] = 0; + term_reset_cell(&mat, mat.rows - 1, tab.cols[i]); + } + if (tab.attr[i] == 0) { + // hard-coding to 5 (row[i] - rand() % rows[i] glitches on empty rows) + if (tab.rows[i] > 5 && rand() % 6 == 0) + term_glitch(tab.rows[i] - 5, tab.cols[i]); + if (tab.rows[i] > 0) + term_reset_cell(&mat, tab.rows[i] - 1, tab.cols[i]); + term_print(&mat, tab.rows[i], tab.cols[i]); + if (tab.rows[i] == mat.rows - 1) + tab.attr[i] = 1; + tab.rows[i]++; + } else { + term_clear_cell(tab.rows[i], tab.cols[i]); + if (tab.rows[i] == mat.rows - 1) { + tab.rows[i] = 0; + tab.attr[i] = 0; + tmp = blank; + blank = tab.cols[i]; + tab.cols[i] = tmp; + } else + tab.rows[i]++; + } + } + if (cols < tab.len * 0.6) + tab.rows[cols++] = 0; + fflush(stdout); + nanosleep(&ts, &ts); + } + + term_reset(); + tab_free(&tab); + free(mat.code); + return 0; +} -- cgit v1.2.3