| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- #include <furi.h>
- #include <gui/gui.h>
- #include <input/input.h>
- #include <stdlib.h>
- #define SCREEN_WIDTH 128
- #define SCREEN_HEIGHT 64
- #define TOTAL_PIXELS SCREEN_WIDTH* SCREEN_HEIGHT
- typedef enum {
- EventTypeTick,
- EventTypeKey,
- } EventType;
- typedef struct {
- EventType type;
- InputEvent input;
- } AppEvent;
- typedef struct {
- bool revive;
- int evo;
- FuriMutex* mutex;
- } State;
- unsigned char new[TOTAL_PIXELS] = {};
- unsigned char old[TOTAL_PIXELS] = {};
- unsigned char* fields[] = {new, old};
- int current = 0;
- int next = 1;
- unsigned char get_cell(int x, int y) {
- if(x <= 0 || x >= SCREEN_WIDTH) return 0;
- if(y <= 0 || y >= SCREEN_HEIGHT) return 0;
- int pix = (y * SCREEN_WIDTH) + x;
- return fields[current][pix];
- }
- int count_neightbors(int x, int y) {
- return get_cell(x + 1, y - 1) + get_cell(x - 1, y - 1) + get_cell(x - 1, y + 1) +
- get_cell(x + 1, y + 1) + get_cell(x + 1, y) + get_cell(x - 1, y) + get_cell(x, y - 1) +
- get_cell(x, y + 1);
- }
- static void update_field(State* state) {
- if(state->revive) {
- for(int i = 0; i < TOTAL_PIXELS; ++i) {
- if((random() % 100) == 1) {
- fields[current][i] = 1;
- }
- state->revive = false;
- }
- }
- for(int i = 0; i < TOTAL_PIXELS; ++i) {
- int x = i % SCREEN_WIDTH;
- int y = (int)(i / SCREEN_WIDTH);
- int v = get_cell(x, y);
- int n = count_neightbors(x, y);
- if(v && n == 3) {
- ++state->evo;
- } else if(v && (n < 2 || n > 3)) {
- ++state->evo;
- v = 0;
- } else if(!v && n == 3) {
- ++state->evo;
- v = 1;
- }
- fields[next][i] = v;
- }
- next ^= current;
- current ^= next;
- next ^= current;
- if(state->evo < TOTAL_PIXELS) {
- state->revive = true;
- state->evo = 0;
- }
- }
- static void input_callback(InputEvent* input_event, void* ctx) {
- furi_assert(ctx);
- FuriMessageQueue* event_queue = ctx;
- AppEvent event = {.type = EventTypeKey, .input = *input_event};
- furi_message_queue_put(event_queue, &event, 0);
- }
- static void render_callback(Canvas* canvas, void* ctx) {
- //furi_assert(ctx);
- State* state = ctx;
- furi_mutex_acquire(state->mutex, FuriWaitForever);
- canvas_clear(canvas);
- for(int i = 0; i < TOTAL_PIXELS; ++i) {
- int x = i % SCREEN_WIDTH;
- int y = (int)(i / SCREEN_WIDTH);
- if(fields[current][i] == 1) canvas_draw_dot(canvas, x, y);
- }
- furi_mutex_release(state->mutex);
- }
- int32_t game_of_life_app(void* p) {
- UNUSED(p);
- srand(DWT->CYCCNT);
- FuriMessageQueue* event_queue = furi_message_queue_alloc(1, sizeof(AppEvent));
- furi_check(event_queue);
- State* _state = malloc(sizeof(State));
- _state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
- if(!_state->mutex) {
- printf("cannot create mutex\r\n");
- furi_message_queue_free(event_queue);
- free(_state);
- return 255;
- }
- ViewPort* view_port = view_port_alloc();
- view_port_draw_callback_set(view_port, render_callback, _state);
- view_port_input_callback_set(view_port, input_callback, event_queue);
- Gui* gui = furi_record_open(RECORD_GUI);
- gui_add_view_port(gui, view_port, GuiLayerFullscreen);
- AppEvent event;
- for(bool processing = true; processing;) {
- FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25);
- furi_mutex_acquire(_state->mutex, FuriWaitForever);
- if(event_status == FuriStatusOk && event.type == EventTypeKey &&
- event.input.type == InputTypePress) {
- if(event.input.key == InputKeyBack) {
- // furiac_exit(NULL);
- processing = false;
- furi_mutex_release(_state->mutex);
- break;
- }
- }
- update_field(_state);
- furi_mutex_release(_state->mutex);
- view_port_update(view_port);
- }
- view_port_enabled_set(view_port, false);
- gui_remove_view_port(gui, view_port);
- furi_record_close(RECORD_GUI);
- view_port_free(view_port);
- furi_message_queue_free(event_queue);
- furi_mutex_free(_state->mutex);
- free(_state);
- return 0;
- }
|