yatzee.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. #include "yatzee_icons.h"
  2. #include <furi.h>
  3. #include <furi_hal.h>
  4. #include <gui/gui.h>
  5. #include <gui/elements.h>
  6. #include <input/input.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #define BASE_X 18
  10. #define BASE_Y 44
  11. #define DICE_OFFSET 12
  12. #define HOLD "*"
  13. #define MAX_DICE 5
  14. #define NUM_SCORES 13
  15. bool new_game = true;
  16. bool game_over = false;
  17. bool bonus_added = false;
  18. int8_t num_bonus_yatzees = 0;
  19. //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
  20. // struct to hold image posistion for dice
  21. typedef struct {
  22. // +-----x
  23. // |
  24. // |
  25. // y
  26. uint8_t x;
  27. uint8_t y;
  28. } ImagePosition;
  29. typedef struct {
  30. char* name;
  31. uint32_t value;
  32. bool used;
  33. int8_t row;
  34. int8_t col;
  35. uint8_t (*fn)(); // pointer to function that calculates score
  36. } Score;
  37. typedef struct {
  38. uint8_t index;
  39. uint8_t value;
  40. bool isHeld;
  41. } Die;
  42. typedef struct {
  43. int index;
  44. char* symbol;
  45. } Cursor;
  46. // locations for the dice images
  47. ImagePosition position[5] = {
  48. {.x = BASE_X-DICE_OFFSET, .y = BASE_Y},
  49. {.x = BASE_X*2-DICE_OFFSET, .y = BASE_Y},
  50. {.x = BASE_X*3-DICE_OFFSET, .y = BASE_Y},
  51. {.x = BASE_X*4-DICE_OFFSET, .y = BASE_Y},
  52. {.x = BASE_X*5-DICE_OFFSET, .y = BASE_Y},
  53. };
  54. // these are the positions that the score cursor will cycle through
  55. ImagePosition score_positions[13] = {
  56. {.x=15, .y=0},
  57. {.x=15, .y=9},
  58. {.x=15, .y=18},
  59. {.x=15, .y=27},
  60. {.x=44, .y=0},
  61. {.x=44, .y=9},
  62. {.x=44, .y=18},
  63. {.x=44, .y=27},
  64. {.x=77, .y=0},
  65. {.x=77, .y=9},
  66. {.x=77, .y=18},
  67. {.x=77, .y=27},
  68. {.x=91, .y=21},
  69. };
  70. // cursor to select dice
  71. Cursor cursor = {
  72. .index = 0,
  73. .symbol = "^"
  74. };
  75. // cursor to select score
  76. Cursor scoreCursor = {
  77. .index = -1,
  78. .symbol = "_"
  79. };
  80. // setup array to store dice info
  81. Die die[5] = {
  82. {.index = 0, .value = 1, .isHeld = false},
  83. {.index = 1, .value = 1, .isHeld = false},
  84. {.index = 2, .value = 1, .isHeld = false},
  85. {.index = 3, .value = 1, .isHeld = false},
  86. {.index = 4, .value = 1, .isHeld = false},
  87. };
  88. uint8_t upperScore = 0;
  89. int32_t lowerScore = 0;
  90. int32_t totalScore = 0;
  91. uint8_t roll = 0;
  92. uint8_t totalrolls = 0;
  93. // #############################################
  94. // # The following methods add the score for #
  95. // # whichever number is mentioned. #
  96. // #############################################
  97. static uint8_t ones() {
  98. uint8_t sum = 0;
  99. for (uint8_t i = 0; i < 5; i++) {
  100. if (die[i].value == 1) {
  101. sum++;
  102. }
  103. }
  104. return sum;
  105. }
  106. static uint8_t twos() {
  107. uint8_t sum = 0;
  108. for (uint8_t i = 0; i < 5; i++) {
  109. if (die[i].value == 2) {
  110. sum = sum+2;
  111. }
  112. }
  113. return sum;
  114. }
  115. static uint8_t threes() {
  116. uint8_t sum = 0;
  117. for (uint8_t i = 0; i < 5; i++) {
  118. if (die[i].value == 3) {
  119. sum = sum+3;
  120. }
  121. }
  122. return sum;
  123. }
  124. static uint8_t fours() {
  125. uint8_t sum = 0;
  126. for (uint8_t i = 0; i < 5; i++) {
  127. if (die[i].value == 4) {
  128. sum = sum+4;
  129. }
  130. }
  131. return sum;
  132. }
  133. static uint8_t fives() {
  134. uint8_t sum = 0;
  135. for (uint8_t i = 0; i < 5; i++) {
  136. if (die[i].value == 5) {
  137. sum = sum+5;
  138. }
  139. }
  140. return sum;
  141. }
  142. static uint8_t sixes() {
  143. uint8_t sum = 0;
  144. for (uint8_t i = 0; i < 5; i++) {
  145. if (die[i].value == 6) {
  146. sum = sum+6;
  147. }
  148. }
  149. return sum;
  150. }
  151. // ####################################################
  152. // # Helper methods for the special score types #
  153. // # defined before them so they can be used #
  154. // # since this whole thing is a linear mess #
  155. // # lol. #
  156. // # add_dice: #
  157. // # inputs: none #
  158. // # output: int8_t value of roll #
  159. // # check_if_score_used:
  160. // # inputs: Score
  161. // # output: true if score.used = true
  162. // # # # # # # # # # # # # # # # # # # # # # # # # # #
  163. int8_t add_dice() {
  164. int8_t sum = 0;
  165. for (int8_t i=0; i<MAX_DICE; i++) {
  166. sum+=die[i].value;
  167. } return sum;
  168. }
  169. bool check_if_score_used(Score score) {
  170. if (score.used == true) {
  171. return true;
  172. } else {
  173. return false;
  174. }
  175. }
  176. // #############################################
  177. // # Methods to calculate scores for the fancy #
  178. // # scoring types: 3 of a kind, 4 of a kind, #
  179. // # Full house, small straight, large straight#
  180. // # chance & yatzee. #
  181. // #############################################
  182. static uint8_t threekind() {
  183. int8_t score = 0;
  184. for (int8_t num=1; num<7; num++) {
  185. int8_t sum = 0;
  186. for (int8_t i=0; i<MAX_DICE; i++) {
  187. if (die[i].value == num) {
  188. sum++;
  189. }
  190. if (sum > 2) {
  191. score = add_dice();
  192. }
  193. }
  194. }
  195. return score;
  196. }
  197. static uint8_t fourkind() {
  198. int8_t score = 0;
  199. for (int8_t num=1; num<7; num++) {
  200. int8_t sum = 0;
  201. for (int8_t i=0; i<MAX_DICE; i++) {
  202. if (die[i].value == num) {
  203. sum++;
  204. }
  205. if (sum > 3) {
  206. score = add_dice();
  207. }
  208. }
  209. }
  210. return score;
  211. }
  212. static uint8_t fullhouse() {
  213. bool check1 = false;
  214. bool check2 = false;
  215. int8_t val1 = 0;
  216. int8_t val2 = 0;
  217. UNUSED(val2);
  218. UNUSED(val1);
  219. //check 1 for three of a kind
  220. for (int8_t num=1; num<7; num++) {
  221. int8_t sum = 0;
  222. for (int8_t i=0; i<MAX_DICE; i++) {
  223. if (die[i].value == num) {
  224. sum++;
  225. }
  226. if (sum > 2) {
  227. val1 = die[i].value;
  228. check1 = true;
  229. }
  230. }
  231. }
  232. // return if check 1 failed
  233. if (check1 == false) {
  234. return 0;
  235. }
  236. // check 2 for two of a kind.
  237. for (int8_t num=1; num<7; num++) {
  238. if (num==val1) {continue;}
  239. int8_t sum = 0;
  240. for (int8_t i=0; i<MAX_DICE; i++) {
  241. if (die[i].value == num) {
  242. sum++;
  243. }
  244. if (sum > 1) {
  245. val2 = die[i].value;
  246. check2 = true;
  247. }
  248. }
  249. if (check1 && check2) {
  250. return 25;
  251. }
  252. }
  253. return 0;
  254. }
  255. // # # # # # # # # # # # # # # # # # # # # # # # # # # #
  256. // # I'm dumb so I asked ChatGPT to write the #
  257. // # smallstraight function for me. Then I adapted it #
  258. // # fo the largestraight function. #
  259. // # # # # # # # # # # # # # # # # # # # # # # # # # # #
  260. static uint8_t smallstraight() {
  261. // Create a new array with the frequencies of the different die faces
  262. int8_t frequencies[6] = {0};
  263. for (int8_t i = 0; i < 5; i++) {
  264. int8_t face = die[i].value;
  265. frequencies[face - 1]++;
  266. }
  267. // Check if there is a sequence of 4 consecutive die faces with at least one die
  268. bool found_small_straight = false;
  269. for (int i = 0; i < 3 && !found_small_straight; i++) {
  270. if (frequencies[i] > 0 && frequencies[i + 1] > 0 && frequencies[i + 2] > 0 && frequencies[i + 3] > 0) {
  271. found_small_straight = true;
  272. }
  273. }
  274. if (found_small_straight) {
  275. return 30;
  276. } else {
  277. return 0;
  278. }
  279. }
  280. static uint8_t largestraight() {
  281. // Create a new array with the frequencies of the different die faces
  282. int8_t frequencies[6] = {0};
  283. for (int8_t i = 0; i < 5; i++) {
  284. int8_t face = die[i].value;
  285. frequencies[face - 1]++;
  286. }
  287. // Check if there is a sequence of 4 consecutive die faces with at least one die
  288. bool found_large_straight = false;
  289. for (int i = 0; i < 3 && !found_large_straight; i++) {
  290. if (frequencies[i] > 0 && frequencies[i + 1] > 0 && frequencies[i + 2] > 0 && frequencies[i + 3] > 0 && frequencies[i + 4] > 0) {
  291. found_large_straight = true;
  292. }
  293. }
  294. if (found_large_straight) {
  295. return 40;
  296. } else {
  297. return 0;
  298. }
  299. }
  300. static uint8_t chance() {
  301. // chance allows your roll to count for the raw number of pips showing
  302. int8_t sum = 0;
  303. for (int8_t i = 0; i<MAX_DICE; i++) {
  304. sum+=die[i].value;
  305. }
  306. return sum;
  307. }
  308. static uint8_t yatzee() {
  309. // checks if all die.values are equal to the first die
  310. int8_t val = die[0].value;
  311. for (int8_t i=1; i<MAX_DICE; i++) {
  312. // if value is the same as the first die, continue to next
  313. if (die[i].value == val){
  314. continue;
  315. } else {
  316. // if any value is not equal to the first die,
  317. // this is not a yatzee and we return 0
  318. return 0;
  319. }
  320. }
  321. return 50;
  322. }
  323. // # # # # # # # # # # # # # # # # # # # # # # # # # #
  324. // # Method to return true if yatzee returns 50 #
  325. // # #
  326. // # # # # # # # # # # # # # # # # # # # # # # # # # #
  327. // static bool check_for_bonus_yatzee() {
  328. // if (yatzee()==50){
  329. // return true;
  330. // } else {
  331. // return false;
  332. // }
  333. // }
  334. // Scorecard defined here so that we can use pointers to the functions
  335. // defined above
  336. Score scorecard[13] = {
  337. {.name = "1", .value = 0, .used = false, .row=0, .col=0, .fn = &ones},
  338. {.name = "2", .value = 0, .used = false, .row=1, .col=0, .fn = &twos},
  339. {.name = "3", .value = 0, .used = false,.row=2, .col=0, .fn = &threes},
  340. {.name = "4", .value = 0, .used = false, .row=3, .col=0, .fn = &fours},
  341. {.name = "5", .value = 0, .used = false, .row=0, .col=1, .fn = &fives},
  342. {.name = "6", .value = 0, .used = false, .row=1, .col=1, .fn = &sixes},
  343. {.name = "3k", .value = 0, .used = false, .row=2, .col=1, .fn = &threekind},
  344. {.name = "4k", .value = 0, .used = false, .row=3, .col=1, .fn = &fourkind},
  345. {.name = "Fh", .value = 0, .used = false, .row=0, .col=2, .fn = &fullhouse},
  346. {.name = "Sm", .value = 0, .used = false, .row=1, .col=2, .fn = &smallstraight},
  347. {.name = "Lg", .value = 0, .used = false, .row=2, .col=2, .fn = &largestraight},
  348. {.name = "Ch", .value = 0, .used = false, .row=3, .col=2, .fn = &chance},
  349. {.name = "Yz", .value = 0, .used = false, .row = 2, .col = 3, .fn = &yatzee},
  350. };
  351. // #############################################
  352. // # begin draw callback #
  353. // # #
  354. // #############################################
  355. // define the callback for telling ViewPort how to update the screen
  356. // not sure what ctx is but it seems important
  357. static void app_draw_callback(Canvas* canvas, void* ctx) {
  358. UNUSED(ctx);
  359. canvas_set_font(canvas, FontSecondary); //define a font so we can put letters on the screen
  360. int8_t selectorOffsetX = 8;
  361. int8_t selectorOffsetY = 16;
  362. char buffer[36];
  363. char bigbuffer[256];
  364. canvas_clear(canvas);
  365. // if new_game, show user instructions
  366. if (new_game) {
  367. canvas_set_font(canvas, FontPrimary);
  368. elements_multiline_text_aligned(canvas, 64,0, AlignCenter, AlignTop, "Yatzee!");
  369. canvas_set_font(canvas, FontSecondary);
  370. snprintf(bigbuffer, sizeof(bigbuffer), "Up: Roll\nLeft/Right: Move cursor\nOK: Hold Die\nDown: Score");
  371. elements_multiline_text_aligned(canvas, 0, 8, AlignLeft, AlignTop, bigbuffer);
  372. elements_button_center(canvas, "Start!");
  373. return;
  374. } else {
  375. // draw border lines
  376. canvas_draw_line(canvas, 0, 37, 104, 37);
  377. canvas_draw_line(canvas, 104, 0, 104, 64);
  378. // iterate through dice and draw icon that correlates to die[n].value, and the x,y position indicated by position[die[i].index]
  379. for (int8_t i = 0; i < 5; i++) {
  380. if (die[i].value == 1) {
  381. canvas_draw_icon(canvas, position[die[i].index].x % 128, position[die[i].index].y % 64, &I_die_1);
  382. } else if (die[i].value == 2) {
  383. canvas_draw_icon(canvas, position[die[i].index].x % 128, position[die[i].index].y % 64, &I_die_2);
  384. } else if (die[i].value == 3) {
  385. canvas_draw_icon(canvas, position[die[i].index].x % 128, position[die[i].index].y % 64, &I_die_3);
  386. } else if (die[i].value == 4) {
  387. canvas_draw_icon(canvas, position[die[i].index].x % 128, position[die[i].index].y % 64, &I_die_4);
  388. } else if (die[i].value == 5) {
  389. canvas_draw_icon(canvas, position[die[i].index].x % 128, position[die[i].index].y % 64, &I_die_5);
  390. } else if (die[i].value == 6) {
  391. canvas_draw_icon(canvas, position[die[i].index].x % 128, position[die[i].index].y % 64, &I_die_6);
  392. }
  393. }
  394. // Puts an '*' above the die if hold is selected.
  395. int8_t holdOffsetX = 8;
  396. int8_t holdOffsetY = -5;
  397. for (int8_t i = 0; i < 5; i++) {
  398. if (die[i].isHeld == 1) {
  399. elements_multiline_text_aligned(
  400. canvas, position[die[i].index].x+holdOffsetX,
  401. position[die[i].index].y+holdOffsetY, AlignCenter, AlignTop, HOLD);
  402. }
  403. }
  404. // Update die cursor location
  405. if (cursor.index != -1) {
  406. elements_multiline_text_aligned(
  407. canvas, position[cursor.index].x+selectorOffsetX,
  408. position[cursor.index].y+selectorOffsetY, AlignCenter, AlignTop, cursor.symbol);
  409. }
  410. // Update score cursor location
  411. if (scoreCursor.index != -1) {
  412. elements_multiline_text_aligned(
  413. canvas, score_positions[scoreCursor.index].x,
  414. score_positions[scoreCursor.index].y+1, AlignLeft, AlignTop, scoreCursor.symbol);
  415. }
  416. // Update Roll
  417. // Scores are updated in groups on screen to help with formatting
  418. // first group is scorecard[0:7], second group is [8:12]
  419. // Cycle through first 8 scores, if cursor at score, update to show possible score
  420. // otherwise, show current scores value.
  421. for (int8_t i = 0; i < 8; i++) {
  422. if (scoreCursor.index == i && scorecard[i].used == false) {
  423. int possiblescore = (int)(*scorecard[i].fn)();
  424. snprintf(buffer, sizeof(buffer), "%s: %3u ", scorecard[i].name, possiblescore);
  425. canvas_draw_str_aligned(canvas, 23+29*scorecard[i].col,
  426. 9*scorecard[i].row, AlignRight, AlignTop, buffer);
  427. } else {
  428. uint8_t currentscore = scorecard[i].value;
  429. snprintf(buffer, sizeof(buffer), "%s: %3u ", scorecard[i].name, currentscore);
  430. canvas_draw_str_aligned(canvas, 23+29*scorecard[i].col,
  431. 9*scorecard[i].row, AlignRight, AlignTop, buffer);
  432. }
  433. if (scorecard[i].used) {
  434. canvas_draw_dot(canvas, 23+29*scorecard[i].col, 3+9*scorecard[i].row);
  435. }
  436. }
  437. // cycle through lower scores
  438. // NUM_SCORES minus one because the yatzee is 12 and is handled separately
  439. for (int8_t i = 8; i < NUM_SCORES-1; i++) {
  440. if (scoreCursor.index == i && scorecard[i].used == false) {
  441. int possiblescore = (int)(*scorecard[i].fn)();
  442. snprintf(buffer, sizeof(buffer), " %s: %3u ", scorecard[i].name, possiblescore);
  443. canvas_draw_str_aligned(canvas, 31+27*scorecard[i].col,
  444. 9*scorecard[i].row, AlignRight, AlignTop, buffer);
  445. } else {
  446. uint8_t currentscore = scorecard[i].value;
  447. snprintf(buffer, sizeof(buffer), " %s: %3u ", scorecard[i].name, currentscore);
  448. canvas_draw_str_aligned(canvas, 31+27*scorecard[i].col,
  449. 9*scorecard[i].row, AlignRight, AlignTop, buffer);
  450. }
  451. if (scorecard[i].used) {
  452. canvas_draw_dot(canvas, 31+27*scorecard[i].col, 3+9*scorecard[i].row);
  453. }
  454. }
  455. // update yatzee score
  456. if (scoreCursor.index == 12 && scorecard[12].used == false) {
  457. int possiblescore = (int)(*scorecard[12].fn)();
  458. snprintf(buffer, sizeof(buffer), "Yz\n%u", possiblescore);
  459. elements_multiline_text_aligned(canvas, 93, 10, AlignCenter, AlignTop, buffer);
  460. } else {
  461. snprintf(buffer, sizeof(buffer), "Yz\n%ld", scorecard[12].value);
  462. elements_multiline_text_aligned(canvas, 93, 10, AlignCenter, AlignTop, buffer);
  463. }
  464. // Scores and roll number updated
  465. // sub score shows the 1-6 scores only. If this is >63 at the end of the game,
  466. // a 35 point bonus is added to the total score
  467. snprintf(buffer, sizeof(buffer), "Sub\n%u", upperScore);
  468. elements_multiline_text_aligned(canvas, 117, 0, AlignCenter, AlignTop, buffer);
  469. snprintf(buffer, sizeof(buffer), "Total\n%ld", totalScore);
  470. elements_multiline_text_aligned(canvas, 117, 22, AlignCenter, AlignTop, buffer);
  471. if (totalrolls == 0) {
  472. snprintf(buffer, sizeof(buffer), "Roll\n%s", " ");
  473. elements_multiline_text_aligned(canvas, 117, 64, AlignCenter, AlignBottom, buffer);
  474. } else {
  475. snprintf(buffer, sizeof(buffer), "Roll\n%u", totalrolls);
  476. elements_multiline_text_aligned(canvas, 117, 64, AlignCenter, AlignBottom, buffer);
  477. }
  478. // Check for then handle end of game
  479. // add num_bonus_yatzees to total rounds so that multiple
  480. // yatzees can be scored without impacting the number of rounds before
  481. // the game is over
  482. int8_t total_rounds = num_bonus_yatzees;
  483. // add up number of scores counted so far
  484. for (int8_t i = 0; i<NUM_SCORES; i++) {
  485. if (scorecard[i].used) {
  486. total_rounds++;
  487. }
  488. }
  489. // if total rounds is 13 + the number of bonus rounds,
  490. // thats it, game over.
  491. if (total_rounds == NUM_SCORES+num_bonus_yatzees) {
  492. // if scores of 1-6 add up to 63, a 35 point bonus is bonus_added
  493. // bonus_added = true keeps the game loop from
  494. // adding bonuses indefinetly
  495. if (upperScore >= 63 && bonus_added == false) {
  496. totalScore+=35;
  497. bonus_added = true;
  498. }
  499. // set game over to true and tell the user the game is over
  500. game_over = true;
  501. elements_button_center(canvas, "Game Over");
  502. }
  503. }
  504. }
  505. // define the callback for helping ViewPort get InputEvent and place it in the event_queue defined in the main method
  506. static void app_input_callback(InputEvent* input_event, void* ctx) {
  507. furi_assert(ctx);
  508. FuriMessageQueue* event_queue = ctx;
  509. furi_message_queue_put(event_queue, input_event, FuriWaitForever);
  510. }
  511. // roll them diiiiceeee
  512. static void roll_dice() {
  513. // increment roll count
  514. totalrolls++;
  515. for (uint8_t i = 0; i < MAX_DICE; i++) {
  516. // dont reroll if the dice is being held
  517. if (die[i].isHeld == false) {
  518. die[i].value = 1 + rand() % 6;
  519. }
  520. }
  521. // if 3 rolls have been used, force user to select a score.
  522. if(totalrolls == 3) {
  523. scoreCursor.index = 0;
  524. }
  525. }
  526. static void clear_board() {
  527. // reset board after adding score
  528. totalrolls = 0;
  529. for (int8_t i=0; i < MAX_DICE; i++) {
  530. die[i].isHeld = false;
  531. }
  532. scoreCursor.index = -1;
  533. cursor.index = 0;
  534. }
  535. static void add_score() {
  536. // return when scoring is not possible
  537. if (cursor.index != -1 || totalrolls == 0 || (scorecard[scoreCursor.index].used && strcmp(scorecard[scoreCursor.index].name,"Yz")!=0)){
  538. return;
  539. }
  540. // extra yatzee scores
  541. if (scoreCursor.index == 12 && scorecard[scoreCursor.index].used) {
  542. uint8_t yatzee_score = (*scorecard[12].fn)();
  543. scorecard[12].value += 2*yatzee_score;
  544. lowerScore+=100;
  545. num_bonus_yatzees++;
  546. }
  547. // upper score
  548. for (int8_t i = 0; i < 6; i++) {
  549. if (scoreCursor.index == i && scorecard[scoreCursor.index].used == false) {
  550. scorecard[i].value =(*scorecard[i].fn)();
  551. upperScore+=scorecard[i].value;
  552. scorecard[i].used = true;
  553. }
  554. }
  555. // lower score
  556. for (int8_t i = 6; i < 13; i++) {
  557. if (scoreCursor.index == i && scorecard[scoreCursor.index].used == false) {
  558. scorecard[i].value = (*scorecard[i].fn)();
  559. lowerScore+=scorecard[i].value;
  560. scorecard[i].used = true;
  561. }
  562. }
  563. // recalculate total score
  564. totalScore = lowerScore + upperScore;
  565. clear_board();
  566. }
  567. // Entry Point
  568. int32_t yatzee_main(void* p) {
  569. UNUSED(p);
  570. // Initialize event queue to handle incoming events like button presses
  571. // Use FuriMessageQueue as type as defined in furi api
  572. // InputEvents are supported by app_input_callback
  573. FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
  574. // Initialize viewport
  575. ViewPort* view_port = view_port_alloc();
  576. // Set system callbacks
  577. view_port_draw_callback_set(view_port, app_draw_callback, view_port);
  578. view_port_input_callback_set(view_port, app_input_callback, event_queue);
  579. // Open GUI & register viewport
  580. Gui* gui = furi_record_open(RECORD_GUI);
  581. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  582. // hold input event
  583. InputEvent event;
  584. // Create a loop for the app to run in and handle InputEvents
  585. bool isRunning = true;
  586. while(isRunning) {
  587. if (totalrolls == 3) {
  588. cursor.index = -1;
  589. }
  590. if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) {
  591. if((event.type == InputTypePress) || event.type == InputTypeRepeat) {
  592. switch(event.key) {
  593. case InputKeyLeft:
  594. if(cursor.index == -1) {
  595. if(scoreCursor.index == 0 && totalrolls == 3){
  596. scoreCursor.index = NUM_SCORES-1;
  597. } else if (scoreCursor.index==0) {
  598. scoreCursor.index = -1;
  599. cursor.index = 4;
  600. } else {
  601. scoreCursor.index--;
  602. }
  603. } else {
  604. if(cursor.index == 0) {
  605. cursor.index = -1;
  606. scoreCursor.index = NUM_SCORES-1;
  607. } else {
  608. cursor.index--;
  609. }
  610. }
  611. break;
  612. case InputKeyRight:
  613. // cursor.index == -1 means that scoreCursor is active
  614. if(cursor.index == -1) {
  615. if(scoreCursor.index == NUM_SCORES-1 && totalrolls == 3){
  616. scoreCursor.index = 0;
  617. } else if (scoreCursor.index == NUM_SCORES-1) {
  618. scoreCursor.index = -1;
  619. cursor.index = 0;
  620. } else {
  621. scoreCursor.index++;
  622. }
  623. // if cursor.index is not -1, then dice cursor is active
  624. } else {
  625. if(cursor.index == 4) {
  626. cursor.index = -1;
  627. scoreCursor.index = 0;
  628. } else {
  629. cursor.index++;
  630. }
  631. }
  632. break;
  633. case InputKeyUp:
  634. if (totalrolls < 3) {
  635. roll_dice();
  636. }
  637. // if (check_for_bonus_yatzee() && scorecard[13].used) {
  638. // num_bonus_yatzees++;
  639. // totalScore+=100;
  640. //
  641. // clear_board();
  642. // }
  643. break;
  644. case InputKeyDown:
  645. add_score();
  646. break;
  647. case InputKeyOk:
  648. if (new_game) {
  649. new_game = false;
  650. break;
  651. }
  652. if (game_over) {
  653. isRunning = false;
  654. }
  655. if (cursor.index == -1 || totalrolls == 0) {
  656. break;
  657. }
  658. if (die[cursor.index].isHeld == false) {
  659. die[cursor.index].isHeld = true;
  660. } else {
  661. die[cursor.index].isHeld = false;
  662. }
  663. break;
  664. default:
  665. isRunning = false;
  666. break;
  667. }
  668. }
  669. }
  670. // after every event, update view_port
  671. // uses app_draw_callback which is set before the game loop begins.
  672. view_port_update(view_port);
  673. }
  674. // cleanup
  675. view_port_enabled_set(view_port, false);
  676. gui_remove_view_port(gui, view_port);
  677. view_port_free(view_port);
  678. furi_message_queue_free(event_queue);
  679. furi_record_close(RECORD_GUI);
  680. return 0;
  681. }