game_of_life.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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, FuriMessageQueue* event_queue) {
  71. furi_assert(event_queue);
  72. AppEvent event = {.type = EventTypeKey, .input = *input_event};
  73. furi_message_queue_put(event_queue, &event, 0);
  74. }
  75. static void render_callback(Canvas* canvas, void* ctx) {
  76. //furi_assert(ctx);
  77. State* state = ctx;
  78. furi_mutex_acquire(state->mutex, FuriWaitForever);
  79. canvas_clear(canvas);
  80. for(int i = 0; i < TOTAL_PIXELS; ++i) {
  81. int x = i % SCREEN_WIDTH;
  82. int y = (int)(i / SCREEN_WIDTH);
  83. if(fields[current][i] == 1) canvas_draw_dot(canvas, x, y);
  84. }
  85. furi_mutex_release(state->mutex);
  86. }
  87. int32_t game_of_life_app(void* p) {
  88. UNUSED(p);
  89. srand(DWT->CYCCNT);
  90. FuriMessageQueue* event_queue = furi_message_queue_alloc(1, sizeof(AppEvent));
  91. furi_check(event_queue);
  92. State* _state = malloc(sizeof(State));
  93. _state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
  94. if(!_state->mutex) {
  95. printf("cannot create mutex\r\n");
  96. furi_message_queue_free(event_queue);
  97. free(_state);
  98. return 255;
  99. }
  100. ViewPort* view_port = view_port_alloc();
  101. view_port_draw_callback_set(view_port, render_callback, _state);
  102. view_port_input_callback_set(view_port, input_callback, event_queue);
  103. Gui* gui = furi_record_open(RECORD_GUI);
  104. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  105. AppEvent event;
  106. for(bool processing = true; processing;) {
  107. FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25);
  108. furi_mutex_acquire(_state->mutex, FuriWaitForever);
  109. if(event_status == FuriStatusOk && event.type == EventTypeKey &&
  110. event.input.type == InputTypePress) {
  111. if(event.input.key == InputKeyBack) {
  112. // furiac_exit(NULL);
  113. processing = false;
  114. furi_mutex_release(_state->mutex);
  115. break;
  116. }
  117. }
  118. update_field(_state);
  119. view_port_update(view_port);
  120. furi_mutex_release(_state->mutex);
  121. }
  122. view_port_enabled_set(view_port, false);
  123. gui_remove_view_port(gui, view_port);
  124. furi_record_close(RECORD_GUI);
  125. view_port_free(view_port);
  126. furi_message_queue_free(event_queue);
  127. furi_mutex_free(_state->mutex);
  128. free(_state);
  129. return 0;
  130. }