Initial commit.
This commit is contained in:
commit
6b20ca721f
21
Makefile
Normal file
21
Makefile
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
PREFIX=
|
||||
|
||||
all: nuke
|
||||
|
||||
nuke: nuke.c
|
||||
cc nuke.c -lncurses -O3 -o nuke
|
||||
|
||||
clean:
|
||||
rm -f nuke
|
||||
|
||||
install: nuke
|
||||
@prefix="$(PREFIX)"; \
|
||||
if [[ ! $$prefix ]]; then \
|
||||
read -p $$'\033[1mWhere do you want to install? (default: /usr/local) \033[0m' prefix; \
|
||||
fi; \
|
||||
if [[ ! $$prefix ]]; then \
|
||||
prefix="/usr/local"; \
|
||||
fi; \
|
||||
mkdir -pv $$prefix/bin; \
|
||||
cp -v nuke $$prefix/bin/
|
262
nuke.c
Normal file
262
nuke.c
Normal file
@ -0,0 +1,262 @@
|
||||
/**
|
||||
* ASCII explosion from squeamish ossifrage at:
|
||||
* https://codegolf.stackexchange.com/questions/24462/display-the-explosion-of-a-star-in-ascii-art/24554#24554
|
||||
*/
|
||||
|
||||
#include <curses.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <poll.h>
|
||||
|
||||
#define NUM_FRAMES 150
|
||||
#define NUM_BLOBS 800
|
||||
#define PERSPECTIVE 50.0
|
||||
#define ESCDELAY 10
|
||||
|
||||
typedef struct {
|
||||
double x,y,z;
|
||||
} spaceblob;
|
||||
|
||||
double prng() {
|
||||
static long long s=1;
|
||||
s = s * 1488248101 + 981577151;
|
||||
return ((s % 65536) - 32768) / 32768.0;
|
||||
}
|
||||
|
||||
static void sighandler(int sig) {
|
||||
(void)sig;
|
||||
curs_set(1);
|
||||
endwin();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static char* get_piped_input() {
|
||||
struct pollfd desc;
|
||||
desc.fd = STDIN_FILENO;
|
||||
desc.events = POLLIN;
|
||||
int ret = poll(&desc, 1, 50);
|
||||
if (ret == 0) {
|
||||
return NULL;
|
||||
} else if (ret < 0) {
|
||||
perror("poll");
|
||||
raise(SIGINT);
|
||||
}
|
||||
size_t chunk = 1024;
|
||||
size_t capacity = chunk;
|
||||
size_t size = 0;
|
||||
char *input = malloc(capacity);
|
||||
for (size_t consumed; (consumed = fread(&input[size], 1, chunk, stdin)); size += consumed) {
|
||||
if (consumed == chunk) {
|
||||
chunk *= 2;
|
||||
capacity += chunk;
|
||||
input = realloc(input, capacity);
|
||||
}
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
/* Populate `lines` with (at most `max_lines`) lines from stdin, each at most
|
||||
* `max_line` characters long.
|
||||
* Return length of the longest line on success, -1 otherwise.
|
||||
* *
|
||||
static int get_piped_lines(char **lines[], size_t *max_lines, ssize_t *max_line) {
|
||||
struct pollfd desc;
|
||||
desc.fd = STDIN_FILENO;
|
||||
desc.events = POLLIN;
|
||||
int ret = poll(&desc, 1, 50);
|
||||
if (ret > 0) {
|
||||
ssize_t num_lines, longest_line = 0;
|
||||
for (num_lines = 0; num_lines < *max_lines; num_lines++) {
|
||||
size_t n = *max_line;
|
||||
lines[num_lines] = (char*)malloc(n+1);
|
||||
ssize_t line_len = getline(&lines[num_lines], &n, stdin);
|
||||
while (lines[num_lines][line_len-1] == '\n')
|
||||
lines[num_lines][--line_len] = '\0';
|
||||
if (line_len == -1) break;
|
||||
if (line_len > longest_line) {
|
||||
longest_line = line_len > *max_line ? *max_line : line_len;
|
||||
}
|
||||
}
|
||||
*max_lines = num_lines;
|
||||
*max_line = longest_line;
|
||||
return 0;
|
||||
} else if (ret < 0) {
|
||||
perror("poll");
|
||||
raise(SIGINT);
|
||||
}
|
||||
*max_lines = 0;
|
||||
*max_line = 0;
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char *frames[NUM_FRAMES], *frame;
|
||||
int i,j,x,y,z,v,rows,cols,ith,i0;
|
||||
int maxx,minx,maxy,miny,delay=1E5;
|
||||
double bx,by,bz,br,r,th,t;
|
||||
spaceblob *blobs;
|
||||
|
||||
char *input = get_piped_input();
|
||||
if (!input) goto exit_failure;
|
||||
|
||||
/* Initialize ncurses and get window dimensions */
|
||||
//initscr();
|
||||
char* term_type = getenv("TERM");
|
||||
if (term_type == NULL || *term_type == '\0') {
|
||||
term_type = "unknown";
|
||||
}
|
||||
FILE* term_in = fopen("/dev/tty", "r");
|
||||
if (term_in == NULL) {
|
||||
perror("fopen(/dev/tty)");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
SCREEN* main_screen = newterm(term_type, stdout, term_in);
|
||||
set_term(main_screen);
|
||||
|
||||
signal(SIGINT, sighandler);
|
||||
|
||||
start_color();
|
||||
const int BLACK_ON_RED = 1;
|
||||
init_pair(BLACK_ON_RED, COLOR_BLACK, COLOR_RED);
|
||||
getmaxyx(stdscr,rows,cols);
|
||||
minx = -cols / 2;
|
||||
maxx = cols+minx-1;
|
||||
miny = -rows / 2;
|
||||
maxy = rows+miny-1;
|
||||
|
||||
/* Generate random blob coordinates */
|
||||
blobs = (spaceblob*)malloc(NUM_BLOBS * sizeof(spaceblob));
|
||||
for (i=0; i<NUM_BLOBS; i++) {
|
||||
bx = prng();
|
||||
by = prng();
|
||||
bz = prng();
|
||||
br = sqrt(bx*bx + by*by + bz*bz);
|
||||
blobs[i].x = (bx / br) * (1.3 + 0.2 * prng());
|
||||
blobs[i].y = (0.5 * by / br) * (1.3 + 0.2 * prng());;
|
||||
blobs[i].z = (bz / br) * (1.3 + 0.2 * prng());;
|
||||
}
|
||||
|
||||
/* Generate animation frames */
|
||||
for (i=0; i<NUM_FRAMES; i++) {
|
||||
t = (1. * i) / NUM_FRAMES;
|
||||
frame = frames[i] = (char*)malloc(cols * rows + 1);
|
||||
|
||||
if (i == 0) {
|
||||
memset(frame, ' ', cols*rows);
|
||||
|
||||
int num_lines = 1, max_line = 0;
|
||||
int linelen = 0;
|
||||
for (char *p = input; *p && (num_lines < rows); ++p) {
|
||||
if (*p == '\n') {
|
||||
if (linelen > max_line)
|
||||
max_line = linelen;
|
||||
linelen = 0;
|
||||
num_lines++;
|
||||
} else {
|
||||
linelen++;
|
||||
}
|
||||
}
|
||||
for (int l = 0, line = 0; input[l] && line < num_lines; line++) {
|
||||
int eol = l;
|
||||
while (input[eol] && input[eol] != '\n') eol++;
|
||||
|
||||
memcpy(&frame[(rows/2 - num_lines/2 + line)*cols + cols/2 - max_line/2],
|
||||
&input[l], cols < eol-l ? cols : eol-l);
|
||||
|
||||
l = input[eol] == '\n' ? eol + 1 : eol;
|
||||
}
|
||||
|
||||
frame += cols*rows;
|
||||
|
||||
} else {
|
||||
char *frame0 = frames[0];
|
||||
for (y=miny; y<=maxy; y++) {
|
||||
for (x=minx; x<=maxx; x++) {
|
||||
char frame0c = *(frame0++);
|
||||
/* Show expanding star in next 7 frames */
|
||||
if (i<8) {
|
||||
r = sqrt(x*x + 4*y*y);
|
||||
*frame++ = (r < i*2) ? '@' : frame0c;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Otherwise show blast wave */
|
||||
r = sqrt(x*x + 4*y*y) * (0.5 + (prng()/3.0)*cos(16.*atan2(y*2.+0.01,x+0.01))*.3);
|
||||
ith = 32 + th * 32. * M_1_PI;
|
||||
v = i - r - 7;
|
||||
if (v<0) *frame++ = (i<19)?"%@W#H=+~-:."[i-8]:frame0c; /* initial flash */
|
||||
else if (v<20) *frame++ = " .:!HIOMW#%$&@08O=+-"[v];
|
||||
else *frame++=' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Add blobs with perspective effect */
|
||||
if (i>6) {
|
||||
i0 = i-6;
|
||||
for (j=0; j<NUM_BLOBS; j++) {
|
||||
bx = blobs[j].x * i0;
|
||||
by = blobs[j].y * i0;
|
||||
bz = blobs[j].z * i0;
|
||||
if (bz<5-PERSPECTIVE || bz>PERSPECTIVE) continue;
|
||||
x = cols / 2 + bx * PERSPECTIVE / (bz+PERSPECTIVE);
|
||||
y = rows / 2 + by * PERSPECTIVE / (bz+PERSPECTIVE);
|
||||
if (x>=0 && x<cols && y>=0 && y<rows)
|
||||
frames[i][x+y*cols] = (bz>40) ? '.' : (bz>-20) ? 'o' : '@';
|
||||
}
|
||||
}
|
||||
|
||||
/* Terminate the text string for this frame */
|
||||
*frame = '\0';
|
||||
}
|
||||
|
||||
/* Now play back the frames in sequence */
|
||||
curs_set(0); /* hide text cursor (supposedly) */
|
||||
noecho();
|
||||
for (i=0; i<NUM_FRAMES; i++) {
|
||||
erase();
|
||||
mvaddstr(0,0,frames[i]);
|
||||
refresh();
|
||||
if (i == 0) {
|
||||
/* Display confirmation */
|
||||
attron(COLOR_PAIR(BLACK_ON_RED));
|
||||
const char confirm[] = " FIRE NUKE? y/n ";
|
||||
mvprintw((rows*3)/4, cols/2 - strlen(confirm)/2, "%s", confirm);
|
||||
attroff(COLOR_PAIR(BLACK_ON_RED));
|
||||
refresh();
|
||||
if (getch() != 'y') {
|
||||
goto exit_failure;
|
||||
}
|
||||
erase();
|
||||
mvaddstr(0,0,frames[i]);
|
||||
refresh();
|
||||
timeout(10);
|
||||
}
|
||||
/* Quit early? */
|
||||
int ch = getch();
|
||||
if (ch == 'q' || ch == 27) {
|
||||
goto exit_success;
|
||||
}
|
||||
|
||||
usleep(delay);
|
||||
delay=16666; /* Change to 60fps after first frame */
|
||||
}
|
||||
|
||||
exit_success:
|
||||
curs_set(1); /* unhide cursor */
|
||||
endwin(); /* Exit ncurses */
|
||||
if (!isatty(fileno(stdout))) {
|
||||
// Print stdin to stdout
|
||||
puts(input);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
exit_failure:
|
||||
curs_set(1); /* unhide cursor */
|
||||
endwin(); /* Exit ncurses */
|
||||
return EXIT_FAILURE;
|
||||
}
|
Loading…
Reference in New Issue
Block a user