4inrow.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. #include <stdio.h>
  2. #include <furi.h>
  3. #include <gui/gui.h>
  4. #include <input/input.h>
  5. #include <notification/notification.h>
  6. #include <notification/notification_messages.h>
  7. #include <dolphin/dolphin.h>
  8. static int matrix[6][7] = {0};
  9. static int cursorx = 3;
  10. static int cursory = 5;
  11. static int player = 1;
  12. static int scoreX = 0;
  13. static int scoreO = 0;
  14. typedef struct {
  15. FuriMutex* mutex;
  16. } FourInRowState;
  17. void init() {
  18. for(size_t i = 0; i < 6; i++) {
  19. for(size_t j = 0; j < 7; j++) {
  20. matrix[i][j] = 0;
  21. }
  22. }
  23. cursorx = 3;
  24. cursory = 5;
  25. player = 1;
  26. }
  27. const NotificationSequence end = {
  28. &message_vibro_on,
  29. &message_note_ds4,
  30. &message_delay_10,
  31. &message_sound_off,
  32. &message_delay_10,
  33. &message_note_ds4,
  34. &message_delay_10,
  35. &message_sound_off,
  36. &message_delay_10,
  37. &message_note_ds4,
  38. &message_delay_10,
  39. &message_sound_off,
  40. &message_delay_10,
  41. &message_vibro_off,
  42. NULL,
  43. };
  44. void intToStr(int num, char* str) {
  45. int i = 0, sign = 0;
  46. if(num < 0) {
  47. num = -num;
  48. sign = 1;
  49. }
  50. do {
  51. str[i++] = num % 10 + '0';
  52. num /= 10;
  53. } while(num > 0);
  54. if(sign) {
  55. str[i++] = '-';
  56. }
  57. str[i] = '\0';
  58. // Reverse the string
  59. int j, len = i;
  60. char temp;
  61. for(j = 0; j < len / 2; j++) {
  62. temp = str[j];
  63. str[j] = str[len - j - 1];
  64. str[len - j - 1] = temp;
  65. }
  66. }
  67. int next_height(int x) {
  68. if(matrix[0][x] != 0) {
  69. return -1;
  70. }
  71. for(size_t y = 1; y < 6; y++) {
  72. if(matrix[y][x] != 0) {
  73. return y - 1;
  74. }
  75. }
  76. return 5;
  77. }
  78. int wincheck() {
  79. for(size_t y = 0; y <= 2; y++) {
  80. for(size_t x = 0; x <= 6; x++) {
  81. if(matrix[y][x] != 0 && matrix[y][x] == matrix[y + 1][x] &&
  82. matrix[y][x] == matrix[y + 2][x] && matrix[y][x] == matrix[y + 3][x]) {
  83. return matrix[y][x];
  84. }
  85. }
  86. }
  87. for(size_t y = 0; y <= 5; y++) {
  88. for(size_t x = 0; x <= 3; x++) {
  89. if(matrix[y][x] != 0 && matrix[y][x] == matrix[y][x + 1] &&
  90. matrix[y][x] == matrix[y][x + 2] && matrix[y][x] == matrix[y][x + 3]) {
  91. return matrix[y][x];
  92. }
  93. }
  94. }
  95. for(size_t y = 0; y <= 2; y++) {
  96. for(size_t x = 0; x <= 3; x++) {
  97. if(matrix[y][x] != 0 && matrix[y][x] == matrix[y + 1][x + 1] &&
  98. matrix[y][x] == matrix[y + 2][x + 2] && matrix[y][x] == matrix[y + 3][x + 3]) {
  99. return matrix[y][x];
  100. }
  101. }
  102. }
  103. for(size_t y = 3; y <= 5; y++) {
  104. for(size_t x = 0; x <= 3; x++) {
  105. if(matrix[y][x] != 0 && matrix[y][x] == matrix[y - 1][x + 1] &&
  106. matrix[y][x] == matrix[y - 2][x + 2] && matrix[y][x] == matrix[y - 3][x + 3]) {
  107. return matrix[y][x];
  108. }
  109. }
  110. }
  111. bool tf = true;
  112. for(size_t y = 0; y < 6; y++) {
  113. for(size_t x = 0; x < 7; x++) {
  114. if(matrix[y][x] == 0) {
  115. tf = false;
  116. }
  117. }
  118. }
  119. if(tf) {
  120. return 0;
  121. }
  122. return -1;
  123. }
  124. static void draw_callback(Canvas* canvas, void* ctx) {
  125. furi_assert(ctx);
  126. const FourInRowState* fourinrow_state = ctx;
  127. furi_mutex_acquire(fourinrow_state->mutex, FuriWaitForever);
  128. canvas_clear(canvas);
  129. if(wincheck() != -1) {
  130. canvas_set_font(canvas, FontPrimary);
  131. if(wincheck() == 0) {
  132. canvas_draw_str(canvas, 30, 35, "Draw! O_o");
  133. }
  134. if(wincheck() == 1) {
  135. canvas_draw_str(canvas, 30, 35, "Player X win!");
  136. }
  137. if(wincheck() == 2) {
  138. canvas_draw_str(canvas, 30, 35, "Player O win!");
  139. }
  140. furi_mutex_release(fourinrow_state->mutex);
  141. return;
  142. }
  143. for(size_t i = 0; i < 6; i++) {
  144. for(size_t j = 0; j < 7; j++) {
  145. char el[2];
  146. switch(matrix[i][j]) {
  147. case 0:
  148. strcpy(el, "_\0");
  149. break;
  150. case 1:
  151. strcpy(el, "X\0");
  152. break;
  153. case 2:
  154. strcpy(el, "O\0");
  155. break;
  156. }
  157. canvas_draw_str(canvas, j * 10 + 10, i * 10 + 10, el);
  158. }
  159. }
  160. canvas_draw_str(canvas, cursorx * 10 + 8, cursory * 10 + 10, "[ ]");
  161. if(player == 1) {
  162. canvas_draw_str(canvas, 80, 10, "Turn: X");
  163. }
  164. if(player == 2) {
  165. canvas_draw_str(canvas, 80, 10, "Turn: O");
  166. }
  167. char scX[1];
  168. intToStr(scoreX, scX);
  169. char scO[1];
  170. intToStr(scoreO, scO);
  171. canvas_draw_str(canvas, 80, 20, "X:");
  172. canvas_draw_str(canvas, 90, 20, scX);
  173. canvas_draw_str(canvas, 80, 30, "O:");
  174. canvas_draw_str(canvas, 90, 30, scO);
  175. furi_mutex_release(fourinrow_state->mutex);
  176. }
  177. static void input_callback(InputEvent* input_event, void* ctx) {
  178. // Проверяем, что контекст не нулевой
  179. furi_assert(ctx);
  180. FuriMessageQueue* event_queue = ctx;
  181. furi_message_queue_put(event_queue, input_event, FuriWaitForever);
  182. }
  183. int32_t four_in_row_app(void* p) {
  184. UNUSED(p);
  185. // Текущее событие типа InputEvent
  186. InputEvent event;
  187. // Очередь событий на 8 элементов размера InputEvent
  188. FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
  189. FourInRowState* fourinrow_state = malloc(sizeof(FourInRowState));
  190. fourinrow_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); // Alloc Mutex
  191. if(!fourinrow_state->mutex) {
  192. FURI_LOG_E("4inRow", "cannot create mutex\r\n");
  193. furi_message_queue_free(event_queue);
  194. free(fourinrow_state);
  195. return 255;
  196. }
  197. dolphin_deed(DolphinDeedPluginGameStart);
  198. // Создаем новый view port
  199. ViewPort* view_port = view_port_alloc();
  200. // Создаем callback отрисовки, без контекста
  201. view_port_draw_callback_set(view_port, draw_callback, fourinrow_state);
  202. // Создаем callback нажатий на клавиши, в качестве контекста передаем
  203. // нашу очередь сообщений, чтоб запихивать в неё эти события
  204. view_port_input_callback_set(view_port, input_callback, event_queue);
  205. // Создаем GUI приложения
  206. Gui* gui = furi_record_open(RECORD_GUI);
  207. // Подключаем view port к GUI в полноэкранном режиме
  208. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  209. NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
  210. notification_message_block(notification, &sequence_display_backlight_enforce_on);
  211. // Бесконечный цикл обработки очереди событий
  212. while(1) {
  213. // Выбираем событие из очереди в переменную event (ждем бесконечно долго, если очередь пуста)
  214. // и проверяем, что у нас получилось это сделать
  215. if(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) {
  216. if((event.type == InputTypePress) && (event.key == InputKeyBack)) {
  217. break;
  218. }
  219. furi_mutex_acquire(fourinrow_state->mutex, FuriWaitForever);
  220. if(wincheck() != -1) {
  221. notification_message(notification, &end);
  222. furi_delay_ms(1000);
  223. if(wincheck() == 1) {
  224. scoreX++;
  225. }
  226. if(wincheck() == 2) {
  227. scoreO++;
  228. }
  229. init();
  230. furi_mutex_release(fourinrow_state->mutex);
  231. continue;
  232. }
  233. if(event.type == InputTypePress) {
  234. if(event.key == InputKeyOk) {
  235. int nh = next_height(cursorx);
  236. if(nh != -1) {
  237. matrix[nh][cursorx] = player;
  238. player = 3 - player;
  239. }
  240. }
  241. if(event.key == InputKeyUp) {
  242. //cursory--;
  243. }
  244. if(event.key == InputKeyDown) {
  245. //cursory++;
  246. }
  247. if(event.key == InputKeyLeft) {
  248. if(cursorx > 0) {
  249. cursorx--;
  250. }
  251. }
  252. if(event.key == InputKeyRight) {
  253. if(cursorx < 6) {
  254. cursorx++;
  255. }
  256. }
  257. }
  258. furi_mutex_release(fourinrow_state->mutex);
  259. }
  260. view_port_update(view_port);
  261. }
  262. // Чистим созданные объекты, связанные с интерфейсом
  263. view_port_enabled_set(view_port, false);
  264. gui_remove_view_port(gui, view_port);
  265. view_port_free(view_port);
  266. furi_message_queue_free(event_queue);
  267. furi_record_close(RECORD_GUI);
  268. // Clear notification
  269. notification_message_block(notification, &sequence_display_backlight_enforce_auto);
  270. furi_record_close(RECORD_NOTIFICATION);
  271. furi_mutex_free(fourinrow_state->mutex);
  272. free(fourinrow_state);
  273. return 0;
  274. }