emfleak 3 лет назад
Родитель
Сommit
0f839056f4
9 измененных файлов с 794 добавлено и 0 удалено
  1. 13 0
      application.fam
  2. BIN
      images/die_1.png
  3. BIN
      images/die_2.png
  4. BIN
      images/die_3.png
  5. BIN
      images/die_4.png
  6. BIN
      images/die_5.png
  7. BIN
      images/die_6.png
  8. BIN
      images/yatzee_icon_10px.png
  9. 781 0
      yatzee.c

+ 13 - 0
application.fam

@@ -0,0 +1,13 @@
+App(
+    appid="yatzee",
+    name="Yatzee",
+    apptype=FlipperAppType.EXTERNAL,
+    entry_point="yatzee_main",
+    requires=["gui"],
+    stack_size=4 * 1024,
+    order=99,
+    fap_icon="images/yatzee_icon_10px.png",
+    fap_category="Games",
+    fap_icon_assets="images",
+
+)

BIN
images/die_1.png


BIN
images/die_2.png


BIN
images/die_3.png


BIN
images/die_4.png


BIN
images/die_5.png


BIN
images/die_6.png


BIN
images/yatzee_icon_10px.png


+ 781 - 0
yatzee.c

@@ -0,0 +1,781 @@
+#include "yatzee_icons.h"
+
+#include <furi.h>
+#include <furi_hal.h>
+
+#include <gui/gui.h>
+#include <gui/elements.h>
+#include <input/input.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#define BASE_X 18
+#define BASE_Y 44
+#define DICE_OFFSET 12
+#define HOLD "*"
+#define MAX_DICE 5
+#define NUM_SCORES 13
+
+bool new_game = true;
+bool game_over = false;
+bool bonus_added = false;
+int8_t num_bonus_yatzees = 0;
+
+//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
+// struct to hold image posistion for dice
+typedef struct {
+    //    +-----x
+    //    |
+    //    |
+    //    y
+    uint8_t x;
+    uint8_t y;
+} ImagePosition;
+
+
+typedef struct {
+  char* name;
+  uint32_t value;
+  bool used;
+  int8_t row;
+  int8_t col;
+  uint8_t (*fn)(); // pointer to function that calculates score
+} Score;
+
+typedef struct {
+    uint8_t index;
+    uint8_t value;
+    bool isHeld;
+} Die;
+
+typedef struct {
+    int index;
+    char* symbol;
+} Cursor;
+
+// locations for the dice images
+ImagePosition position[5] = {
+  {.x = BASE_X-DICE_OFFSET, .y = BASE_Y},
+  {.x = BASE_X*2-DICE_OFFSET, .y = BASE_Y},
+  {.x = BASE_X*3-DICE_OFFSET, .y = BASE_Y},
+  {.x = BASE_X*4-DICE_OFFSET, .y = BASE_Y},
+  {.x = BASE_X*5-DICE_OFFSET, .y = BASE_Y},
+};
+
+// these are the positions that the score cursor will cycle through
+ImagePosition score_positions[13] = {
+  {.x=15, .y=0},
+  {.x=15, .y=9},
+  {.x=15, .y=18},
+  {.x=15, .y=27},
+  {.x=44, .y=0},
+  {.x=44, .y=9},
+  {.x=44, .y=18},
+  {.x=44, .y=27},
+  {.x=77, .y=0},
+  {.x=77, .y=9},
+  {.x=77, .y=18},
+  {.x=77, .y=27},
+  {.x=91, .y=21},
+};
+
+// cursor to select dice
+Cursor cursor = {
+  .index = 0,
+  .symbol = "^"
+};
+
+// cursor to select score
+Cursor scoreCursor = {
+  .index = -1,
+  .symbol = "_"
+};
+
+// setup array to store dice info
+Die die[5] = {
+  {.index = 0, .value = 1, .isHeld = false},
+  {.index = 1, .value = 1, .isHeld = false},
+  {.index = 2, .value = 1, .isHeld = false},
+  {.index = 3, .value = 1, .isHeld = false},
+  {.index = 4, .value = 1, .isHeld = false},
+};
+
+uint8_t upperScore = 0;
+int32_t lowerScore = 0;
+int32_t totalScore = 0;
+uint8_t roll = 0;
+uint8_t totalrolls = 0;
+
+// #############################################
+// # The following methods add the score for   #
+// # whichever number is mentioned.            #
+// #############################################
+static uint8_t ones() {
+  uint8_t sum = 0;
+  for (uint8_t i = 0; i < 5; i++) {
+    if (die[i].value == 1) {
+      sum++;
+    }
+  }
+  return sum;
+}
+
+static uint8_t twos() {
+  uint8_t sum = 0;
+  for (uint8_t i = 0; i < 5; i++) {
+    if (die[i].value == 2) {
+      sum = sum+2;
+    }
+  }
+  return sum;
+}
+
+static uint8_t threes() {
+  uint8_t sum = 0;
+  for (uint8_t i = 0; i < 5; i++) {
+    if (die[i].value == 3) {
+      sum = sum+3;
+    }
+  }
+  return sum;
+}
+
+static uint8_t fours() {
+  uint8_t sum = 0;
+  for (uint8_t i = 0; i < 5; i++) {
+    if (die[i].value == 4) {
+      sum = sum+4;
+    }
+  }
+  return sum;
+}
+
+static uint8_t fives() {
+  uint8_t sum = 0;
+  for (uint8_t i = 0; i < 5; i++) {
+    if (die[i].value == 5) {
+      sum = sum+5;
+    }
+  }
+  return sum;
+}
+
+static uint8_t sixes() {
+  uint8_t sum = 0;
+  for (uint8_t i = 0; i < 5; i++) {
+    if (die[i].value == 6) {
+      sum = sum+6;
+    }
+  }
+  return sum;
+}
+
+// ####################################################
+// # Helper methods for the special score types       #
+// # defined before them so they can be used          #
+// # since this whole thing is a linear mess          #
+// # lol.                                             #
+// # add_dice:                                        #
+// #    inputs: none                                  #
+// #    output: int8_t value of roll                  #
+// # check_if_score_used:
+// #    inputs: Score
+// #    output: true if score.used = true
+// # # # # # # # # # # # # # # # # # # # # # # # # # #
+int8_t add_dice() {
+  int8_t sum = 0;
+  for (int8_t i=0; i<MAX_DICE; i++) {
+    sum+=die[i].value;
+  } return sum;
+}
+
+bool check_if_score_used(Score score) {
+    if (score.used == true) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+// #############################################
+// # Methods to calculate scores for the fancy #
+// # scoring types: 3 of a kind, 4 of a kind,  #
+// # Full house, small straight, large straight#
+// # chance & yatzee.                          #
+// #############################################
+static uint8_t threekind() {
+  int8_t score = 0;
+  for (int8_t num=1; num<7; num++) {
+    int8_t sum = 0;
+
+    for (int8_t i=0; i<MAX_DICE; i++) {
+      if (die[i].value == num) {
+        sum++;
+      }
+      if (sum > 2) {
+        score = add_dice();
+      }
+    }
+  }
+  return score;
+}
+
+static uint8_t fourkind() {
+  int8_t score = 0;
+  for (int8_t num=1; num<7; num++) {
+    int8_t sum = 0;
+
+    for (int8_t i=0; i<MAX_DICE; i++) {
+      if (die[i].value == num) {
+        sum++;
+      }
+      if (sum > 3) {
+        score = add_dice();
+      }
+    }
+  }
+  return score;
+}
+
+static uint8_t fullhouse() {
+
+  bool check1 = false;
+  bool check2 = false;
+  int8_t val1 = 0;
+  int8_t val2 = 0;
+  UNUSED(val2);
+  UNUSED(val1);
+
+  //check 1 for three of a kind
+  for (int8_t num=1; num<7; num++) {
+    int8_t sum = 0;
+
+    for (int8_t i=0; i<MAX_DICE; i++) {
+      if (die[i].value == num) {
+        sum++;
+      }
+      if (sum > 2) {
+        val1 = die[i].value;
+        check1 = true;
+      }
+    }
+  }
+
+  // return if check 1 failed
+  if (check1 == false) {
+    return 0;
+  }
+
+  // check 2 for two of a kind.
+  for (int8_t num=1; num<7; num++) {
+    if (num==val1) {continue;}
+    int8_t sum = 0;
+
+    for (int8_t i=0; i<MAX_DICE; i++) {
+      if (die[i].value == num) {
+        sum++;
+      }
+      if (sum > 1) {
+        val2 = die[i].value;
+        check2 = true;
+      }
+    }
+    if (check1 && check2) {
+      return 25;
+    }
+  }
+  return 0;
+}
+
+// # # # # # # # # # # # # # # # # # # # # # # # # # # #
+// # I'm dumb so I asked ChatGPT to write the          #
+// # smallstraight function for me. Then I adapted it  #
+// # fo the largestraight function.                    #
+// # # # # # # # # # # # # # # # # # # # # # # # # # # #
+static uint8_t smallstraight() {
+    // Create a new array with the frequencies of the different die faces
+    int8_t frequencies[6] = {0};
+
+    for (int8_t i = 0; i < 5; i++) {
+      int8_t face = die[i].value;
+      frequencies[face - 1]++;
+    }
+
+    // Check if there is a sequence of 4 consecutive die faces with at least one die
+    bool found_small_straight = false;
+    for (int i = 0; i < 3 && !found_small_straight; i++) {
+      if (frequencies[i] > 0 && frequencies[i + 1] > 0 && frequencies[i + 2] > 0 && frequencies[i + 3] > 0) {
+        found_small_straight = true;
+      }
+    }
+
+    if (found_small_straight) {
+      return 30;
+    } else {
+      return 0;
+    }
+}
+
+static uint8_t largestraight() {
+    // Create a new array with the frequencies of the different die faces
+    int8_t frequencies[6] = {0};
+
+    for (int8_t i = 0; i < 5; i++) {
+      int8_t face = die[i].value;
+      frequencies[face - 1]++;
+    }
+
+    // Check if there is a sequence of 4 consecutive die faces with at least one die
+    bool found_large_straight = false;
+    for (int i = 0; i < 3 && !found_large_straight; i++) {
+      if (frequencies[i] > 0 && frequencies[i + 1] > 0 && frequencies[i + 2] > 0 && frequencies[i + 3] > 0 && frequencies[i + 4] > 0) {
+        found_large_straight = true;
+      }
+    }
+
+    if (found_large_straight) {
+      return 40;
+    } else {
+      return 0;
+    }
+}
+
+static uint8_t chance() {
+  // chance allows your roll to count for the raw number of pips showing
+  int8_t sum = 0;
+  for (int8_t i = 0; i<MAX_DICE; i++) {
+    sum+=die[i].value;
+  }
+  return sum;
+}
+
+static uint8_t yatzee() {
+  // checks if all die.values are equal to the first die
+  int8_t val = die[0].value;
+  for (int8_t i=1; i<MAX_DICE; i++) {
+    // if value is the same as the first die, continue to next
+    if (die[i].value == val){
+      continue;
+    } else {
+      // if any value is not equal to the first die,
+      // this is not a yatzee and we return 0
+      return 0;
+    }
+  }
+  return 50;
+}
+
+// # # # # # # # # # # # # # # # # # # # # # # # # # #
+// # Method to return true if yatzee returns 50      #
+// #                                                 #
+// # # # # # # # # # # # # # # # # # # # # # # # # # #
+// static bool check_for_bonus_yatzee() {
+//   if (yatzee()==50){
+//     return true;
+//   } else {
+//     return false;
+//   }
+// }
+
+// Scorecard defined here so that we can use pointers to the functions
+// defined above
+Score scorecard[13] = {
+  {.name = "1", .value = 0, .used = false,  .row=0, .col=0, .fn = &ones},
+  {.name = "2", .value = 0, .used = false,  .row=1, .col=0, .fn = &twos},
+  {.name = "3", .value = 0, .used = false,.row=2, .col=0, .fn = &threes},
+  {.name = "4", .value = 0, .used = false, .row=3, .col=0, .fn = &fours},
+  {.name = "5", .value = 0, .used = false, .row=0, .col=1, .fn = &fives},
+  {.name = "6", .value = 0, .used = false, .row=1, .col=1, .fn = &sixes},
+  {.name = "3k", .value = 0, .used = false, .row=2, .col=1, .fn = &threekind},
+  {.name = "4k", .value = 0, .used = false, .row=3, .col=1, .fn = &fourkind},
+  {.name = "Fh", .value = 0, .used = false, .row=0, .col=2, .fn = &fullhouse},
+  {.name = "Sm", .value = 0, .used = false, .row=1, .col=2, .fn = &smallstraight},
+  {.name = "Lg", .value = 0, .used = false, .row=2, .col=2, .fn = &largestraight},
+  {.name = "Ch", .value = 0, .used = false, .row=3, .col=2, .fn = &chance},
+  {.name = "Yz", .value = 0, .used = false, .row = 2, .col = 3, .fn = &yatzee},
+};
+
+
+// #############################################
+// # begin draw callback                       #
+// #                                           #
+// #############################################
+// define the callback for telling ViewPort how to update the screen
+// not sure what ctx is but it seems important
+static void app_draw_callback(Canvas* canvas, void* ctx) {
+    UNUSED(ctx);
+    canvas_set_font(canvas, FontSecondary); //define a font so we can put letters on the screen
+    int8_t selectorOffsetX = 8;
+    int8_t selectorOffsetY = 16;
+    char buffer[36];
+    char bigbuffer[256];
+
+    canvas_clear(canvas);
+
+    // if new_game, show user instructions
+    if (new_game) {
+      canvas_set_font(canvas, FontPrimary);
+      elements_multiline_text_aligned(canvas, 64,0, AlignCenter, AlignTop, "Yatzee!");
+      canvas_set_font(canvas, FontSecondary);
+      snprintf(bigbuffer, sizeof(bigbuffer), "Up: Roll\nLeft/Right: Move cursor\nOK: Hold Die\nDown: Score");
+      elements_multiline_text_aligned(canvas, 0, 8, AlignLeft, AlignTop, bigbuffer);
+      elements_button_center(canvas, "Start!");
+      return;
+
+
+    } else {
+
+      // draw border lines
+      canvas_draw_line(canvas, 0, 37, 104, 37);
+      canvas_draw_line(canvas, 104, 0, 104, 64);
+
+      // iterate through dice and draw icon that correlates to die[n].value, and the x,y position indicated by position[die[i].index]
+      for (int8_t i = 0; i < 5; i++) {
+          if (die[i].value == 1) {
+              canvas_draw_icon(canvas, position[die[i].index].x % 128, position[die[i].index].y % 64, &I_die_1);
+          } else if (die[i].value == 2) {
+              canvas_draw_icon(canvas, position[die[i].index].x % 128, position[die[i].index].y % 64, &I_die_2);
+          } else if (die[i].value == 3) {
+              canvas_draw_icon(canvas, position[die[i].index].x % 128, position[die[i].index].y % 64, &I_die_3);
+          } else if (die[i].value == 4) {
+              canvas_draw_icon(canvas, position[die[i].index].x % 128, position[die[i].index].y % 64, &I_die_4);
+          } else if (die[i].value == 5) {
+              canvas_draw_icon(canvas, position[die[i].index].x % 128, position[die[i].index].y % 64, &I_die_5);
+          } else if (die[i].value == 6) {
+              canvas_draw_icon(canvas, position[die[i].index].x % 128, position[die[i].index].y % 64, &I_die_6);
+          }
+      }
+
+      // Puts an '*' above the die if hold is selected.
+      int8_t holdOffsetX = 8;
+      int8_t holdOffsetY = -5;
+      for (int8_t i = 0; i < 5; i++) {
+          if (die[i].isHeld == 1) {
+              elements_multiline_text_aligned(
+                  canvas, position[die[i].index].x+holdOffsetX,
+                    position[die[i].index].y+holdOffsetY, AlignCenter, AlignTop, HOLD);
+          }
+      }
+
+      // Update die cursor location
+      if (cursor.index != -1) {
+          elements_multiline_text_aligned(
+              canvas, position[cursor.index].x+selectorOffsetX,
+                position[cursor.index].y+selectorOffsetY, AlignCenter, AlignTop, cursor.symbol);
+      }
+
+      // Update score cursor location
+      if (scoreCursor.index != -1) {
+          elements_multiline_text_aligned(
+              canvas, score_positions[scoreCursor.index].x,
+                score_positions[scoreCursor.index].y+1, AlignLeft, AlignTop, scoreCursor.symbol);
+      }
+
+      // Update Roll
+
+
+      // Scores are updated in groups on screen to help with formatting
+      // first group is scorecard[0:7], second group is [8:12]
+      // Cycle through first 8 scores, if cursor at score, update to show possible score
+      // otherwise, show current scores value.
+      for (int8_t i = 0; i < 8; i++) {
+          if (scoreCursor.index == i && scorecard[i].used == false) {
+              int possiblescore = (int)(*scorecard[i].fn)();
+
+              snprintf(buffer, sizeof(buffer), "%s: %3u ", scorecard[i].name, possiblescore);
+              canvas_draw_str_aligned(canvas, 23+29*scorecard[i].col,
+                    9*scorecard[i].row, AlignRight, AlignTop, buffer);
+          } else {
+
+              uint8_t currentscore = scorecard[i].value;
+              snprintf(buffer, sizeof(buffer), "%s: %3u ", scorecard[i].name, currentscore);
+              canvas_draw_str_aligned(canvas, 23+29*scorecard[i].col,
+                    9*scorecard[i].row, AlignRight, AlignTop, buffer);
+          }
+          if (scorecard[i].used) {
+              canvas_draw_dot(canvas, 23+29*scorecard[i].col, 3+9*scorecard[i].row);
+          }
+      }
+
+      // cycle through lower scores
+      // NUM_SCORES minus one because the yatzee is 12 and is handled separately
+      for (int8_t i = 8; i < NUM_SCORES-1; i++) {
+          if (scoreCursor.index == i && scorecard[i].used == false) {
+              int possiblescore = (int)(*scorecard[i].fn)();
+
+              snprintf(buffer, sizeof(buffer), " %s: %3u ", scorecard[i].name, possiblescore);
+              canvas_draw_str_aligned(canvas, 31+27*scorecard[i].col,
+                    9*scorecard[i].row, AlignRight, AlignTop, buffer);
+          } else {
+              uint8_t currentscore = scorecard[i].value;
+              snprintf(buffer, sizeof(buffer), " %s: %3u ", scorecard[i].name, currentscore);
+              canvas_draw_str_aligned(canvas, 31+27*scorecard[i].col,
+                    9*scorecard[i].row, AlignRight, AlignTop, buffer);
+          }
+          if (scorecard[i].used) {
+              canvas_draw_dot(canvas, 31+27*scorecard[i].col, 3+9*scorecard[i].row);
+          }
+      }
+
+      // update yatzee score
+      if (scoreCursor.index == 12 && scorecard[12].used == false) {
+          int possiblescore = (int)(*scorecard[12].fn)();
+
+          snprintf(buffer, sizeof(buffer), "Yz\n%u", possiblescore);
+          elements_multiline_text_aligned(canvas, 93, 10, AlignCenter, AlignTop, buffer);
+      } else {
+          snprintf(buffer, sizeof(buffer), "Yz\n%ld", scorecard[12].value);
+          elements_multiline_text_aligned(canvas, 93, 10, AlignCenter, AlignTop, buffer);
+      }
+
+
+      // Scores and roll number updated
+
+      // sub score shows the 1-6 scores only. If this is >63 at the end of the game,
+      // a 35 point bonus is added to the total score
+      snprintf(buffer, sizeof(buffer), "Sub\n%u", upperScore);
+      elements_multiline_text_aligned(canvas, 117, 0, AlignCenter, AlignTop, buffer);
+
+      snprintf(buffer, sizeof(buffer), "Total\n%ld", totalScore);
+      elements_multiline_text_aligned(canvas, 117, 22, AlignCenter, AlignTop, buffer);
+
+      if (totalrolls == 0) {
+          snprintf(buffer, sizeof(buffer), "Roll\n%s", " ");
+          elements_multiline_text_aligned(canvas, 117, 64, AlignCenter, AlignBottom, buffer);
+      } else {
+          snprintf(buffer, sizeof(buffer), "Roll\n%u", totalrolls);
+          elements_multiline_text_aligned(canvas, 117, 64, AlignCenter, AlignBottom, buffer);
+      }
+
+      // Check for then handle end of game
+
+      // add num_bonus_yatzees to total rounds so that multiple
+      // yatzees can be scored without impacting the number of rounds before
+      // the game is over
+      int8_t total_rounds = num_bonus_yatzees;
+      // add up number of scores counted so far
+      for (int8_t i = 0; i<NUM_SCORES; i++) {
+          if (scorecard[i].used) {
+              total_rounds++;
+          }
+      }
+
+      // if total rounds is 13 + the number of bonus rounds,
+      // thats it, game over.
+      if (total_rounds == NUM_SCORES+num_bonus_yatzees) {
+          // if scores of 1-6 add up to 63, a 35 point bonus is bonus_added
+          // bonus_added = true keeps the game loop from
+          // adding bonuses indefinetly
+          if (upperScore >= 63 && bonus_added == false) {
+            totalScore+=35;
+            bonus_added = true;
+          }
+          // set game over to true and tell the user the game is over
+          game_over = true;
+          elements_button_center(canvas, "Game Over");
+    }
+  }
+}
+
+// define the callback for helping ViewPort get InputEvent and place it in the event_queue defined in the main method
+static void app_input_callback(InputEvent* input_event, void* ctx) {
+    furi_assert(ctx);
+
+    FuriMessageQueue* event_queue = ctx;
+    furi_message_queue_put(event_queue, input_event, FuriWaitForever);
+}
+
+// roll them diiiiceeee
+static void roll_dice() {
+    // increment roll count
+    totalrolls++;
+    for (uint8_t i = 0; i < MAX_DICE; i++) {
+        // dont reroll if the dice is being held
+        if (die[i].isHeld == false) {
+            die[i].value = 1 + rand() % 6;
+        }
+    }
+    // if 3 rolls have been used, force user to select a score.
+    if(totalrolls == 3) {
+        scoreCursor.index = 0;
+    }
+}
+
+static void clear_board() {
+  // reset board after adding score
+  totalrolls = 0;
+  for (int8_t i=0; i < MAX_DICE; i++) {
+      die[i].isHeld = false;
+  }
+  scoreCursor.index = -1;
+  cursor.index = 0;
+}
+
+static void add_score() {
+    // return when scoring is not possible
+    if (cursor.index != -1 || totalrolls == 0 || (scorecard[scoreCursor.index].used && strcmp(scorecard[scoreCursor.index].name,"Yz")!=0)){
+        return;
+    }
+
+    // extra yatzee scores
+    if (scoreCursor.index == 12 && scorecard[scoreCursor.index].used) {
+              uint8_t yatzee_score = (*scorecard[12].fn)();
+              scorecard[12].value += 2*yatzee_score;
+              lowerScore+=100;
+              num_bonus_yatzees++;
+      }
+
+
+    // upper score
+    for (int8_t i = 0; i < 6; i++) {
+        if (scoreCursor.index == i && scorecard[scoreCursor.index].used == false) {
+            scorecard[i].value =(*scorecard[i].fn)();
+            upperScore+=scorecard[i].value;
+            scorecard[i].used = true;
+        }
+    }
+
+    // lower score
+    for (int8_t i = 6; i < 13; i++) {
+        if (scoreCursor.index == i && scorecard[scoreCursor.index].used == false) {
+            scorecard[i].value = (*scorecard[i].fn)();
+            lowerScore+=scorecard[i].value;
+            scorecard[i].used = true;
+      }
+    }
+
+    // recalculate total score
+    totalScore = lowerScore + upperScore;
+    clear_board();
+}
+
+
+
+
+// Entry Point
+int32_t yatzee_main(void* p) {
+    UNUSED(p);
+
+    // Initialize event queue to handle incoming events like button presses
+    // Use FuriMessageQueue as type as defined in furi api
+    // InputEvents are supported by app_input_callback
+    FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
+
+    // Initialize viewport
+    ViewPort* view_port = view_port_alloc();
+
+    // Set system callbacks
+    view_port_draw_callback_set(view_port, app_draw_callback, view_port);
+    view_port_input_callback_set(view_port, app_input_callback, event_queue);
+
+    // Open GUI & register viewport
+    Gui* gui = furi_record_open(RECORD_GUI);
+    gui_add_view_port(gui, view_port, GuiLayerFullscreen);
+
+    // hold input event
+    InputEvent event;
+
+    // Create a loop for the app to run in and handle InputEvents
+    bool isRunning = true;
+
+    while(isRunning) {
+
+      if (totalrolls == 3) {
+        cursor.index = -1;
+      }
+        if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) {
+            if((event.type == InputTypePress) || event.type == InputTypeRepeat) {
+                switch(event.key) {
+                    case InputKeyLeft:
+                        if(cursor.index == -1) {
+                            if(scoreCursor.index == 0 && totalrolls == 3){
+                              scoreCursor.index = NUM_SCORES-1;
+                            } else if (scoreCursor.index==0) {
+                                scoreCursor.index = -1;
+                                cursor.index = 4;
+                            } else {
+                                scoreCursor.index--;
+                            }
+                        } else {
+                            if(cursor.index == 0) {
+                                cursor.index = -1;
+                                scoreCursor.index = NUM_SCORES-1;
+                            } else {
+                                cursor.index--;
+                            }
+                        }
+                        break;
+                    case InputKeyRight:
+                        // cursor.index == -1 means that scoreCursor is active
+                        if(cursor.index == -1) {
+                            if(scoreCursor.index == NUM_SCORES-1 && totalrolls == 3){
+                                scoreCursor.index = 0;
+                            } else if (scoreCursor.index == NUM_SCORES-1) {
+                                scoreCursor.index = -1;
+                                cursor.index = 0;
+                            } else {
+                                scoreCursor.index++;
+                            }
+                        // if cursor.index is not -1, then dice cursor is active
+                        } else {
+                            if(cursor.index == 4) {
+                                cursor.index = -1;
+                                scoreCursor.index = 0;
+                            } else {
+                                cursor.index++;
+                            }
+                        }
+                        break;
+                    case InputKeyUp:
+
+                        if (totalrolls < 3) {
+                            roll_dice();
+                        }
+                        // if (check_for_bonus_yatzee() && scorecard[13].used) {
+                        //   num_bonus_yatzees++;
+                        //   totalScore+=100;
+                        //
+                        //   clear_board();
+                        // }
+                        break;
+                    case InputKeyDown:
+                        add_score();
+                        break;
+                    case InputKeyOk:
+                        if (new_game) {
+                          new_game = false;
+                          break;
+                        }
+                        if (game_over) {
+                          isRunning = false;
+                        }
+                        if (cursor.index == -1 || totalrolls == 0) {
+                            break;
+                        }
+                        if (die[cursor.index].isHeld == false) {
+                            die[cursor.index].isHeld = true;
+                        } else {
+                            die[cursor.index].isHeld = false;
+                        }
+                      break;
+                    default:
+                        isRunning = false;
+                        break;
+            }
+          }
+        }
+        // after every event, update view_port
+        // uses app_draw_callback which is set before the game loop begins.
+        view_port_update(view_port);
+    }
+
+    // cleanup
+    view_port_enabled_set(view_port, false);
+    gui_remove_view_port(gui, view_port);
+    view_port_free(view_port);
+    furi_message_queue_free(event_queue);
+    furi_record_close(RECORD_GUI);
+
+    return 0;
+}