| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- #include "game.h"
- #include "wave/data_structures/queue.h"
- #include "wave/data_structures/list.h"
- #include "wave/exception_manager.h"
- #include <gui/gui.h>
- #include <stdlib.h>
- #include <math.h>
- Card AllCardsData[NUMBER_OF_CARDS];
- const int CARD_NONE = -1;
- struct GameState {
- int cardLocation[NUMBER_OF_CARDS]; // 0 = deck, -1 = discard, 1+ = player index
- int playerTurn;
- int direction;
- int topCard;
- CardSuit forcedSuit;
- int cardToPlay;
- CardSuit forcedSuitToPlay;
- int winner;
- Queue* shuffleQueue;
- };
- void fill_shuffle_queue(GameState* state) {
- int array[NUMBER_OF_CARDS];
- for(int i = 0; i < NUMBER_OF_CARDS; i++) array[i] = i;
- for(int i = 0; i < NUMBER_OF_CARDS; i++) {
- int j = rand() % NUMBER_OF_CARDS;
- int temp = array[i];
- array[i] = array[j];
- array[j] = temp;
- }
- for(int i = 0; i < NUMBER_OF_CARDS; i++) queue_enqueue(state->shuffleQueue, &array[i]);
- }
- int game_step_draw_card(GameState* state, int playerNumber) {
- if(game_get_player_hand_count(state, 0) == 0) {
- for(int i = 0; i < NUMBER_OF_CARDS; i++)
- if(state->cardLocation[i] == -1) state->cardLocation[i] = 0;
- }
- int cardIndex;
- do {
- if(queue_count(state->shuffleQueue) == 0) fill_shuffle_queue(state);
- queue_dequeue(state->shuffleQueue, &cardIndex);
- } while(state->cardLocation[cardIndex] != 0);
- state->cardLocation[cardIndex] = playerNumber;
- return cardIndex;
- }
- bool game_is_draw_four_valid_to_play(GameState* state, int playerIndex) {
- Card topCard = AllCardsData[game_get_top_card(state)];
- CardSuit forbiddenSuit = state->forcedSuit != CardSuit_None ? state->forcedSuit : topCard.suit;
- for(int i = 0; i < NUMBER_OF_CARDS; i++) {
- if(state->cardLocation[i] == playerIndex) {
- Card card = AllCardsData[i];
- if(card.suit == forbiddenSuit) return false;
- }
- }
- return true;
- }
- bool game_is_card_valid_to_play(GameState* state, int cardIndex) {
- Card card = AllCardsData[cardIndex];
- Card topCard = AllCardsData[game_get_top_card(state)];
- // Playing a joker
- if(card.action == ActionType_ChangeSuit) return true;
- if(card.action == ActionType_ChangeSuitPlus4)
- return game_is_draw_four_valid_to_play(state, state->playerTurn);
- // Playing on a joker (forced suit)
- if(state->forcedSuit != CardSuit_None && card.suit == state->forcedSuit) return true;
- // Playing a card of the same suit or number
- if(card.suit == topCard.suit) return true;
- if(card.number != -1 && card.number == topCard.number) return true;
- // Playing an action card of the same action
- if(card.action != ActionType_None && card.action == topCard.action) return true;
- return false;
- }
- void assert_valid_play(GameState* state, int cardIndex, CardSuit forcedSuit) {
- char message[100];
- Card card = AllCardsData[cardIndex];
- bool isForcingSuit = forcedSuit != CardSuit_None;
- bool requiresForcedSuit = card.action == ActionType_ChangeSuit ||
- card.action == ActionType_ChangeSuitPlus4;
- if(isForcingSuit != requiresForcedSuit) {
- snprintf(message, 100, "Invalid forced suit: %d on %d", forcedSuit, card.action);
- throw_exception(message);
- }
- if(!game_is_card_valid_to_play(state, cardIndex)) {
- snprintf(message, 100, "Invalid play: %d on %d", cardIndex, state->topCard);
- throw_exception(message);
- }
- }
- int game_get_winner(GameState* state) {
- return state->winner;
- }
- void game_update_winner(GameState* state) {
- for(int playerIndex = 1; playerIndex <= NUMBER_OF_PLAYERS; playerIndex++) {
- if(game_get_player_hand_count(state, playerIndex) == 0) {
- state->winner = playerIndex;
- break;
- }
- }
- }
- void game_set_card_to_play(GameState* state, int cardIndex, int forcedSuit) {
- assert_valid_play(state, cardIndex, forcedSuit);
- state->cardToPlay = cardIndex;
- state->forcedSuitToPlay = forcedSuit;
- }
- int game_get_card_to_play(GameState* state) {
- return state->cardToPlay;
- }
- CardSuit game_get_forced_suit_to_play(GameState* state) {
- return state->forcedSuitToPlay;
- }
- void game_apply_card_to_play(GameState* state) {
- int cardIndex = state->cardToPlay;
- CardSuit forcedSuit = state->forcedSuitToPlay;
- game_step_play_card(state, cardIndex);
- if(game_get_winner(state) != 0) return;
- Card card = AllCardsData[cardIndex];
- if(card.action == ActionType_Invert) game_step_reverse(state);
- if(card.action == ActionType_Skip) game_step_next_player(state);
- if(card.action == ActionType_ChangeSuit) game_step_set_suit(state, forcedSuit);
- if(card.action == ActionType_Plus2) {
- game_step_draw_card(state, game_get_next_player(state));
- game_step_draw_card(state, game_get_next_player(state));
- game_step_next_player(state);
- }
- if(card.action == ActionType_ChangeSuitPlus4) {
- game_step_draw_card(state, game_get_next_player(state));
- game_step_draw_card(state, game_get_next_player(state));
- game_step_draw_card(state, game_get_next_player(state));
- game_step_draw_card(state, game_get_next_player(state));
- game_step_set_suit(state, forcedSuit);
- game_step_next_player(state);
- }
- state->cardToPlay = CARD_NONE;
- state->forcedSuitToPlay = CardSuit_None;
- // Next player
- game_step_next_player(state);
- }
- void game_step_play_card(GameState* state, int cardIndex) {
- state->cardLocation[cardIndex] = -1;
- state->topCard = cardIndex;
- state->forcedSuit = CardSuit_None;
- game_update_winner(state);
- }
- void game_step_next_player(GameState* state) {
- state->playerTurn = game_get_next_player(state);
- }
- void game_step_reverse(GameState* state) {
- state->direction = -state->direction;
- }
- void game_step_set_suit(GameState* state, int suit) {
- state->forcedSuit = suit;
- }
- void initialize_cards_data() {
- // Initializes cards data.
- // Order is useful: it will be used when displaying the cards so they are already sorted.
- static bool initialized = false;
- if(initialized) return;
- initialized = true;
- int cardIndex = 0;
- for(int suit = 1; suit <= 4; suit++) {
- for(int number = 0; number < 10; number++) {
- Card card;
- card.suit = suit;
- card.number = number;
- card.action = ActionType_None;
- AllCardsData[cardIndex++] = card;
- if(number != 0) // 0 is only once per suit
- AllCardsData[cardIndex++] = card;
- }
- }
- for(int suit = 1; suit <= 4; suit++) {
- Card card;
- card = (Card){.suit = suit, .number = -1, .action = ActionType_Skip};
- AllCardsData[cardIndex++] = card;
- AllCardsData[cardIndex++] = card;
- card = (Card){.suit = suit, .number = -1, .action = ActionType_Invert};
- AllCardsData[cardIndex++] = card;
- AllCardsData[cardIndex++] = card;
- card = (Card){.suit = suit, .number = -1, .action = ActionType_Plus2};
- AllCardsData[cardIndex++] = card;
- AllCardsData[cardIndex++] = card;
- }
- for(int i = 0; i < 4; i++) {
- Card card = {.suit = CardSuit_None, .number = -1, .action = ActionType_ChangeSuit};
- AllCardsData[cardIndex++] = card;
- }
- for(int i = 0; i < 4; i++) {
- Card card = {.suit = CardSuit_None, .number = -1, .action = ActionType_ChangeSuitPlus4};
- AllCardsData[cardIndex++] = card;
- }
- }
- GameState* game_alloc() {
- GameState* state = malloc(sizeof(GameState));
- state->shuffleQueue = queue_alloc(NUMBER_OF_CARDS, sizeof(int));
- game_reset(state);
- return state;
- }
- void game_free(GameState* state) {
- queue_free(state->shuffleQueue);
- free(state);
- }
- void game_reset_top_card(GameState* state) {
- int cardIndex;
- do {
- cardIndex = rand() % NUMBER_OF_CARDS;
- } while(AllCardsData[cardIndex].number == -1);
- game_step_play_card(state, cardIndex);
- }
- void game_reset(GameState* state) {
- initialize_cards_data();
- for(int i = 0; i < NUMBER_OF_CARDS; i++) state->cardLocation[i] = 0;
- for(int playerIndex = 1; playerIndex <= NUMBER_OF_PLAYERS; playerIndex++) {
- for(int j = 0; j < NUMBER_OF_STARTING_CARDS; j++) {
- game_step_draw_card(state, playerIndex);
- }
- }
- game_reset_top_card(state);
- state->playerTurn = rand() % NUMBER_OF_PLAYERS + 1;
- state->direction = rand() % 2 == 0 ? 1 : -1;
- state->cardToPlay = CARD_NONE;
- state->forcedSuitToPlay = CardSuit_None;
- state->winner = 0;
- }
- int game_get_player_turn(GameState* state) {
- return state->playerTurn;
- }
- int game_get_next_player(GameState* state) {
- return game_calculate_next_player(state, state->playerTurn);
- }
- int game_calculate_next_player(GameState* state, int playerIndex) {
- return (playerIndex - 1 + state->direction + NUMBER_OF_PLAYERS) % NUMBER_OF_PLAYERS + 1;
- }
- int game_get_top_card(GameState* state) {
- return state->topCard;
- }
- int game_get_card_location(GameState* state, int index) {
- return state->cardLocation[index];
- }
- CardSuit game_get_forced_suit(GameState* state) {
- return state->forcedSuit;
- }
- void game_get_player_hand(GameState* state, int playerIndex, List* result) {
- list_clear(result);
- for(int i = 0; i < NUMBER_OF_CARDS; i++) {
- if(state->cardLocation[i] == playerIndex) list_add(result, &i);
- }
- }
- int game_get_player_hand_count(GameState* state, int playerIndex) {
- int count = 0;
- for(int i = 0; i < NUMBER_OF_CARDS; i++) {
- if(state->cardLocation[i] == playerIndex) count++;
- }
- return count;
- }
- void game_get_player_hand_valid_cards(GameState* state, int playerIndex, List* result) {
- list_clear(result);
- for(int i = 0; i < NUMBER_OF_CARDS; i++) {
- if(state->cardLocation[i] == playerIndex && game_is_card_valid_to_play(state, i))
- list_add(result, &i);
- }
- }
- int game_get_player_hand_valid_cards_count(GameState* state, int playerIndex) {
- int count = 0;
- for(int i = 0; i < NUMBER_OF_CARDS; i++) {
- if(state->cardLocation[i] == playerIndex && game_is_card_valid_to_play(state, i)) count++;
- }
- return count;
- }
- int game_get_direction(GameState* state) {
- return state->direction;
- }
|