game_of_life.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #include <furi.h>
  2. #include <gui/gui.h>
  3. #include <input/input.h>
  4. #include <stdlib.h>
  5. #define SCREEN_WIDTH 128
  6. #define SCREEN_HEIGHT 64
  7. #define TOTAL_PIXELS SCREEN_WIDTH* SCREEN_HEIGHT
  8. typedef enum {
  9. EventTypeTick,
  10. EventTypeKey,
  11. } EventType;
  12. typedef struct {
  13. EventType type;
  14. InputEvent input;
  15. } AppEvent;
  16. typedef struct {
  17. bool revive;
  18. int evo;
  19. FuriMutex* mutex;
  20. } State;
  21. unsigned char new[TOTAL_PIXELS] = {};
  22. unsigned char old[TOTAL_PIXELS] = {};
  23. unsigned char* fields[] = {new, old};
  24. int current = 0;
  25. int next = 1;
  26. unsigned char get_cell(int x, int y) {
  27. if(x <= 0 || x >= SCREEN_WIDTH) return 0;
  28. if(y <= 0 || y >= SCREEN_HEIGHT) return 0;
  29. int pix = (y * SCREEN_WIDTH) + x;
  30. return fields[current][pix];
  31. }
  32. int count_neightbors(int x, int y) {
  33. return get_cell(x + 1, y - 1) + get_cell(x - 1, y - 1) + get_cell(x - 1, y + 1) +
  34. get_cell(x + 1, y + 1) + get_cell(x + 1, y) + get_cell(x - 1, y) + get_cell(x, y - 1) +
  35. get_cell(x, y + 1);
  36. }
  37. static void update_field(State* state) {
  38. if(state->revive) {
  39. for(int i = 0; i < TOTAL_PIXELS; ++i) {
  40. if((random() % 100) == 1) {
  41. fields[current][i] = 1;
  42. }
  43. state->revive = false;
  44. }
  45. }
  46. for(int i = 0; i < TOTAL_PIXELS; ++i) {
  47. int x = i % SCREEN_WIDTH;
  48. int y = (int)(i / SCREEN_WIDTH);
  49. int v = get_cell(x, y);
  50. int n = count_neightbors(x, y);
  51. if(v && n == 3) {
  52. ++state->evo;
  53. } else if(v && (n < 2 || n > 3)) {
  54. ++state->evo;
  55. v = 0;
  56. } else if(!v && n == 3) {
  57. ++state->evo;
  58. v = 1;
  59. }
  60. fields[next][i] = v;
  61. }
  62. next ^= current;
  63. current ^= next;
  64. next ^= current;
  65. if(state->evo < TOTAL_PIXELS) {
  66. state->revive = true;
  67. state->evo = 0;
  68. }
  69. }
  70. static void input_callback(InputEvent* input_event, void* ctx) {
  71. FuriMessageQueue* event_queue = ctx;
  72. furi_assert(event_queue);
  73. AppEvent event = {.type = EventTypeKey, .input = *input_event};
  74. furi_message_queue_put(event_queue, &event, 0);
  75. }
  76. static void render_callback(Canvas* canvas, void* ctx) {
  77. //furi_assert(ctx);
  78. State* state = ctx;
  79. furi_mutex_acquire(state->mutex, FuriWaitForever);
  80. canvas_clear(canvas);
  81. for(int i = 0; i < TOTAL_PIXELS; ++i) {
  82. int x = i % SCREEN_WIDTH;
  83. int y = (int)(i / SCREEN_WIDTH);
  84. if(fields[current][i] == 1) canvas_draw_dot(canvas, x, y);
  85. }
  86. furi_mutex_release(state->mutex);
  87. }
  88. int32_t game_of_life_app(void* p) {
  89. UNUSED(p);
  90. srand(DWT->CYCCNT);
  91. FuriMessageQueue* event_queue = furi_message_queue_alloc(1, sizeof(AppEvent));
  92. furi_check(event_queue);
  93. State* _state = malloc(sizeof(State));
  94. _state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
  95. if(!_state->mutex) {
  96. printf("cannot create mutex\r\n");
  97. furi_message_queue_free(event_queue);
  98. free(_state);
  99. return 255;
  100. }
  101. ViewPort* view_port = view_port_alloc();
  102. view_port_draw_callback_set(view_port, render_callback, _state);
  103. view_port_input_callback_set(view_port, input_callback, event_queue);
  104. Gui* gui = furi_record_open(RECORD_GUI);
  105. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  106. AppEvent event;
  107. for(bool processing = true; processing;) {
  108. FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25);
  109. furi_mutex_acquire(_state->mutex, FuriWaitForever);
  110. if(event_status == FuriStatusOk && event.type == EventTypeKey &&
  111. event.input.type == InputTypePress) {
  112. if(event.input.key == InputKeyBack) {
  113. // furiac_exit(NULL);
  114. processing = false;
  115. furi_mutex_release(_state->mutex);
  116. break;
  117. }
  118. }
  119. update_field(_state);
  120. furi_mutex_release(_state->mutex);
  121. view_port_update(view_port);
  122. }
  123. view_port_enabled_set(view_port, false);
  124. gui_remove_view_port(gui, view_port);
  125. furi_record_close(RECORD_GUI);
  126. view_port_free(view_port);
  127. furi_message_queue_free(event_queue);
  128. furi_mutex_free(_state->mutex);
  129. free(_state);
  130. return 0;
  131. }