@@ 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 <string.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
+#include <SDL2/SDL.h>
#include <time.h>
+#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)]) {}