#include #include #include #include #include #include #include #define DISP_WIDTH 640 #define DISP_HEIGHT 480 #define FPS 3.3 #define DO_INIT(check, desc) \ if (!(check)) { \ fprintf(stderr, "err: can't initialise %s\n", desc); \ rval = 1; \ goto done; \ } static bool bit_get(uint8_t *bline, unsigned off) { return (bline[off / 8] >> (off % 8)) & 0x01; } static void bit_set(uint8_t *bline, unsigned off) { bline[off / 8] = (bline[off / 8] | (0x01 << (off % 8)) ); } static void bit_toggle(uint8_t *bline, unsigned off) { bline[off / 8] = (bline[off / 8] ^ (0x01 << (off % 8)) ); } int main(int argc, char **argv) { int rval = 0; uint8_t bits[DISP_HEIGHT][DISP_WIDTH / 8]; uint8_t automaton = 0; unsigned x, y; bool pause = 0; ALLEGRO_DISPLAY* d = NULL; ALLEGRO_TIMER* t = NULL; ALLEGRO_EVENT_QUEUE* eq = NULL; ALLEGRO_EVENT e; DO_INIT(sodium_init() >= 0, "sodium"); DO_INIT(al_init(), "allegro"); DO_INIT(al_init_primitives_addon(), "primitives"); DO_INIT(al_install_keyboard(), "keyboard"); DO_INIT(t = al_create_timer(1.0 / FPS), "timer"); DO_INIT(eq = al_create_event_queue(), "event queue"); al_set_new_display_option(ALLEGRO_SINGLE_BUFFER, 1, ALLEGRO_REQUIRE); DO_INIT(d = al_create_display(DISP_WIDTH, DISP_HEIGHT), "display"); al_register_event_source(eq, al_get_keyboard_event_source()); al_register_event_source(eq, al_get_display_event_source(d)); al_register_event_source(eq, al_get_timer_event_source(t)); al_start_timer(t); al_clear_to_color(al_map_rgb(0, 0, 0)); while(true) { al_wait_for_event(eq, &e); switch (e.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: goto done; case ALLEGRO_EVENT_KEY_DOWN: switch(e.keyboard.keycode) { case ALLEGRO_KEY_UP: automaton += 10; printf("%d\n", automaton); break; case ALLEGRO_KEY_DOWN: automaton -= 10; printf("%d\n", automaton); break; case ALLEGRO_KEY_LEFT: automaton -= 1; printf("%d\n", automaton); break; case ALLEGRO_KEY_RIGHT: automaton += 1; printf("%d\n", automaton); break; case ALLEGRO_KEY_ENTER: pause = !pause; printf("%s\n", pause ? "pause" : "play"); break; default: break; } break; case ALLEGRO_EVENT_TIMER: if (pause) break; /* seed bits */ memset(bits[1], 0, (DISP_HEIGHT - 1) * DISP_WIDTH / 8); for (x = 1; x < DISP_WIDTH - 1; x++) { if (randombytes_random() < 0x20000000) bit_toggle(bits[0], x); } /* propagate */ for (y = 0; y < DISP_HEIGHT - 1; y++) { for (x = 1; x < DISP_WIDTH - 2; x++) { if ( bit_get(&automaton, bit_get(bits[y], x + 2) + bit_get(bits[y], x + 1) * 2 + bit_get(bits[y], x) * 4 ) ) { bit_set(bits[y + 1], x + 1); } } } /* draw frame */ al_clear_to_color(al_map_rgb(0, 0, 0)); for (y = 0; y < DISP_HEIGHT; y++) { for (x = 0; x < DISP_WIDTH; x++) { if (bit_get(bits[y], x)) { al_draw_filled_rectangle( (float)x, (float)y, (float)(x + 1), (float)(y + 1), al_map_rgb(255, 255, 255) ); } } } al_flip_display(); } } done: if (d) al_destroy_display(d); if (t) al_destroy_timer(t); if (eq) al_destroy_event_queue(eq); return rval; }