From eb90648bdad1443c9cfc72e903a93642e10a0ab7 Mon Sep 17 00:00:00 2001 From: scratko Date: Fri, 16 Aug 2024 18:10:11 +0300 Subject: Global fixes v2.0 Added spectator mode. Added screen of game result. Added definition of durak. If not all players can replenish their decks, they take cards one at a time in turn. --- server/server.c | 219 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 164 insertions(+), 55 deletions(-) (limited to 'server/server.c') diff --git a/server/server.c b/server/server.c index b2f1c3b..1655448 100644 --- a/server/server.c +++ b/server/server.c @@ -7,7 +7,6 @@ #include #include #include -#include #include "server.h" #include "server_data_processing.h" @@ -35,7 +34,6 @@ static int accept_client(struct server *serv) struct session *new_session; socklen_t len = sizeof(addr); fd = accept(serv->listen_socket, (struct sockaddr*) &addr, &len); - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (int[]){1}, sizeof(int)); if(fd == -1) return -1; @@ -56,6 +54,10 @@ static int accept_client(struct server *serv) return 1; } +static void close_connection(struct server *serv) +{ +} + static int check_playable_player_number(struct server *serv) { return serv->connected_players_counter >= 2 && @@ -84,6 +86,7 @@ static void init_new_game(struct server *serv) #endif serv->turn_queue = malloc(sizeof(struct session*) * serv->connected_players_counter); + serv->turn_queue_size = serv->connected_players_counter; /* number of cards each player holds */ serv->cc.number_arr_idx = serv->connected_players_counter - 1; serv->cc.number_arr = malloc(sizeof(int) * serv->connected_players_counter); @@ -117,13 +120,15 @@ static void init_new_game(struct server *serv) for(i = 0; i < who_attack; ++i) shift_turn_queue_by_one(serv->turn_queue, serv->connected_players_counter); - update_card_quantity_arr(serv); + update_card_quantity_arr(serv->turn_queue, serv->cc); init_queue(&serv->cq); serv->gi = get_new_game_info(serv->connected_players_counter, serv->cc.number_arr, serv->shuffled_deck_size, serv->trump_card, serv->position_whose_turn, &serv->cq, &serv->cot); + serv->durak_position = 0; + serv->tossing_limit = 0; } static void set_whose_turn(struct server *serv, enum client_game_states state) @@ -141,6 +146,9 @@ static void set_whose_turn(struct server *serv, enum client_game_states state) } } +/* + * state set during game play + */ static void set_state_for_client(struct server *serv, enum client_game_states state) { @@ -159,7 +167,10 @@ static void set_state_for_client(struct server *serv, {} } - for(i = 0; i < serv->connected_players_counter; ++i) { + for(i = 0; i < serv->turn_queue_size; ++i) { + if(serv->turn_queue[i]->state == spectator) + continue; + switch(state) { case attack: if(serv->turn_queue[i] && serv->turn_queue[i] != @@ -193,6 +204,11 @@ static void set_state_for_client(struct server *serv, {} } } + /* end of game */ + if(state == result) + for(i = 0; i < serv->max_sess_arr_size; ++i) + if(serv->sess_arr[i]) + serv->sess_arr[i]->state = result; } static void set_record_status_for_all(struct server *serv) @@ -258,7 +274,7 @@ static void define_phase_after_defense(struct server *serv) if(!is_receiving_cards_limit(&serv->cot, serv->turn_queue[1]->deck, &serv->cq) && check_someone_can_toss_card(serv->turn_queue, - serv->connected_players_counter, + serv->turn_queue_size, &serv->cq, &serv->cot)) { set_state_for_client(serv, tossing); @@ -276,7 +292,7 @@ static void define_phase_after_defense(struct server *serv) if(!is_receiving_cards_limit(&serv->cot, serv->turn_queue[0]->deck, &serv->cq) && check_someone_can_toss_card(serv->turn_queue, - serv->connected_players_counter, + serv->turn_queue_size, &serv->cq, &serv->cot)) { set_state_for_client(serv, tossing); @@ -294,9 +310,8 @@ static void define_phase_after_defense(struct server *serv) set_state_for_client(serv, defense); set_whose_turn(serv, defense); serv->state = defense_phase_out; - } - /* defender can't defense */ -#if 0 + + /* defender can't defense */ } else { serv->turn_queue[1]->defense_lost = 1; put_all_cards_from_queue_to_table(&serv->cot, &serv->cq); @@ -308,15 +323,10 @@ static void define_phase_after_defense(struct server *serv) set_whose_turn(serv, tossing); serv->state = tossing_phase_out; } else { - move_all_cards_to_defender(&serv->cot, - &serv->turn_queue[1]->deck); - /* add shifting of turn arr*/ - set_state_for_client(serv, attack); - set_whose_turn(serv, attack); - serv->state = attack_phase_out; + set_state_for_client(serv, display_only_table); + serv->state = table; } } -#endif } } } @@ -334,7 +344,7 @@ static void define_phase_after_tossing(struct server *serv) if(is_receiving_cards_limit(&serv->cot, serv->turn_queue[1]->deck, &serv->cq) && check_someone_can_toss_card(serv->turn_queue, - serv->connected_players_counter, + serv->turn_queue_size, &serv->cq, &serv->cot)) { set_state_for_client(serv, tossing); @@ -364,7 +374,7 @@ static void define_phase_after_tossing(struct server *serv) serv->turn_queue[1]->deck, &serv->cq) && check_someone_can_toss_card(serv->turn_queue, - serv->connected_players_counter, + serv->turn_queue_size, &serv->cq, &serv->cot)) { set_state_for_client(serv, tossing); @@ -381,6 +391,9 @@ static void define_phase_after_tossing(struct server *serv) static void determine_server_state(struct server *serv) { + int key, turn_queue_resizing = 0; + struct session *defender = NULL; + switch(serv->state) { case no_players: serv->state = first_player; @@ -416,38 +429,129 @@ static void determine_server_state(struct server *serv) /* all answers received or the limit on card tossing was reached */ define_phase_after_tossing(serv); set_record_status_for_all(serv); - update_card_quantity_arr(serv); + update_card_quantity_arr(serv->turn_queue, serv->cc); update_game_info(serv->gi, serv->connected_players_counter, serv->shuffled_deck_size, serv->position_whose_turn); break; case table: - if(serv->turn_queue[1]->defense_lost) { - clear_defense_lost_status(serv->turn_queue[1]); - move_all_cards_to_defender(&serv->cot, &serv->turn_queue[1]->deck); - move_turn_queue_two_players_ahead(serv->turn_queue, - serv->connected_players_counter); + 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; } - else { + /* ========= 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); - shift_turn_queue_by_one(serv->turn_queue, - serv->connected_players_counter); + 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; + } + } } - set_record_status_for_all(serv); - set_state_for_client(serv, attack); - set_whose_turn(serv, attack); - /* - * update the number of cards to determine how many cards - * a player still needs to add - */ - update_card_quantity_arr(serv); - deal_cards(serv->shuffled_deck, &serv->shuffled_deck_size, - serv->turn_queue, serv->connected_players_counter, - serv->cc.number_arr); - /* update the card count after giving out */ - update_card_quantity_arr(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); + } + update_game_info(serv->gi, serv->connected_players_counter, serv->shuffled_deck_size, serv->position_whose_turn); - serv->state = attack_phase_out; + set_record_status_for_all(serv); + turn_queue_resizing = 0; + serv->tossing_limit = 0; break; case defense_phase_out: serv->state = defense_phase_in; @@ -455,6 +559,9 @@ static void determine_server_state(struct server *serv) case tossing_phase_out: serv->state = tossing_phase_in; break; + case end_game: + close_connection(serv); + serv->state = no_players; } serv->change_server_state = 0; } @@ -518,6 +625,7 @@ static void set_up_player_tracking(struct server *serv, fd_set *readfds, case table: case defense_phase_out: case tossing_phase_out: + case end_game: if(serv->sess_arr[i]->record) { FD_SET(i, writefds); *maxfd = i > *maxfd ? i : *maxfd; @@ -549,8 +657,7 @@ static void set_up_player_tracking(struct server *serv, fd_set *readfds, } } -static int check_server_state_change_conditions(int is_tossing_limit, - struct server *serv) +static int check_server_state_change_conditions(struct server *serv) { switch(serv->state) { case start_game: @@ -560,12 +667,13 @@ static int check_server_state_change_conditions(int is_tossing_limit, case defense_phase_in: case tossing_phase_out: case table: + case end_game: return 1; case tossing_phase_in: - if(is_tossing_limit || + if(serv->tossing_limit || check_all_answers_were_received((const struct session**) serv->turn_queue, - serv->connected_players_counter)) + serv->turn_queue_size)) return 1; default: return 0; @@ -573,14 +681,10 @@ static int check_server_state_change_conditions(int is_tossing_limit, return 0; } -static void close_connection() -{ -} - static void make_data_transfer(struct server *serv, fd_set *readfds, fd_set *writefds) { - int i, result, tossing_limit = 0; + int i, result; for(i = 0; i < serv->max_sess_arr_size; ++i) { if(!serv->sess_arr[i]) continue; @@ -610,7 +714,8 @@ static void make_data_transfer(struct server *serv, fd_set *readfds, case tossing_phase_out: case table: if(FD_ISSET(i, writefds) && serv->sess_arr[i]->record) - result = print_game_part(serv->sess_arr[i], serv->gi); + result = print_game_part(serv->sess_arr[i], serv->state, + serv->gi); serv->sess_arr[i]->record = 0; break; case attack_phase_in: @@ -627,7 +732,7 @@ static void make_data_transfer(struct server *serv, fd_set *readfds, case tossing_phase_in: if(FD_ISSET(i, readfds)) { /* to determine that the player can no longer tossing */ - if(tossing_limit) + if(serv->tossing_limit) serv->sess_arr[i]->tm = cancel; result = get_cards_from_tossing_player(serv->sess_arr[i], @@ -637,22 +742,26 @@ static void make_data_transfer(struct server *serv, fd_set *readfds, serv->sess_arr[i]->tm = answer_got; if(result == 2) - tossing_limit = 1; + serv->tossing_limit = 1; else if(result == 3) serv->sess_arr[i]->tm = cancel; } break; case no_players: {} + case end_game: + if(FD_ISSET(i, writefds) && serv->sess_arr[i]->record) + print_game_result(serv->sess_arr[i], serv->durak_position); + break; } } if(serv->state == start_game || serv->state == table) sleep(2); - if(check_server_state_change_conditions(tossing_limit, serv)) + if(check_server_state_change_conditions(serv)) serv->change_server_state = 1; /* connection is closed */ if(!result) - close_connection(); + close_connection(serv); } int main_loop(struct server *serv) -- cgit v1.2.3