From b4b784928cbec4a93c71f3ca1e37a14397929edb Mon Sep 17 00:00:00 2001 From: scratko Date: Sun, 18 Aug 2024 22:24:30 +0300 Subject: Final version v1.0 Fixed stack clearing. Added check for NULL before clearing game parameters. Added refactoring of define_phase_after_attack(). Analyzing game results is organized into several functions. Fixed card limit detection on tossing (line 366 in server_data_processing.c). --- server/card_stack.c | 7 +- server/server.c | 374 +++++++++++++++++++++++----------------- server/server.h | 4 +- server/server_data_processing.c | 6 +- server/server_game_process.c | 27 ++- server/server_game_process.h | 4 +- 6 files changed, 243 insertions(+), 179 deletions(-) (limited to 'server') diff --git a/server/card_stack.c b/server/card_stack.c index 077707e..548f23c 100644 --- a/server/card_stack.c +++ b/server/card_stack.c @@ -90,11 +90,12 @@ int find_card_in_stack(player_cards involved_cards, const char *str) void clear_stack(player_cards *deck) { struct card_stack_item *tmp; + player_cards tmp_deck = *deck; - while(*deck) { - tmp = *deck; + while(tmp_deck) { + tmp = tmp_deck; + tmp_deck = tmp_deck->next; free(tmp); - *deck = (*deck)->next; } *deck = NULL; } diff --git a/server/server.c b/server/server.c index 8ebc937..6a9075c 100644 --- a/server/server.c +++ b/server/server.c @@ -70,14 +70,22 @@ static void close_connection(struct server *serv) serv->sess_arr[i] = NULL; } serv->connected_players_counter = 0; - free(serv->cc.number_arr); - free(serv->shuffled_deck); - free(serv->turn_queue); - free(serv->gi); - serv->cc.number_arr = NULL; - serv->shuffled_deck = NULL; - serv->turn_queue = NULL; - serv->gi = NULL; + if(serv->cc.number_arr) { + free(serv->cc.number_arr); + serv->cc.number_arr = NULL; + } + if(serv->shuffled_deck) { + free(serv->shuffled_deck); + serv->shuffled_deck = NULL; + } + if(serv->turn_queue) { + free(serv->turn_queue); + serv->turn_queue = NULL; + } + if(serv->gi) { + free(serv->gi); + serv->gi = NULL; + } clear_queue(&serv->cq); } @@ -239,6 +247,7 @@ static void set_record_status_for_all(struct server *serv) serv->sess_arr[i]->record = 1; } +#if 0 static int print_table_condition(struct server *serv) { return !check_defender_can_defend(&serv->cq, serv->turn_queue[1]->deck, @@ -247,22 +256,45 @@ static int print_table_condition(struct server *serv) serv->connected_players_counter, &serv->cq, &serv->cot); } +#endif static int defense_condition(struct server *serv) { return check_defender_can_defend(&serv->cq, serv->turn_queue[1]->deck, serv->trump_suit); } -/* - * TODO refactoring - */ + static void define_phase_after_attack(struct server *serv) { + if(defense_condition(serv)) { + set_state_for_client(serv, defense); + set_whose_turn(serv, defense); + put_one_card_from_queue_to_table(&serv->cot, &serv->cq); + serv->state = defense_phase_out; + /* defender can't keep defense */ + } else { + serv->turn_queue[1]->defense_lost = 1; + put_all_cards_from_queue_to_table(&serv->cot, &serv->cq); + if(check_someone_can_toss_card(serv->turn_queue, + serv->connected_players_counter, + &serv->cq, &serv->cot) && + !is_receiving_cards_limit(&serv->cot, serv->turn_queue[1]->deck, + &serv->cq)) + { + set_state_for_client(serv, tossing); + set_whose_turn(serv, tossing); + serv->state = tossing_phase_out; + } else { + set_state_for_client(serv, display_only_table); + serv->state = end_round; + } + } +#if 0 if(print_table_condition(serv)) { set_state_for_client(serv, display_only_table); put_all_cards_from_queue_to_table(&serv->cot, &serv->cq); serv->turn_queue[1]->defense_lost = 1; - serv->state = table; + serv->state = end_round; } else if(defense_condition(serv)) { set_state_for_client(serv, defense); set_whose_turn(serv, defense); @@ -274,14 +306,14 @@ static void define_phase_after_attack(struct server *serv) if(is_receiving_cards_limit(&serv->cot, serv->turn_queue[1]->deck, &serv->cq)) { set_state_for_client(serv, display_only_table); - serv->state = table; + serv->state = end_round; } else { set_state_for_client(serv, tossing); set_whose_turn(serv, tossing); serv->state = tossing_phase_out; } - } +#endif } static void define_phase_after_defense(struct server *serv) @@ -303,7 +335,7 @@ static void define_phase_after_defense(struct server *serv) /* then begin new attack */ } else { set_state_for_client(serv, display_only_table); - serv->state = table; + serv->state = end_round; } /* can defender continue defense? */ } else { @@ -320,7 +352,7 @@ static void define_phase_after_defense(struct server *serv) serv->state = tossing_phase_out; } else { set_state_for_client(serv, display_only_table); - serv->state = table; + serv->state = end_round; } /* card queue contains some cards for defender */ } else { @@ -344,7 +376,7 @@ static void define_phase_after_defense(struct server *serv) serv->state = tossing_phase_out; } else { set_state_for_client(serv, display_only_table); - serv->state = table; + serv->state = end_round; } } } @@ -355,31 +387,31 @@ static void define_phase_after_tossing(struct server *serv) { if(serv->turn_queue[1]->defense_lost) { if(is_empty_queue(&serv->cq)) { - /* nobody's put any cards on the table */ + /* nobody's put any cards on the end_round */ set_state_for_client(serv, display_only_table); - serv->state = table; + serv->state = end_round; } else { put_all_cards_from_queue_to_table(&serv->cot, &serv->cq); if(!is_receiving_cards_limit(&serv->cot, serv->turn_queue[1]->deck, - &serv->cq) && + &serv->cq) && check_someone_can_toss_card(serv->turn_queue, - serv->turn_queue_size, - &serv->cq, &serv->cot)) + serv->turn_queue_size, + &serv->cq, &serv->cot)) { set_state_for_client(serv, tossing); set_whose_turn(serv, tossing); serv->state = tossing_phase_out; } else { set_state_for_client(serv, display_only_table); - serv->state = table; + serv->state = end_round; } } /* defense continue? */ } else { if(is_empty_queue(&serv->cq)) { set_state_for_client(serv, display_only_table); - serv->state = table; + serv->state = end_round; } else { if(check_defender_can_defend(&serv->cq, serv->turn_queue[1]->deck, serv->trump_suit)) { @@ -391,29 +423,166 @@ static void define_phase_after_tossing(struct server *serv) serv->turn_queue[1]->defense_lost = 1; put_all_cards_from_queue_to_table(&serv->cot, &serv->cq); if(!is_receiving_cards_limit(&serv->cot, - serv->turn_queue[1]->deck, - &serv->cq) && + serv->turn_queue[1]->deck, + &serv->cq) && check_someone_can_toss_card(serv->turn_queue, - serv->turn_queue_size, - &serv->cq, &serv->cot)) + serv->turn_queue_size, + &serv->cq, &serv->cot)) { set_state_for_client(serv, tossing); set_whose_turn(serv, tossing); serv->state = tossing_phase_out; } else { set_state_for_client(serv, display_only_table); - serv->state = table; + serv->state = end_round; } } } } } -static void determine_server_state(struct server *serv) +static void analyze_attackers_move(struct server *serv, + int *turn_queue_resizing, + struct session **defender) +{ + + int key; + key = serv->turn_queue[0]->player_position-1; + *defender = serv->turn_queue[1]; + + /* attacker was left without cards */ + if(!serv->shuffled_deck_size && !serv->cc.number_arr[key]) { + serv->turn_queue[0]->state = spectator; + /* resizing of turn_queue */ + shift_turn_queue_by_one(serv->turn_queue, serv->turn_queue_size); + --serv->turn_queue_size; + *turn_queue_resizing = 1; + } +} + +static void analyze_defenders_move(struct server *serv, int turn_queue_resizing, + struct session *defender) { - int key, turn_queue_resizing = 0; + int key; + + if(defender->defense_lost) { + clear_defense_lost_status(defender); + move_all_cards_to_defender(&serv->cot, &defender->deck); + update_card_quantity_arr(serv->turn_queue, serv->cc); + if(!serv->shuffled_deck_size && serv->turn_queue_size == 1) { + serv->durak_position = defender->player_position; + set_state_for_client(serv, result); + serv->state = end_game; + } else { + turn_queue_resizing ? shift_turn_queue_by_one(serv->turn_queue, + serv->turn_queue_size) : + move_turn_queue_two_players_ahead(serv->turn_queue, + serv->turn_queue_size); + set_whose_turn(serv, attack); + set_state_for_client(serv, attack); + serv->state = attack_phase_out; + } + } else { + remove_cards_from_table(&serv->cot); + key = defender->player_position - 1; + if(!serv->shuffled_deck_size && !serv->cc.number_arr[key]) { + /* + * the final attack was completely beaten. + * The defender also has no cards left + */ + if(serv->turn_queue_size == 1) { + /* draw */ + serv->durak_position = 0; + set_state_for_client(serv, result); + serv->state = end_game; + } else { + /* attacker has no cards in current part*/ + if(turn_queue_resizing) { + shift_turn_queue_by_one(serv->turn_queue, + serv->turn_queue_size); + --serv->turn_queue_size; + defender->state = spectator; + set_state_for_client(serv, attack); + set_whose_turn(serv, attack); + serv->state = attack_phase_out; + /* third (last) player has cards */ + if(serv->turn_queue_size == 1) { + serv->durak_position = + serv->turn_queue[0]->player_position; + set_state_for_client(serv, result); + serv->state = end_game; + } + } else { + /* behind defender */ + move_turn_queue_two_players_ahead(serv->turn_queue, + serv->turn_queue_size); + --serv->turn_queue_size; + defender->state = spectator; + set_state_for_client(serv, attack); + set_whose_turn(serv, attack); + serv->state = attack_phase_out; + if(serv->turn_queue_size == 1) { + /* attacker is durak */ + serv->durak_position = + serv->turn_queue[0]->player_position; + set_state_for_client(serv, result); + serv->state = end_game; + } + } + } + } else { + if(serv->turn_queue_size == 1) { + serv->durak_position = defender->player_position; + set_state_for_client(serv, result); + serv->state = end_game; + } else { + if(!turn_queue_resizing) + shift_turn_queue_by_one(serv->turn_queue, + serv->turn_queue_size); + set_state_for_client(serv, attack); + set_whose_turn(serv, attack); + serv->state = attack_phase_out; + } + } + } +} + +static void analyze_end_round(struct server *serv) +{ + int turn_queue_resizing = 0; struct session *defender = NULL; + update_card_quantity_arr(serv->turn_queue, serv->cc); + + /* ========= result of attacker's move ===========*/ + analyze_attackers_move(serv, &turn_queue_resizing, &defender); + /* ========= result of defender's move =========== */ + analyze_defenders_move(serv, turn_queue_resizing, defender); +} + +static void dealing_cards_phase(struct server *serv) +{ + /* ======== dealing cards =========== */ + if(serv->shuffled_deck_size) { + if(check_everyone_can_replanish_deck(serv->shuffled_deck_size, + serv->turn_queue, + serv->turn_queue_size, + serv->cc.number_arr)) + { + deal_cards(serv->shuffled_deck, &serv->shuffled_deck_size, + serv->turn_queue, serv->turn_queue_size, + serv->cc.number_arr); + } else + deal_one_card_in_turn(serv->shuffled_deck, + &serv->shuffled_deck_size, serv->turn_queue, + serv->turn_queue_size, serv->cc); + /* update the card count after giving out cards */ + update_card_quantity_arr(serv->turn_queue, serv->cc); + } +} + +static void determine_server_state(struct server *serv) +{ switch(serv->state) { case no_players: serv->state = first_player; @@ -453,124 +622,12 @@ static void determine_server_state(struct server *serv) update_game_info(serv->gi, serv->connected_players_counter, serv->shuffled_deck_size, serv->position_whose_turn); break; - case table: - defender = serv->turn_queue[1]; - key = serv->turn_queue[0]->player_position-1; - update_card_quantity_arr(serv->turn_queue, serv->cc); - - /* ========= result of attacker's move ===========*/ - /* attacker was left without cards */ - if(!serv->shuffled_deck_size && !serv->cc.number_arr[key]) { - serv->turn_queue[0]->state = spectator; - /* resizing of turn_queue */ - shift_turn_queue_by_one(serv->turn_queue, serv->turn_queue_size); - --serv->turn_queue_size; - turn_queue_resizing = 1; - } - /* ========= result of defender's move =========== */ - if(defender->defense_lost) { - clear_defense_lost_status(defender); - move_all_cards_to_defender(&serv->cot, &defender->deck); - update_card_quantity_arr(serv->turn_queue, serv->cc); - if(!serv->shuffled_deck_size && serv->turn_queue_size == 1) { - serv->durak_position = defender->player_position; - set_state_for_client(serv, result); - serv->state = end_game; - } else { - turn_queue_resizing ? shift_turn_queue_by_one(serv->turn_queue, - serv->turn_queue_size) : - move_turn_queue_two_players_ahead(serv->turn_queue, - serv->turn_queue_size); - set_whose_turn(serv, attack); - set_state_for_client(serv, attack); - serv->state = attack_phase_out; - } - } else { - remove_cards_from_table(&serv->cot); - key = defender->player_position - 1; - if(!serv->shuffled_deck_size && !serv->cc.number_arr[key]) { - /* - * the final attack was completely beaten. - * The defender also has no cards left - */ - if(serv->turn_queue_size == 1) { - /* draw */ - serv->durak_position = 0; - set_state_for_client(serv, result); - serv->state = end_game; - } else { - /* attacker has no cards in current part*/ - if(turn_queue_resizing) { - shift_turn_queue_by_one(serv->turn_queue, - serv->turn_queue_size); - --serv->turn_queue_size; - defender->state = spectator; - set_state_for_client(serv, attack); - set_whose_turn(serv, attack); - serv->state = attack_phase_out; - /* third (last) player has cards */ - if(serv->turn_queue_size == 1) { - serv->durak_position = - serv->turn_queue[0]->player_position; - set_state_for_client(serv, result); - serv->state = end_game; - } - } else { - /* behind defender */ - move_turn_queue_two_players_ahead(serv->turn_queue, - serv->turn_queue_size); - --serv->turn_queue_size; - defender->state = spectator; - set_state_for_client(serv, attack); - set_whose_turn(serv, attack); - serv->state = attack_phase_out; - if(serv->turn_queue_size == 1) { - /* attacker is durak */ - serv->durak_position = - serv->turn_queue[0]->player_position; - set_state_for_client(serv, result); - serv->state = end_game; - } - } - } - } else { - if(serv->turn_queue_size == 1) { - serv->durak_position = defender->player_position; - set_state_for_client(serv, result); - serv->state = end_game; - } else { - if(!turn_queue_resizing) - shift_turn_queue_by_one(serv->turn_queue, - serv->turn_queue_size); - set_state_for_client(serv, attack); - set_whose_turn(serv, attack); - serv->state = attack_phase_out; - } - } - } - /* ======== dealing cards =========== */ - if(serv->shuffled_deck_size) { - if(check_everyone_can_replanish_deck(serv->shuffled_deck_size, - serv->turn_queue, - serv->turn_queue_size, - serv->cc.number_arr)) - { - deal_cards(serv->shuffled_deck, &serv->shuffled_deck_size, - serv->turn_queue, serv->turn_queue_size, - serv->cc.number_arr); - } else - deal_one_card_in_turn(serv->shuffled_deck, - &serv->shuffled_deck_size, - serv->turn_queue, serv->turn_queue_size, - serv->cc); - /* update the card count after giving out cards */ - update_card_quantity_arr(serv->turn_queue, serv->cc); - } - + case end_round: + analyze_end_round(serv); + dealing_cards_phase(serv); update_game_info(serv->gi, serv->connected_players_counter, serv->shuffled_deck_size, serv->position_whose_turn); set_record_status_for_all(serv); - turn_queue_resizing = 0; serv->tossing_limit = 0; break; case defense_phase_out: @@ -637,7 +694,7 @@ static void set_up_player_tracking(struct server *serv, fd_set *readfds, break; case start_game: case attack_phase_out: - case table: + case end_round: case defense_phase_out: case tossing_phase_out: case end_game: @@ -681,7 +738,7 @@ static int check_server_state_change_conditions(struct server *serv) case defense_phase_out: case defense_phase_in: case tossing_phase_out: - case table: + case end_round: case end_game: return 1; case tossing_phase_in: @@ -730,7 +787,7 @@ static void make_data_transfer(struct server *serv, fd_set *readfds, case attack_phase_out: case defense_phase_out: case tossing_phase_out: - case table: + case end_round: if(FD_ISSET(i, writefds) && serv->sess_arr[i]->record) result = print_game_part(serv->sess_arr[i], serv->state, serv->gi); @@ -756,10 +813,10 @@ static void make_data_transfer(struct server *serv, fd_set *readfds, get_cards_from_tossing_player(serv->sess_arr[i], serv->turn_queue[1]->deck, &serv->cot, &serv->cq); - if(result == answer_got || result == anwer_got_with_limit) + if(result == answer_got || result == answer_got_with_limit) serv->sess_arr[i]->tm = answer_got; - if(result == anwer_got_with_limit) + if(result == answer_got_with_limit) serv->tossing_limit = 1; else if(result == cancel) serv->sess_arr[i]->tm = cancel; @@ -779,7 +836,7 @@ static void make_data_transfer(struct server *serv, fd_set *readfds, result = 1; /* next can be reading that's not ready */ } } - if(serv->state == start_game || serv->state == table || + if(serv->state == start_game || serv->state == end_round || serv->state == end_game) sleep(2); if(check_server_state_change_conditions(serv)) @@ -859,12 +916,14 @@ static int init_server(struct server *serv, int port) serv->shuffled_deck_size = max_shuffled_deck_size; serv->gi = NULL; serv->cc.number_arr = NULL; + serv->turn_queue = NULL; + serv->cq.first = NULL; + serv->cq.last = NULL; listen(serv->listen_socket, listen_qlen); return 1; } -#if 0 static void demonization() { int pid; @@ -884,7 +943,6 @@ static void demonization() if(pid) exit(0); } -#endif int main(int argc, char **argv) { @@ -896,25 +954,17 @@ int main(int argc, char **argv) "Usage: \n"); return 1; } -#if 0 demonization(); -#endif srand(time(NULL)); -#if 0 openlog("durak server", 0, LOG_USER); syslog(LOG_INFO, "daemon started"); -#endif port = strtol(argv[1], NULL, 10); if(!init_server(&serv, port)) { -#if 0 syslog(LOG_ERR, "server initialization error"); -#endif return 2; } return main_loop(&serv); -#if 0 syslog(LOG_INFO, "server terminated"); closelog(); -#endif } diff --git a/server/server.h b/server/server.h index 552f899..a62f085 100644 --- a/server/server.h +++ b/server/server.h @@ -26,7 +26,7 @@ enum server_states { defense_phase_in, tossing_phase_out, tossing_phase_in, - table, + end_round, end_game }; @@ -51,7 +51,7 @@ enum tossing_mode { cancel, answer_wait, answer_got, - anwer_got_with_limit, + answer_got_with_limit, }; enum spectator_mode { diff --git a/server/server_data_processing.c b/server/server_data_processing.c index 99ac579..41e4b08 100644 --- a/server/server_data_processing.c +++ b/server/server_data_processing.c @@ -291,7 +291,7 @@ int get_card_from_defender(struct session *client, struct cards_on_table *cot, for(i = 0; i < read_result && client->buffer[i] != '\n'; ++i) given_card[i] = client->buffer[i]; given_card[i] = '\0'; - if(is_card_bit(cot->card_arr[cot->card_arr_idx-2], given_card, trump_suit)){ + if(is_card_beat(cot->card_arr[cot->card_arr_idx-2], given_card, trump_suit)){ stack_card = remove_card_from_stack(&client->deck, given_card); put_defender_card_on_table(cot, stack_card); return 1; @@ -363,10 +363,10 @@ int get_cards_from_tossing_player(struct session *client, data_length = sprintf(output_buffer, "%d:%s\n", card_acceptance_status, all_cards_received_status ? "all" : "not all"); write_to_client(client->fd, data_length); - if(all_cards_received_status) + if(!card_return_status) return answer_got; else - return anwer_got_with_limit; + return answer_got_with_limit; } void print_game_result(const struct session *client, int durak_position) diff --git a/server/server_game_process.c b/server/server_game_process.c index 369f3d6..451fce3 100644 --- a/server/server_game_process.c +++ b/server/server_game_process.c @@ -223,8 +223,8 @@ void update_game_info(struct game_info *gi, int players_number, gi->position_whose_turn = position_whose_turn; } -int is_card_bit(const char *attack_card, const char *defend_card, - const char *trump_suit) +int is_card_beat(const char *attack_card, const char *defend_card, + const char *trump_suit) { int length, attack_rank, defend_rank; const char *attack_suit, *defend_suit; @@ -295,9 +295,17 @@ static int trump_cards_left_uncovered(player_cards remaining_cards, return 0; } +static void clean_up_stacks(player_cards *involved_cards, + player_cards *trump_cards, + player_cards *remaining_attack_cards) +{ + clear_stack(involved_cards); + clear_stack(trump_cards); + clear_stack(remaining_attack_cards); +} + /* * 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) @@ -325,8 +333,8 @@ int check_defender_can_defend(struct card_queue *cq, min_rank = 0; while(next_defend_card) { - if(is_card_bit(next_attack_card->str, next_defend_card->str, - trump_suit)) + if(is_card_beat(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)) @@ -351,8 +359,10 @@ int check_defender_can_defend(struct card_queue *cq, * 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)) + if(trump_cards_left_uncovered(remaining_attack_cards, trump_suit)) { + clean_up_stacks(&involved_cards, &trump_cards, &remaining_attack_cards); return 0; + } while(remaining_attack_cards) { if(!is_empty_stack(trump_cards)) { pop_stack(&trump_cards); @@ -360,8 +370,11 @@ int check_defender_can_defend(struct card_queue *cq, } else break; } - if(!is_empty_stack(remaining_attack_cards)) + if(!is_empty_stack(remaining_attack_cards)) { + clean_up_stacks(&involved_cards, &trump_cards, &remaining_attack_cards); return 0; + } + clean_up_stacks(&involved_cards, &trump_cards, &remaining_attack_cards); return 1; } diff --git a/server/server_game_process.h b/server/server_game_process.h index 0259751..613fc91 100644 --- a/server/server_game_process.h +++ b/server/server_game_process.h @@ -43,8 +43,8 @@ struct game_info* get_new_game_info(int players_number, int *card_quantity_arr, struct card_queue *cq, struct cards_on_table *cot); -int is_card_bit(const char *attack_card, const char *defend_card, - const char *trump_suit); +int is_card_beat(const char *attack_card, const char *defend_card, + const char *trump_suit); int check_defender_can_defend(struct card_queue *cq, player_cards deck, const char *trump_suit); -- cgit v1.2.3