From 1f4a15a7c4d5d7830caae39af8104d737a8ff432 Mon Sep 17 00:00:00 2001 From: lemon Date: Sat, 19 Feb 2022 20:33:09 +0100 Subject: [PATCH] vla/life: turn it into a graphical program --- vla/Makefile | 1 + vla/life.c | 125 +++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 98 insertions(+), 28 deletions(-) diff --git a/vla/Makefile b/vla/Makefile index f8d5260..b7ac053 100644 --- a/vla/Makefile +++ b/vla/Makefile @@ -4,5 +4,6 @@ all: md5sum sha256sum life md5sum: md5sum.c sha256sum: sha256sum.c life: life.c + $(CC) $(CFLAGS) -lSDL2 -o $@ $< clean: $(RM) md5sum sha256sum life diff --git a/vla/life.c b/vla/life.c index 88e3170..69b961d 100644 --- a/vla/life.c +++ b/vla/life.c @@ -1,27 +1,58 @@ -#define _GNU_SOURCE // for nanosleep.. +/* Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. */ + #include #include #include #include +#include #include +#define bool _Bool + #define TAIL /* tail call (declaration of intent) */ +#define EXPECT(x, ...) \ + ((!(x)) ? (fprintf(stderr, "error: "), \ + fprintf(stderr, __VA_ARGS__), \ + fputc('\n', stderr), \ + exit(1)) \ + : (void)0) +#define MIN(x,y) ((x) < (y) ? (x) : (y)) +#define W 230 +#define H 180 +#define SCALE 4 -#define W 64 -#define H 32 -static char board[H][W], boardtmp[H][W]; -static unsigned gen; +/* live cells = 0, dead cells = 1..255, depending how long they've been dead, + * for a fadeout effect */ +static unsigned char board[H][W], boardtmp[H][W]; char title[60]; static unsigned gen; +static SDL_Window *win; static SDL_Renderer *ren; static bool running = 1, + pause; #define neighbours(b,y,x) \ - ( b[(y-1)%H][(x-1)%W] + b[(y-1)%H][(x)%W] + b[(y-1)%H][(x+1)%W] \ - + b[(y+0)%H][(x-1)%W] + b[(y+0)%H][(x+1)%W] \ - + b[(y+1)%H][(x-1)%W] + b[(y+1)%H][(x)%W] + b[(y+1)%H][(x+1)%W] ) \ + ( !b[(y-1)%H][(x-1)%W] + !b[(y-1)%H][(x)%W] + !b[(y-1)%H][(x+1)%W] \ + + !b[(y+0)%H][(x-1)%W] + !b[(y+0)%H][(x+1)%W] \ + + !b[(y+1)%H][(x-1)%W] + !b[(y+1)%H][(x)%W] + !b[(y+1)%H][(x+1)%W] ) \ static void life(size_t i, size_t y, size_t x, size_t n, char *); static void life(size_t i, size_t y, size_t x, size_t n, char _[( y = i/W, x = i%W, n = neighbours(board, y, x), - boardtmp[y][x] = (board[y][x] ? (n == 2 || n == 3) : (n == 3)), + boardtmp[y][x] = board[y][x], + (board[y][x] == 0 ? (n == 2 || n == 3) : (n == 3)) ? + boardtmp[y][x] = 0 + : (board[y][x] == 0) ? + boardtmp[y][x] = 150 + : + (boardtmp[i/W][i%W] = MIN(boardtmp[i/W][i%W]*5/4, 255)), + (++i < W*H) ? TAIL life(i, y,x,n,"") : @@ -30,41 +61,79 @@ static void life(size_t i, size_t y, size_t x, size_t n, char _[( static void randini(size_t i, char *); static void randini(size_t i, char _[( - board[i/W][i%W] = rand() < RAND_MAX / 2, + board[i/W][i%W] = rand() < RAND_MAX / 3 ? 0 : 255, (++i < W*H) ? TAIL randini(i, "") : (void)0, 1)]) {} -static void clear(char _[( - printf("%s", "\x1b[2J"), - fflush(stdout), +static void draw(size_t i, int c, SDL_Rect *rc, char *); +static void draw(size_t i, int c, SDL_Rect *rc, char _[( + (rc->x = i%W*SCALE, rc->y = i/W*SCALE, rc->w = rc->h = SCALE), + ((c = board[i/W][i%W]) > 0) ? + c = pause ? 255 : c, + SDL_SetRenderDrawColor(ren, 200,200,255,255-c) + : + SDL_SetRenderDrawColor(ren, 255,255,255,255), + SDL_RenderFillRect(ren, rc), + (++i < W*H) ? + TAIL draw(i, c, rc, "") + : (void)0, +1)]) {} + +static void events(SDL_Event *, char *); +static void events(SDL_Event *ev, char _[( + (SDL_PollEvent(ev)) ? ( + (ev->type == SDL_QUIT || (ev->type == SDL_KEYDOWN && ev->key.keysym.sym == SDLK_ESCAPE)) ? + running = 0 + : (ev->type == SDL_KEYDOWN && ev->key.keysym.sym == SDLK_SPACE) ? + pause ^= 1 + : (ev->type == SDL_KEYDOWN && ev->key.keysym.sym == SDLK_r) ? + randini(0, "") + : (ev->type == SDL_KEYDOWN && ev->key.keysym.sym == SDLK_c) ? + memset(board, 255, sizeof board) + : (void)0, + + TAIL events(ev, "") + ) : (void)0, 1)]) {} -static void draw(size_t i, char *); -static void draw(size_t i, char _[( - (i && i%W == 0) ? putchar('\n') : (void)0, - putchar(board[i/W][i%W] ? '#' : ' '), - (++i < W*H) ? - TAIL draw(i, "") - : putchar('\n'), +static void maybepaint(int mb, int mx, int my, char _[( + (mb = SDL_GetMouseState(&mx, &my)), + (mb & SDL_BUTTON_LMASK && mx >= 0 && my >= 0 && mx < W*SCALE && my < H*SCALE) ? + board[my/SCALE][mx/SCALE] = 0 + : (mb & SDL_BUTTON_RMASK && mx >= 0 && my >= 0 && mx < W*SCALE && my < H*SCALE) ? + board[my/SCALE][mx/SCALE] = 255 + : (void)0, 1)]) {} static void loop(char *); static void loop(char _[( - clear(""), - printf("Generation %u\n", gen++), - draw(0, ""), - life(0, 0,0,0,""), - puts("Enter: step ^D: auto ^C: quit"), - getchar() == EOF ? - nanosleep(&(struct timespec){ .tv_nsec = 30000000 }, NULL) + sprintf(title, "SPC: Pause; R: Reset; C: Clear - Gen. %u\n", gen), + SDL_SetWindowTitle(win, title), + events(&(SDL_Event){}, ""), + maybepaint(0,0,0,""), + SDL_SetRenderDrawColor(ren, 0, 0, 0, 255), + SDL_RenderClear(ren), + (!pause && !(SDL_GetMouseState(NULL, NULL) & (SDL_BUTTON_LMASK | SDL_BUTTON_RMASK))) ? + ++gen, + life(0, 0,0,0,"") + : (void)0, + draw(0, 0, &(SDL_Rect){0}, ""), + SDL_RenderPresent(ren), + SDL_Delay(16), + running ? + TAIL loop("") : (void)0, - TAIL loop(""), 1)]) {} int main(int argc, char *argv[( + EXPECT(SDL_Init(SDL_INIT_VIDEO) == 0, "SDL: %s", SDL_GetError()), + EXPECT(SDL_CreateWindowAndRenderer(W*SCALE, H*SCALE, 0, &win, &ren) == 0, "SDL: %s", SDL_GetError()), + SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND), srand(time(NULL)), randini(0, ""), + loop(""), + SDL_Quit(), 1)]) {} -- 2.45.2