Commit c040a344 authored by Chris's avatar Chris
Browse files

replaced unnecessary string comparisons with enums and switches

parent 89e55ede
Loading
Loading
Loading
Loading
+126 −99
Original line number Diff line number Diff line
@@ -108,29 +108,36 @@ void clear_held_values(game_context *ctx) {
}

// todo: this should only map the selection to the method, and then yaht.c will handle the scoreboard assignment (I think -- revisit to confirm)
unsigned int calculate_selection_score(game_context *ctx, char *selection) {
unsigned int calculate_selection_score(game_context *ctx, enum scorecard_command selection) {
    // discern score action based on the scoring selection
    // we pass in a whole game_context because we need to write to the scorecard and read the dice values
    int points_awarded = 0;
    if (strcasecmp(selection, "aces") == 0) {
    switch (selection) {
        case ACES:
            ctx->game_state.scorecard.aces = sum_dice_matching_value(ctx->game_state.dice, 1);
            points_awarded = ctx->game_state.scorecard.aces;
    } else if (strcasecmp(selection, "twos") == 0) {
            break;
        case TWOS:
            ctx->game_state.scorecard.twos = sum_dice_matching_value(ctx->game_state.dice, 2);
            points_awarded = ctx->game_state.scorecard.twos;
    } else if (strcasecmp(selection, "threes") == 0) {
            break;
        case THREES:
            ctx->game_state.scorecard.threes = sum_dice_matching_value(ctx->game_state.dice, 3);
            points_awarded = ctx->game_state.scorecard.threes;
    } else if (strcasecmp(selection, "fours") == 0) {
            break;
        case FOURS:
            ctx->game_state.scorecard.fours = sum_dice_matching_value(ctx->game_state.dice, 4);
            points_awarded = ctx->game_state.scorecard.fours;
    } else if (strcasecmp(selection, "fives") == 0) {
            break;
        case FIVES:
            ctx->game_state.scorecard.fives = sum_dice_matching_value(ctx->game_state.dice, 5);
            points_awarded = ctx->game_state.scorecard.fives;
    } else if (strcasecmp(selection, "sixes") == 0) {
            break;
        case SIXES:
            ctx->game_state.scorecard.sixes = sum_dice_matching_value(ctx->game_state.dice, 6);
            points_awarded = ctx->game_state.scorecard.sixes;
    } else if (strcasecmp(selection, "three of a kind") == 0) {
            break;
        case THREE_OF_A_KIND:
            // sum all dice if 3 of a kind match; 0 otherwise
            if (n_of_a_kind(ctx->game_state.dice, NUM_DICE, 3, 0)) {
                ctx->game_state.scorecard.three_of_a_kind = sum_dice(ctx->game_state.dice);
@@ -138,7 +145,8 @@ unsigned int calculate_selection_score(game_context *ctx, char *selection) {
                ctx->game_state.scorecard.three_of_a_kind = 0;
            }
            points_awarded = ctx->game_state.scorecard.three_of_a_kind;
    } else if (strcasecmp(selection, "four of a kind") == 0) {
            break;
        case FOUR_OF_A_KIND:
            // sum all dice if 4 of a kind match; 0 otherwise
            if (n_of_a_kind(ctx->game_state.dice, NUM_DICE, 4, 0)) {
                ctx->game_state.scorecard.four_of_a_kind = sum_dice(ctx->game_state.dice);
@@ -146,20 +154,8 @@ unsigned int calculate_selection_score(game_context *ctx, char *selection) {
                ctx->game_state.scorecard.four_of_a_kind = 0;
            }
            points_awarded = ctx->game_state.scorecard.four_of_a_kind;
    } else if (strcasecmp(selection, "full house") == 0) {
        // 25 points for a combination of three of one number + two of another; 0 otherwise
        unsigned int three_of_a_kind_value = n_of_a_kind(ctx->game_state.dice, NUM_DICE, 3, 0);
        unsigned int two_of_a_kind_value = 0;
        if (three_of_a_kind_value) {
            two_of_a_kind_value = n_of_a_kind(ctx->game_state.dice, NUM_DICE, 2, three_of_a_kind_value);
        }
        if (three_of_a_kind_value && two_of_a_kind_value) {
            ctx->game_state.scorecard.full_house = 25;
        } else {
            ctx->game_state.scorecard.full_house = 0;
        }
        points_awarded = ctx->game_state.scorecard.full_house;
    } else if (strcasecmp(selection, "small straight") == 0) {
            break;
        case SMALL_STRAIGHT:
            // 30 points for a sequence of four consecutive numbers; 0 otherwise
            if (n_in_a_row(ctx->game_state.dice, NUM_DICE, 4)) {
                ctx->game_state.scorecard.small_straight = 30;
@@ -167,7 +163,8 @@ unsigned int calculate_selection_score(game_context *ctx, char *selection) {
                ctx->game_state.scorecard.small_straight = 0;
            }
            points_awarded = ctx->game_state.scorecard.small_straight;
    } else if (strcasecmp(selection, "large straight") == 0) {
            break;
        case LARGE_STRAIGHT:
            // 40 points for a sequence of five consecutive numbers; 0 otherwise
            if (n_in_a_row(ctx->game_state.dice, NUM_DICE, 5)) {
                ctx->game_state.scorecard.large_straight = 40;
@@ -175,7 +172,22 @@ unsigned int calculate_selection_score(game_context *ctx, char *selection) {
                ctx->game_state.scorecard.large_straight = 0;
            }
            points_awarded = ctx->game_state.scorecard.large_straight;
    } else if (strcasecmp(selection, "yahtc") == 0) {
            break;
        case FULL_HOUSE:
            // 25 points for a combination of three of one number + two of another; 0 otherwise
            unsigned int three_of_a_kind_value = n_of_a_kind(ctx->game_state.dice, NUM_DICE, 3, 0);
            unsigned int two_of_a_kind_value = 0;
            if (three_of_a_kind_value) {
                two_of_a_kind_value = n_of_a_kind(ctx->game_state.dice, NUM_DICE, 2, three_of_a_kind_value);
            }
            if (three_of_a_kind_value && two_of_a_kind_value) {
                ctx->game_state.scorecard.full_house = 25;
            } else {
                ctx->game_state.scorecard.full_house = 0;
            }
            points_awarded = ctx->game_state.scorecard.full_house;
            break;
        case YAHTC:
            // 50 points for five of a kind; 0 otherwise
            if (n_of_a_kind(ctx->game_state.dice, NUM_DICE, NUM_DICE, 0)) {
                ctx->game_state.scorecard.yahtc = 50;
@@ -183,10 +195,14 @@ unsigned int calculate_selection_score(game_context *ctx, char *selection) {
                ctx->game_state.scorecard.yahtc = 0;
            }
            points_awarded = ctx->game_state.scorecard.yahtc;
    } else if (strcasecmp(selection, "chance") == 0) {
            break;
        case CHANCE:
            // sum of all dice
            ctx->game_state.scorecard.chance = sum_dice(ctx->game_state.dice);
            points_awarded = ctx->game_state.scorecard.chance;
            break;
        case SCORING_MENU_BACK:
            break;
    }

    return points_awarded;
@@ -235,11 +251,6 @@ void hold_dice_with_menu(struct die_st *dice, unsigned int num_dice) {

        dice_hold_selections[i].enabled = 1;

        // todo cm delete: you don't even need a command for this because we go by the "multi_selected" value for dice hold assignments
//        dice_hold_selections[i].command = malloc(SCORECARD_NUM_ITEMS * sizeof(char));
//        sprintf(dice_hold_selections[i].command, "toggle_hold_%1d", i);
        dice_hold_selections[i].command = "";

    }
    char *action = menu_prompt_multi_select(dice_hold_selections, num_dice, "Hold dice", "held");

@@ -252,28 +263,25 @@ void hold_dice_with_menu(struct die_st *dice, unsigned int num_dice) {
        if (dice_hold_selections[i].title) {
            free(dice_hold_selections[i].title);
        }
//        if (dice_hold_selections[i].command) {
//            free(dice_hold_selections[i].command);
//        }
    }
}

char *get_player_score_selection_with_menu(struct scorecard_st *scorecard) {
int get_player_score_selection_with_menu(struct scorecard_st *scorecard) {
    const menu_item scoring_menu[] = {
            {.title = "aces", .command = "aces", .multi_selected = 0, .enabled = scorecard->aces == SCORE_UNSCORED},
            {.title = "twos", .command = "twos", .multi_selected = 0, .enabled = scorecard->twos == SCORE_UNSCORED},
            {.title = "threes", .command = "threes", .multi_selected = 0, .enabled = scorecard->threes == SCORE_UNSCORED},
            {.title = "fours", .command = "fours", .multi_selected = 0, .enabled = scorecard->fours == SCORE_UNSCORED},
            {.title = "fives", .command = "fives", .multi_selected = 0, .enabled = scorecard->fives == SCORE_UNSCORED},
            {.title = "sixes", .command = "sixes", .multi_selected = 0, .enabled = scorecard->sixes == SCORE_UNSCORED},
            {.title = "three of a kind", .command = "three of a kind", .multi_selected = 0, .enabled = scorecard->three_of_a_kind == SCORE_UNSCORED},
            {.title = "four of a kind", .command = "four of a kind", .multi_selected = 0, .enabled = scorecard->four_of_a_kind == SCORE_UNSCORED},
            {.title = "small straight", .command = "small straight", .multi_selected = 0, .enabled = scorecard->small_straight == SCORE_UNSCORED},
            {.title = "large straight", .command = "large straight", .multi_selected = 0, .enabled = scorecard->large_straight == SCORE_UNSCORED},
            {.title = "full house", .command = "full house", .multi_selected = 0, .enabled = scorecard->full_house == SCORE_UNSCORED},
            {.title = "yahtc", .command = "yahtc", .multi_selected = 0, .enabled = scorecard->yahtc == SCORE_UNSCORED},
            {.title = "chance", .command = "chance", .multi_selected = 0, .enabled = scorecard->chance == SCORE_UNSCORED},
            {.title = "{BACK}", .command = "back", .multi_selected = 0, .enabled = 1}
            {.title = "aces", .command = ACES, .multi_selected = 0, .enabled = scorecard->aces == SCORE_UNSCORED},
            {.title = "twos", .command = TWOS, .multi_selected = 0, .enabled = scorecard->twos == SCORE_UNSCORED},
            {.title = "threes", .command = THREES, .multi_selected = 0, .enabled = scorecard->threes == SCORE_UNSCORED},
            {.title = "fours", .command = FOURS, .multi_selected = 0, .enabled = scorecard->fours == SCORE_UNSCORED},
            {.title = "fives", .command = FIVES, .multi_selected = 0, .enabled = scorecard->fives == SCORE_UNSCORED},
            {.title = "sixes", .command = SIXES, .multi_selected = 0, .enabled = scorecard->sixes == SCORE_UNSCORED},
            {.title = "three of a kind", .command = THREE_OF_A_KIND, .multi_selected = 0, .enabled = scorecard->three_of_a_kind == SCORE_UNSCORED},
            {.title = "four of a kind", .command = FOUR_OF_A_KIND, .multi_selected = 0, .enabled = scorecard->four_of_a_kind == SCORE_UNSCORED},
            {.title = "small straight", .command = SMALL_STRAIGHT, .multi_selected = 0, .enabled = scorecard->small_straight == SCORE_UNSCORED},
            {.title = "large straight", .command = LARGE_STRAIGHT, .multi_selected = 0, .enabled = scorecard->large_straight == SCORE_UNSCORED},
            {.title = "full house", .command = FULL_HOUSE, .multi_selected = 0, .enabled = scorecard->full_house == SCORE_UNSCORED},
            {.title = "yahtc", .command = YAHTC, .multi_selected = 0, .enabled = scorecard->yahtc == SCORE_UNSCORED},
            {.title = "chance", .command = CHANCE, .multi_selected = 0, .enabled = scorecard->chance == SCORE_UNSCORED},
            {.title = "{BACK}", .command = SCORING_MENU_BACK, .multi_selected = 0, .enabled = 1}
    };
    unsigned int num_menu_items = sizeof(scoring_menu) / sizeof(menu_item);
    return menu_prompt(scoring_menu, num_menu_items, "Scoring", "already played");
@@ -367,3 +375,22 @@ unsigned int n_in_a_row(struct die_st *dice, unsigned int num_dice, unsigned int
    }
    return 0;
}

const char *command_name[] = {
    "aces",
    "twos",
    "threes",
    "fours",
    "fives",
    "sixes",
    "three of a kind",
    "four of a kind",
    "small straight",
    "large straight",
    "yahtc",
    "chance",
    ""
};
const char *name_of_scorecard_command(enum scorecard_command command) {
    return command_name[command];
}
+20 −2
Original line number Diff line number Diff line
@@ -33,6 +33,23 @@ struct scorecard_st {
};
extern const unsigned int SCORECARD_NUM_ITEMS;

enum scorecard_command {
    ACES,
    TWOS,
    THREES,
    FOURS,
    FIVES,
    SIXES,
    THREE_OF_A_KIND,
    FOUR_OF_A_KIND,
    SMALL_STRAIGHT,
    LARGE_STRAIGHT,
    FULL_HOUSE,
    YAHTC,
    CHANCE,
    SCORING_MENU_BACK
};

struct game_state_st {
    struct die_st dice[5];
    struct scorecard_st scorecard;
@@ -57,11 +74,12 @@ int sum_dice_matching_value(struct die_st *dice, unsigned int value);
int sum_dice(struct die_st *dice);

// scorecard functions
unsigned int calculate_selection_score(game_context *ctx, char *selection);
unsigned int calculate_selection_score(game_context *ctx, enum scorecard_command selection);
unsigned int calculate_total_score(struct scorecard_st *scorecard);
void initialize_scorecard(struct scorecard_st *scorecard);
char *get_player_score_selection_with_menu(struct scorecard_st *scorecard);
int get_player_score_selection_with_menu(struct scorecard_st *scorecard);
unsigned int n_of_a_kind(struct die_st *dice, unsigned int num_dice, unsigned int n, unsigned int value_to_avoid);
unsigned int n_in_a_row(struct die_st *dice, unsigned int num_dice, unsigned int n);
const char *name_of_scorecard_command(enum scorecard_command command);

#endif //DICELOGIC_H
+7 −6
Original line number Diff line number Diff line
@@ -5,14 +5,15 @@
#include "menu.h"

MENU_DIRECTION get_direction(void);
const int UNSELECTED = -1;

void *menu_prompt(const menu_item *items, unsigned int num_menu_items, const char *title, const char *item_disabled_label) {
int menu_prompt(const menu_item *items, unsigned int num_menu_items, const char *title, const char *item_disabled_label) {
    printf("%s\n", title);

    for (unsigned int i = 0; i < num_menu_items; i++) {
        printf("\n"); // make downward room for the menu
    }
    char *selected_action = "";
    int selected_action = UNSELECTED;
    int hovered_item_changed = 1;
    unsigned int hovered_selection_index = 0;
    // menu logic! TODO make this cross platform (play nice with Windows...)
@@ -64,7 +65,7 @@ void *menu_prompt(const menu_item *items, unsigned int num_menu_items, const cha
                hovered_item_changed = 0;
                break;
        }
    } while (strcasecmp(selected_action, "") == 0);
    } while (selected_action == UNSELECTED);

    return selected_action;
}
@@ -177,12 +178,12 @@ MENU_DIRECTION get_direction(void) {
    }
}

menu_item *get_menu_item_by_command(menu_item *items, const unsigned int num_menu_items, char *command_to_find) {
menu_item *get_menu_item_by_command(menu_item *items, const unsigned int num_menu_items, int command_to_find) {
    for (unsigned int i = 0; i < num_menu_items; i++) {
        if (strcasecmp(items[i].command, command_to_find) == 0) {
        if (items[i].command == command_to_find) {
            return &items[i];
        }
    }
    printf("get_menu_item_by_command(): item %s not found", command_to_find);
    printf("get_menu_item_by_command(): item %d not found", command_to_find);
    return NULL;
}
+2 −2
Original line number Diff line number Diff line
@@ -14,13 +14,13 @@ typedef enum {
} MENU_DIRECTION;

typedef struct {
    void *command;
    unsigned int command;
    unsigned int enabled;
    unsigned int multi_selected;
    char *title;
} menu_item;

void *menu_prompt(const menu_item *items, unsigned int num_menu_items, const char *title, const char *item_disabled_label);
int menu_prompt(const menu_item *items, unsigned int num_menu_items, const char *title, const char *item_disabled_label);
char *menu_prompt_multi_select(menu_item *items, unsigned int num_menu_items, const char *title, const char *item_disabled_label);

#endif //MENU_H
+66 −43
Original line number Diff line number Diff line
@@ -28,32 +28,42 @@ int main(void) {

    printf("yaht.c\n");

    enum item_commands {
        START,
        RULES,
        EXIT
    };
    menu_item items[] = {
            {.title = "New Game", .command = "start", .enabled = 1},
            {.title = "New Game", .command = START, .enabled = 1},
//            {.title = "Demo", .command = "demo", .enabled = 1}, // todo deprecate demo
            {.title = "Rules", .command = "rules", .enabled = 1},
            {.title = "Exit", .command = "exit", .enabled = 1},
            {.title = "Rules", .command = RULES, .enabled = 1},
            {.title = "Exit", .command = EXIT, .enabled = 1},
    };
    const unsigned int num_menu_items = sizeof(items) / sizeof(menu_item);

    int exiting = 0; // to be modified by the internal menu selection
    while (exiting == 0) {
        const char *selected_action = menu_prompt(items, num_menu_items, "Main menu", "");
        const int selected_action = menu_prompt(items, num_menu_items, "Main menu", "");

        if (strcasecmp(selected_action, "start") == 0) {
            unsigned int game_over = 0;
        switch (selected_action) {
            unsigned int game_over;
            case START:
                game_over = 0;
                while (can_continue_playing(&ctx.game_state.scorecard) && !game_over) {
                    game_over = take_turn(&ctx, NUM_DICE);
                }
                printf("Your final score was %d.\nThank you for playing!\n",
                       calculate_total_score(&ctx.game_state.scorecard));
//      } else if (strcasecmp(selected_action, "demo") == 0) {
//          do_demo_dice_rolls(&ctx, NUM_DICE);
//      }
        } else if (strcasecmp(selected_action, "rules") == 0) {
                break;
            case RULES:
                show_rules();
        } else if (strcasecmp(selected_action, "exit") == 0) {
                break;
            case EXIT:
                exiting = 1;
                break;
            default:
                printf("invalid selection");
                break;
        }

    }
@@ -83,34 +93,47 @@ unsigned int take_turn(game_context *ctx, unsigned int num_dice) {
        //      (also don't allow user to roll again if on the third roll)
        unsigned int ready_for_next_roll = 0;
        while (!ready_for_next_roll) {
            enum in_turn_menu_commands {
                ENTER_HOLD_SELECTION,
                ROLL,
                SCORE,
                QUIT
            };
            const menu_item in_turn_menu[] = {
                    {.title = "Hold dice", .command = "enter_hold_selection", .enabled = which_roll_number < 3},
                    {.title = "Roll again", .command = "roll", .enabled = which_roll_number < 3},
                    {.title = "Score", .command = "score", .enabled = 1},
                    {.title = "End game", .command = "quit", .enabled = 1},
                    {.title = "Hold dice", .command = ENTER_HOLD_SELECTION, .enabled = which_roll_number < 3},
                    {.title = "Roll again", .command = ROLL, .enabled = which_roll_number < 3},
                    {.title = "Score", .command = SCORE, .enabled = 1},
                    {.title = "End game", .command = QUIT, .enabled = 1},
            };
            const unsigned int num_menu_items = sizeof(in_turn_menu) / sizeof(menu_item);
            const char *player_action = menu_prompt(in_turn_menu, num_menu_items, "Choose from the following:",
            const enum in_turn_menu_commands player_action = menu_prompt(in_turn_menu, num_menu_items, "Choose from the following:",
                                                  "disabled");
            if (strcasecmp(player_action, "enter_hold_selection") == 0) {
            enum scorecard_command selection;
            switch (player_action) {
                case ENTER_HOLD_SELECTION:
                    // enter the menu for which dice to hold
                    hold_dice_with_menu(ctx->game_state.dice, NUM_DICE);
            } else if (strcasecmp(player_action, "roll") == 0) {
                    break;
                case ROLL:
//                printf("Rolling again...\n");
                    ready_for_next_roll = 1;
            } else if (strcasecmp(player_action, "score") == 0) {
                    break;
                case SCORE:
                    // enter the score menu
                char *selection = get_player_score_selection_with_menu(&ctx->game_state.scorecard);
                if (strcasecmp(selection, "back") != 0) {
                    selection = get_player_score_selection_with_menu(&ctx->game_state.scorecard);
                    if (selection != SCORING_MENU_BACK) {
                        unsigned int points_awarded = calculate_selection_score(ctx,
                                                                                selection); // todo we should use the return value for this to assign the point value, not do it within get_player_score_selection()
                    printf("for selection %s, points awarded: %d\n", selection, points_awarded);
                        printf("for selection %s, points awarded: %d\n", name_of_scorecard_command(selection),
                               points_awarded);
                        return 0; // 0 signifies user_quit == false, which will move on to the next turn
                    }
            } else if (strcasecmp(player_action, "quit") == 0) {
                case QUIT:
                    // todo this could be more robust or interactive. maybe add the final score?
                    //      also you could maybe ask to start a new game or to quit the program
                    return 1; // 1 signifies user_quit == true, which will end the game
                default:
                    break;
            }
        }
    }