#include "server_game_process.h" #include #include #include enum { deck_size = 52 }; static const char *basic_deck[deck_size] = { "2^", "3^", "4^", "5^", "6^", "7^", "8^", "9^", "10^", "J^", "Q^", "K^", "A^", "2#", "3#", "4#", "5#", "6#", "7#", "8#", "9#", "10#", "J#", "Q#", "K#", "A#", "2%", "3%", "4%", "5%", "6%", "7%", "8%", "9%", "10%", "J%", "Q%", "K%", "A%", "2v", "3v", "4v", "5v", "6v", "7v", "8v", "9v", "10v", "Jv", "Qv", "Kv", "Av" }; static int get_random_idx() { return 0 + (int)((double)deck_size*rand()/(RAND_MAX + 1.0)); } const char** get_shuffled_deck() { int i, new_idx; const char **shuffled_deck = calloc(deck_size, sizeof(char*)); for(i = 0; i < deck_size; ++i) { new_idx = get_random_idx(); while(shuffled_deck[new_idx]) new_idx = get_random_idx(); shuffled_deck[new_idx] = basic_deck[i]; } return shuffled_deck; } void deal_first_cards(const char **shuffled_deck, int *cards_left, player_cards *deck) { int i, last_idx; const char *str; for(i = 0; i < start_deck_size; ++i) { last_idx = *cards_left-1; str = shuffled_deck[last_idx]; if(str) { push_stack(deck, str); --*cards_left; shuffled_deck[last_idx] = NULL; } } } void deal_cards(const char **shuffled_deck, int *shuffled_cards_left, struct session **turn_queue, int turn_queue_size, int *number_arr) { int i, j, key, player_deck_size, card_shortage_quantity, last_idx; const char *extracted_card = NULL; for(i = 0; i < turn_queue_size; ++i) { key = turn_queue[i]->player_position - 1; player_deck_size = number_arr[key]; if(player_deck_size < start_deck_size) { card_shortage_quantity = start_deck_size - player_deck_size; for(j = 0; j < card_shortage_quantity; ++j) { last_idx = *shuffled_cards_left-1; /* shuffled deck is empty */ if(last_idx < 0) return; extracted_card = shuffled_deck[last_idx]; push_stack(&turn_queue[i]->deck, extracted_card); --*shuffled_cards_left; shuffled_deck[last_idx] = NULL; } } } } void deal_one_card_in_turn(const char **shuffled_deck, int *shuffled_cards_left, struct session **turn_queue, int turn_queue_size, struct card_count cc) { int i, key, player_deck_size, last_idx; const char *extracted_card = NULL; while(*shuffled_cards_left) { update_card_quantity_arr(turn_queue, cc); for(i = 0; i < turn_queue_size; ++i) { key = turn_queue[i]->player_position - 1; player_deck_size = cc.number_arr[key]; if(player_deck_size < start_deck_size) { last_idx = *shuffled_cards_left-1; /* shuffled deck is empty */ if(last_idx < 0) return; extracted_card = shuffled_deck[last_idx]; push_stack(&turn_queue[i]->deck, extracted_card); --*shuffled_cards_left; shuffled_deck[last_idx] = NULL; } } } } const char* extract_trump_card(const char **shuffled_deck, int *cards_left) { const char *trump_card = NULL; trump_card = shuffled_deck[*cards_left-1] ? shuffled_deck[*cards_left-1] : NULL; if(trump_card) { shuffled_deck[*cards_left-1] = NULL; --*cards_left; } return trump_card; } int convert_rank_to_int(const char *card) { int length; char str_rank[2]; length = strlen(card); /* 10 - the only one of its kind */ if(length == 3) return 10; str_rank[0] = card[0]; str_rank[1] = '\0'; switch(card[0]) { case 'J': return 11; case 'Q': return 12; case 'K': return 13; case 'A': return 14; default: return strtol(str_rank, NULL, 10); } return 0; } int find_lowest_trump(player_cards deck, const char *trump_suit) { int length, lowest_rank = 0, current_rank; const char *suit = NULL; while(deck) { length = strlen(deck->str); suit = deck->str + length - 1; if(*suit == *trump_suit) { current_rank = convert_rank_to_int(deck->str); if(!lowest_rank || lowest_rank > current_rank) lowest_rank = current_rank; } deck = deck->next; } return lowest_rank; } /* * used to transition attack to defender */ void shift_turn_queue_by_one(struct session **turn_queue, int turn_queue_size) { int i; struct session *tmp = turn_queue[0]; for(i = 1; i < turn_queue_size; ++i) turn_queue[i-1] = turn_queue[i]; turn_queue[i-1] = tmp; } /* * used to transition the attack to player behind defender */ void move_turn_queue_two_players_ahead(struct session **turn_queue, int turn_queue_size) { int i; for(i = 0; i < 2; ++i) shift_turn_queue_by_one(turn_queue, turn_queue_size); } void update_card_quantity_arr(struct session **turn_queue, struct card_count cc) { int i, key; for(i = 0; i <= cc.number_arr_idx; ++i) { key = turn_queue[i]->player_position - 1; cc.number_arr[key] = find_out_card_quantity_in_deck(turn_queue[i]->deck); } } struct game_info* get_new_game_info(int players_number, int *card_quantity_arr, int shuffled_cards_left, const char *trump_card, int position_whose_turn, struct card_queue *cq, struct cards_on_table *cot) { struct game_info *gi = malloc(sizeof(struct game_info)); gi->players_number = players_number; gi->card_quantity_arr = card_quantity_arr; gi->shuffled_cards_left = shuffled_cards_left; gi->trump_card = trump_card; gi->position_whose_turn = position_whose_turn; gi->cq = cq; gi->cot = cot; return gi; } void update_game_info(struct game_info *gi, int players_number, int shuffled_cards_left, int position_whose_turn) { gi->players_number = players_number; gi->shuffled_cards_left = shuffled_cards_left; gi->position_whose_turn = position_whose_turn; } int is_card_bit(const char *attack_card, const char *defend_card, const char *trump_suit) { int length, attack_rank, defend_rank; const char *attack_suit, *defend_suit; length = strlen(attack_card); attack_suit= attack_card + length - 1; length = strlen(defend_card); defend_suit = defend_card + length - 1; /* suits matched */ if(!strcmp(attack_suit, defend_suit)) { attack_rank = convert_rank_to_int(attack_card); defend_rank = convert_rank_to_int(defend_card); if(defend_rank > attack_rank) return 1; /* defender has a trump suit */ } else if(!strcmp(defend_suit, trump_suit)) return 1; return 0; } static void find_out_trump_cards_in_deck(player_cards *trump_cards, player_cards deck, const char *trump_suit) { const char *suit = NULL, *card = NULL; while(deck) { card = deck->str; suit= card + strlen(card) - 1; if(*suit == *trump_suit) push_stack(trump_cards, card); deck = deck->next; } } static int is_same_suit_and_not_meet(player_cards involved_cards, struct card_stack_item *defend_card, struct card_queue_item *attack_card) { int length; const char *attack_suit, *defend_suit; if(!find_card_in_stack(involved_cards, defend_card->str)) { length = strlen(attack_card->str); attack_suit= attack_card->str + length - 1; length = strlen(defend_card->str); defend_suit = defend_card->str + length - 1; return *attack_suit == *defend_suit; } return 0; } static int trump_cards_left_uncovered(player_cards remaining_cards, const char *trump_suit) { const char *suit; const char *card = NULL; while(remaining_cards) { card = remaining_cards->str; suit = card + strlen(card) - 1; if(*suit == *trump_suit) return 1; remaining_cards = remaining_cards->next; } return 0; } /* * analyze that each attacker card can be beat * TODO: free memory */ int check_defender_can_defend(struct card_queue *cq, player_cards deck, const char *trump_suit) { int current_rank = 0, min_rank = 0; struct card_stack_item *next_defend_card; struct card_queue_item *next_attack_card; const char* card_with_min_rank = NULL; player_cards involved_cards, trump_cards, remaining_attack_cards; init_stack(&involved_cards); init_stack(&trump_cards); init_stack(&remaining_attack_cards); find_out_trump_cards_in_deck(&trump_cards, deck, trump_suit); next_attack_card = NULL; while((next_attack_card = get_next_card_from_queue(cq, next_attack_card))) { /* get first defend card */ next_defend_card = NULL; next_defend_card = get_next_card_from_stack(deck, next_defend_card); card_with_min_rank = NULL; min_rank = 0; while(next_defend_card) { if(is_card_bit(next_attack_card->str, next_defend_card->str, trump_suit)) { if(is_same_suit_and_not_meet(involved_cards, next_defend_card, next_attack_card)) { current_rank = convert_rank_to_int(next_defend_card->str); if(!card_with_min_rank || min_rank > current_rank) { card_with_min_rank = next_defend_card->str; min_rank = current_rank; } } } next_defend_card = get_next_card_from_stack(deck, next_defend_card); } if(card_with_min_rank) { push_stack(&involved_cards, card_with_min_rank); if(find_card_in_stack(trump_cards, card_with_min_rank)) remove_card_from_stack(&trump_cards, card_with_min_rank); } else push_stack(&remaining_attack_cards, next_attack_card->str); } /* * there are trump attacking uncovered cards remaining * if the defender also has trump cards, they are of a lower rank */ if(trump_cards_left_uncovered(remaining_attack_cards, trump_suit)) return 0; while(remaining_attack_cards) { if(!is_empty_stack(trump_cards)) { pop_stack(&trump_cards); pop_stack(&remaining_attack_cards); } else break; } if(!is_empty_stack(remaining_attack_cards)) return 0; return 1; } static int check_matched_ranks(const char *attack_card, const char *not_defender_card) { int attack_rank, not_defender_rank; attack_rank = convert_rank_to_int(attack_card); not_defender_rank = convert_rank_to_int(not_defender_card); return attack_rank == not_defender_rank; } int check_someone_can_toss_card(struct session **turn_queue, int players_quantity, /* like turn_queue_size */ struct card_queue *cq, struct cards_on_table *cot) { int i, j; struct card_queue_item *attack_card_in_queue; struct card_stack_item *not_defender_card; for(i = 0; i < players_quantity; ++i) { /* skipping defender's cards */ if(i == 1) continue; /* checking card queue of attack cards */ attack_card_in_queue = NULL; while((attack_card_in_queue = get_next_card_from_queue(cq, attack_card_in_queue))) { not_defender_card = NULL; while((not_defender_card = get_next_card_from_stack(turn_queue[i]->deck, not_defender_card)) && !check_matched_ranks(attack_card_in_queue->str, not_defender_card->str)) {} if(not_defender_card) return 1; } /* checking cards on table */ for(j = cot->card_arr_idx; j >= 0; --j) { if(cot->card_arr[j][0] == '-' || cot->card_arr[j][0] == '\\') continue; not_defender_card = NULL; while((not_defender_card = get_next_card_from_stack(turn_queue[i]->deck, not_defender_card)) && !check_matched_ranks(cot->card_arr[j], not_defender_card->str)) {} if(not_defender_card) return 1; } } return 0; } /* is used to make the client's state tossing */ int check_player_can_toss_card(player_cards deck, struct cards_on_table *cot) { int i; struct card_stack_item *not_defender_card; /* checking cards on table */ for(i = cot->card_arr_idx; i >= 0; --i) { if(cot->card_arr[i][0] == '-' || cot->card_arr[i][0] == '\\') continue; not_defender_card = NULL; while((not_defender_card = get_next_card_from_stack(deck, not_defender_card)) && !check_matched_ranks(cot->card_arr[i], not_defender_card->str)) {} if(not_defender_card) return 1; } return 0; } int is_correct_tossing_card(const char *card, struct cards_on_table *cot) { int i; for(i = cot->card_arr_idx; i >= 0; --i) { if(cot->card_arr[i][0] == '-' || cot->card_arr[i][0] == '\\') continue; if(check_matched_ranks(cot->card_arr[i], card)) return 1; } return 0; } /* when defender cannot bit any card */ void put_all_cards_from_queue_to_table(struct cards_on_table *cot, struct card_queue *cq) { const char *card; while(!is_empty_queue(cq)) { card = pop_card_queue(cq); ++cot->card_arr_idx; cot->card_arr[cot->card_arr_idx] = card; ++cot->card_arr_idx; cot->card_arr[cot->card_arr_idx] = "\\"; ++cot->card_arr_idx; cot->card_arr[cot->card_arr_idx] = "-"; } } void put_one_card_from_queue_to_table(struct cards_on_table *cot, struct card_queue *cq) { const char *card; card = pop_card_queue(cq); ++cot->card_arr_idx; cot->card_arr[cot->card_arr_idx] = card; ++cot->card_arr_idx; cot->card_arr[cot->card_arr_idx] = "\\"; ++cot->card_arr_idx; cot->card_arr[cot->card_arr_idx] = "-"; } /* it used by defender to bit attack card */ void put_defender_card_on_table(struct cards_on_table *cot, const char *card) { cot->card_arr[cot->card_arr_idx] = card; } void move_all_cards_to_defender(struct cards_on_table *cot, player_cards *deck) { int i; for(i = cot->card_arr_idx; i >= 0; --i) { if(cot->card_arr[i][0] == '-' || cot->card_arr[i][0] == '\\') continue; push_stack(deck, cot->card_arr[i]); } cot->card_arr_idx = i; } void remove_cards_from_table(struct cards_on_table *cot) { cot->card_arr_idx = -1; } int calculate_defense_card_quantity_on_table(const struct cards_on_table *cot) { int i, counter = 0; for(i = 0; i <= cot->card_arr_idx; ++i) { /* every 3 position meets a defender card */ if(!((i+1) % 3)) { if(!strcmp(cot->card_arr[i], "-")) continue; else ++counter; } } return counter; } int calculate_attack_card_quantity_on_table(const struct cards_on_table *cot) { int i, counter = 0; for(i = 0; i <= cot->card_arr_idx; ++i) if(i == 0 || !(i % 3)) ++counter; return counter; } int check_all_answers_were_received(const struct session **turn_queue, int turn_queue_size) { int i; for(i = 0; i < turn_queue_size; ++i) if(turn_queue[i]->tm == answer_wait) return 0; return 1; } int is_receiving_cards_limit(const struct cards_on_table *cot, player_cards defense_deck, const struct card_queue *cq) { int total_defense_cards, total_attack_cards; total_defense_cards = calculate_defense_card_quantity_on_table(cot); total_attack_cards = calculate_attack_card_quantity_on_table(cot); total_defense_cards += find_out_card_quantity_in_deck(defense_deck); total_attack_cards += find_out_card_quantity_in_cq(cq); if(total_defense_cards >= start_deck_size && total_attack_cards == start_deck_size) { return 1; } else if(total_defense_cards == total_attack_cards) return 1; return 0; } void clear_defense_lost_status(struct session *defender) { defender->defense_lost = 0; } /* * can everyone fully replenish their deck (up to 6 cards)? */ int check_everyone_can_replanish_deck(int shuffled_cards_left, struct session **turn_queue, int turn_queue_size, int *number_arr) { int i, key, player_deck_size; for(i = 0; i < turn_queue_size; ++i) { key = turn_queue[i]->player_position - 1; player_deck_size = number_arr[key]; if(player_deck_size < start_deck_size) shuffled_cards_left -= start_deck_size - player_deck_size; } return shuffled_cards_left >= 0; }