فهرست منبع

API 31 / unzip sources

MX 2 سال پیش
کامیت
3d65e8a508
3فایلهای تغییر یافته به همراه176 افزوده شده و 0 حذف شده
  1. 12 0
      application.fam
  2. 164 0
      game_of_life.c
  3. BIN
      golIcon.png

+ 12 - 0
application.fam

@@ -0,0 +1,12 @@
+App(
+    appid="gameoflife",
+    name="Game of Life",
+    apptype=FlipperAppType.EXTERNAL,
+    entry_point="game_of_life_app",
+    cdefines=["APP_GAMEOFLIFE_GAME"],
+    requires=["gui"],
+    stack_size=2 * 1024,
+    order=110,
+    fap_icon="golIcon.png",
+    fap_category="Games_Extra",
+)

+ 164 - 0
game_of_life.c

@@ -0,0 +1,164 @@
+#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, FuriMessageQueue* event_queue) {
+    furi_assert(event_queue);
+
+    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);
+
+        view_port_update(view_port);
+        furi_mutex_release(_state->mutex);
+    }
+
+    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;
+}

BIN
golIcon.png