diff options
-rw-r--r-- | card_queue.c | 60 | ||||
-rw-r--r-- | card_queue.h | 20 | ||||
-rw-r--r-- | card_stack.c | 79 | ||||
-rw-r--r-- | card_stack.h | 23 | ||||
-rw-r--r-- | server.c | 700 | ||||
-rw-r--r-- | server.h | 80 | ||||
-rw-r--r-- | server_data_processing.c | 301 | ||||
-rw-r--r-- | server_data_processing.h | 17 | ||||
-rw-r--r-- | server_game_process.c | 397 | ||||
-rw-r--r-- | server_game_process.h | 72 |
10 files changed, 1749 insertions, 0 deletions
diff --git a/card_queue.c b/card_queue.c new file mode 100644 index 0000000..ec42b3b --- /dev/null +++ b/card_queue.c @@ -0,0 +1,60 @@ +#include "card_queue.h" + +#include <stdlib.h> + +void init_queue(struct card_queue *cq) +{ + cq->first = NULL; + cq->last = NULL; +} + +void push_queue(struct card_queue *cq, const char *str) +{ + struct card_queue_item *tmp = malloc(sizeof(struct card_queue_item)); + tmp->str = str; + tmp->next = NULL; + if(!cq->first) { + cd->first = tmp; + cd->last = tmp; + } else { + cd->last->next = tmp; + cd->last = tmp; + } +} + +struct card_queue_item* get_next_card_from_queue(struct card_queue *cq, + struct card_queue_item *prev) +{ + if(prev == NULL) + return cq->first; + else + return prev->next; +} + +int is_empty_queue(struct card_queue *cq) +{ + return !cq->first; +} + +const char* pop_card_queue(struct card_queue *cq) +{ + struct card_queue_item *tmp = NULL; + const char *card = NULL; + + tmp = cq->first; + cq->first = cq->first->next; + card = tmp->str; + free(tmp); + return card; +} + +int find_out_card_quantity_in_cq(const struct card_queue *cq) +{ + int counter = 0; + + while(cq) { + ++counter; + cq = cq->next; + } + return counter; +} diff --git a/card_queue.h b/card_queue.h new file mode 100644 index 0000000..475a93e --- /dev/null +++ b/card_queue.h @@ -0,0 +1,20 @@ +#ifndef H_SENTRY_CARD_QUEUE +#define H_SENTRY_CARD_QUEUE + +struct card_queue_item { + const char *str; + struct card_queue_item *next; +}; + +struct card_queue { + struct card_queue_item *first; + struct card_queue_item *last; +}; + +void init_queue(struct card_queue *cq); +void push_queue(struct card_queue *cq, const char *str); +struct card_queue_item* get_next_card_from_queue(struct card_queue *cq, + struct card_queue_item *prev); +int find_out_card_quantity_in_cq(const struct card_queue *cq); + +#endif diff --git a/card_stack.c b/card_stack.c new file mode 100644 index 0000000..b9b61f6 --- /dev/null +++ b/card_stack.c @@ -0,0 +1,79 @@ +#include "card_stack.h" + +#include <stdlib.h> +#include <string.h> + +void init_stack(player_cards *deck) +{ + *deck = NULL; +} + +void push_stack(player_cards *deck, char *str) +{ + struct card_stack_item new_card = malloc(sizeof(struct card_stack_item)); + new_card->str = str; + new_card->next = *deck; + if(new_card->next) + new_card->next->prev = new_card; + new_card->prev = NULL; + *deck = new_card; +} + +int is_empty_stack(const player_cards deck) +{ + return !deck; +} + +int find_out_card_quantity_in_deck(const player_cards deck) +{ + int counter = 0; + + while(deck) { + ++counter; + deck = deck->next; + } + return counter; +} + +const char* remove_card_from_stack(player_cards *deck, const char *str) +{ + struct card_stack_item *tmp = NULL; + struct card_stack_item *first_tmp = *deck; + const char *card = NULL; + + while(first_tmp) { + if(!strcmp(first_tmp->str, str)) { + tmp = first_tmp; + if(first_tmp->prev) + first_tmp->prev->next = first_tmp->next; + else + *deck = first_tmp->next; + if(first_tmp->next) + first_tmp->next->prev = first_tmp->prev; + card = tmp->str; + free(tmp); + return card; + } + first_tmp = first_tmp->next; + } + return 0; +} + +struct card_stack_item* get_next_card_from_stack(player_cards deck, + player_cards prev) +{ + if(prev == NULL) + return deck; + else + return prev->next; +} + +int find_card_in_stack(player_cards involved_cards, const char *str) +{ + while(involved_cards) { + if(!strcmp(involved_cards->str, str)) + return 1; + involved_cards = involved_cards->next; + } + return 0; +} diff --git a/card_stack.h b/card_stack.h new file mode 100644 index 0000000..37612aa --- /dev/null +++ b/card_stack.h @@ -0,0 +1,23 @@ +#ifndef CARD_STACK_H_SENTRY +#define CARD_STACK_H_SENTRY + +struct card_stack_item { + char *str; + struct card_stack_item *next; + struct card_stack_item *prev; +}; + +typedef struct card_stack_item* player_cards; + +void init_stack(player_cards *deck); +void push_stack(player_cards *deck, char *str); +int is_empty_stack(const player_cards deck); +int find_out_card_quantity_in_deck(const player_cards deck); +const char* remove_card_from_stack(player_cards *deck, const char *str); +struct card_stack_item* get_next_card_from_stack(player_cards deck, + player_cards prev); +int find_card_in_stack(player_cards involved_cards, const char *str); +int is_empty_queue(struct card_queue *cq); +const char* pop_card_queue(struct card_queue *cq); + +#endif diff --git a/server.c b/server.c new file mode 100644 index 0000000..74b2a92 --- /dev/null +++ b/server.c @@ -0,0 +1,700 @@ +#include <stdio.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <syslog.h> +#include <time.h> + +#include "server.h" +#include "server_data_processing.h" +#include "server_game_process.h" +#include "card_stack.h" +#include "card_queue.h" + + +static void init_session(struct session *new_session, struct sockaddr_in *from, + int fd, int player_position) +{ + new_session->fd = fd; + new_session->record = 1; + new_session->state = display_only_table; + new_session->player_position = player_position; + new_session->tm = none; + new_session->defense_lost = 0; + init_stack(new_session->deck); +} + +static int accept_client(struct server *serv) +{ + int fd, i, flags; + struct sockaddr_in addr; + struct session *new_session; + socklen_t len = sizeof(addr); + fd = accept(serv->listen_socket, (struct sockaddr*) &addr, &len); + if(fd == -1) + return -1; + + if(fd >= serv->max_sess_arr_size) { + int newlen = serv->max_sess_arr_size; + while(fd >= newlen) + newlen += init_sess_arr_size; + serv->sess_arr = + realloc(serv->sess_arr, newlen * sizeof(struct session*)); + for(i = serv->max_sess_arr_size; i < newlen; i++) + serv->sess_arr[i] = NULL; + serv->max_sess_arr_size = newlen; + } + new_session = malloc(sizeof(struct session)); + serv->sess_arr[fd] = new_session; + ++serv->connected_players_counter; + init_session(new_session, &addr, fd, serv->connected_players_counter); + return 1; +} + +static int check_playable_player_number(struct server *serv) +{ + return serv->connected_players_counter >= 2 && + serv->connected_players_counter < 8; +} + +static int is_max_playable_player_number(struct server *serv) +{ + return serv->connected_players_counter == 8; +} + +static void init_new_game(struct server *serv) +{ + int i,j, lowest_trump, current_trump, who_attack; + /* idx in serv->turn_queue */ + who_attack = -1; + lowest_trump = 0; + + serv->shuffled_deck = get_shuffled_deck(); + serv->trump_suit = find_trump_suit(serv->shuffled_deck, + serv->shuffled_deck_size); + serv->turn_queue = malloc(sizeof(struct session*) * + serv->connected_players_counter); + serv->card_quantity_arr = malloc(sizeof(int) * + serv->connected_players_counter); + serv->position_whose_turn = 0; + serv->cq = malloc(sizeof(struct card_queue)); + serv->cot = malloc(sizeof(struct cards_on_table)); + /* + * dealing cards to all and + * determining who moves first + */ + for(i = 0, j = 0; i < serv->max_sess_arr_size; ++i) { + if(serv->sess_arr[i]) { + serv->turn_queue[j] = serv->sess_arr[i]; + deal_first_cards(serv->shuffled_deck, &serv->deck_size, + &serv->sess_arr[i]->deck); + found_trump = find_lowest_trump(serv->sess_arr[i]->deck, + serv->trump_suit); + if(found_trump) + if(!lowest_trump || found_trump < lowest_trump) { + lowest_trump = found_trump; + who_attack = j; + } + ++j; + } + } + /* random selection of the first player */ + if(who_attack == -1) { + who_attack = + 0 + (int)((double)serv->connected_players_counter*rand()/ + (RAND_MAX + 1.0)); + } + for(i = 0; i < who_attack; ++i) + shift_turn_queue_by_one(serv->turn_queue, + serv->connected_players_counter); + update_card_quantity_arr(serv); + init_queue(serv->cq); + serv->cot->card_arr_idx = -1; + serv->gi = get_new_game_info(serv->connected_players_counter, + serv->card_quantity_arr, + serv->shuffled_deck_size, + serv->trump_suit, serv->position_whose_turn, + serv->cq, serv->cot); +} + +static void set_whose_turn(struct server *serv, enum client_game_states state) +{ + switch(state) { + case attack: + serv->position_whose_turn = serv->turn_queue[0]->player_position; + break; + case defense: + serv->position_whose_turn = serv->turn_queue[1]->player_position; + break; + case tossing: + serv->position_whose_turn = 0; + } +} + +static void set_state_for_client(struct server *serv, + enum client_game_states state) +{ + int i; + + switch(state) { + case attack: + serv->turn_queue[0]->state = attack; + break; + case defense: + serv->turn_queue[1]->state = defense; + break; + case tossing: + serv->turn_queue[1]->state = tossing_expectation; + } + + for(i = 0; i < serv->max_sess_arr_size; ++i) { + switch(state) { + case attack: + if(serv->sess_arr[i] && serv->sess_arr[i] != serv->turn_queue[0]) + serv->sess_arr[i]->state = attack_expectation; + break; + case defense: + if(serv->sess_arr[i] && serv->sess_arr[i] != serv->turn_queue[1]) + serv->sess_arr[i]->state = defense_expectation; + break; + case tossing: + if(serv->sess_arr[i] && serv->sess_arr[i] != serv->turn_queue[1]) { + if(check_player_can_tossing(serv->sess_arr[i]->deck, + serv->cot)) { + serv->sess_arr[i]->answer_wait; + serv->sess_arr[i]->state = tossing; + } else { + serv->sess_arr[i]->none; + serv->sess_arr[i]->state = tossing_expectation; + } + } + break; + case display_only_table: + if(serv->sess_arr[i]) + serv->sess_arr[i]->state = display_only_table; + break; + } + } +} + +static void set_record_status_for_all(struct server *serv) +{ + int i; + for(i = 0; i < serv->max_sess_arr_size; ++i) + if(serv->sess_arr[i]) + serv->sess_arr[i]->record = 1; +} + +static int print_table_condition(struct server *serv) +{ + return !check_defender_can_defend(serv->cq, serv->turn_queue[1]->deck, + serv->trump_suit) && + !check_someone_can_toss_card(serv->turn_queue, + serv->connected_players_counter, + serv->cq, serv->cot); +} + +static int defense_condition(struct server *serv) +{ + return check_defender_can_defend(serv->cq, serv->turn_queue[1]->deck, + serv->trump_suit); +} + +static void define_phase_after_defense(struct serve *serv) +{ + /* card wasn't beated */ + if(serv->cot->card_arr[serv->cot->card_arr_idx] == '-') { + 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)) + { + set_state_for_client(serv, tossing); + set_whose_turn(serv, tossing); + serv->state = tossing_phase_out; + /* then begin new attack */ + } else { + move_all_cards_to_defender(serv->cot, &serv->turn_queue[1]->deck); + set_state_for_client(serv, attack); + /* add shifting of turn arr*/ + set_whose_turn(serv, attack); + serv->state = attack_phase_out; + } + /* can defender continue defense? */ + } else { + if(is_empty_queue(serv->cq)) { + if(check_something_can_toss_card(serv->turn_queue, + serv->connected_players_counter, + serv->cq, serv->cot)) + { + set_state_for_client(serv, tossing); + set_whose_turn(serv, tossing); + serv->state = tossing_phase_out; + } else { + /* remove cards from table */ + remove_cards_from_table(serv->cot); + /* TODO: deal cards, shift turn queue */ + } + /* card queue contains some cards for defender */ + } else { + /* defender can defense */ + if(defense_condition(serv)) { + put_one_card_from_queue_to_table(serv->cot, serv->cq); + set_state_for_client(serv, defense); + set_whose_turn(serv, defense); + serv->state = defense_phase_out; + /* defender can't 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)) + { + set_state_for_client(serv, tossing); + 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; + } + } + } + } +} + +static void determine_server_state(struct server *serv) +{ + int i; + + switch(serv->state) { + case no_players: + serv->state = first_player; + break; + case first_player: + if(check_playable_player_number(serv)) + serv->state = confirmation_waiting; + break; + case confirmation_waiting: + if(serv->confirmation_status || is_max_playable_player_number(serv)) { + set_record_status_for_all(serv); + init_new_game(serv); + serv->state = start_game; + } + break; + case start_game: + set_state_for_client(serv, attack); + set_whose_turn(serv, attack); + set_record_status_for_all(serv); + serv->state = attack_phase_out; + break; + case attack_phase_out: + serv->state = attack_phase_in; + break; + case attack_phase_in: + 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->state = table; + } else 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; + } else { + set_state_for_client(serv, tossing); + set_whose_turn(serv, tossing); + put_all_cards_from_queue_to_table(serv->cot, serv->cq); + /* ??? */ + serv->state = tossing_phase_out; + } + set_record_status_for_all(serv); + update_card_quantity_arr(serv); + update_game_info(serv->gi, serv->connected_players_counter, + serv->shuffled_deck_size, serv->position_whose_turn); + break; + case table: + move_all_cards_to_defender(serv->cot, &serv->turn_queue[1]->deck); + set_record_status_for_all(serv); + set_state_for_client(serv, attack); + /* add shifting of turn arr*/ + set_whose_turn(serv, attack); + serv->state = attack_phase_out; + break; + case defense_phase_out: + serv->state = defense_phase_in; + break; + case defense_phase_in: + define_phase_after_defense(serv); + set_record_status_for_all(serv); + update_card_quantity_arr(serv); + update_game_info(serv->gi, serv->connected_players_counter, + serv->shuffled_deck_size, serv->position_whose_turn); + break; + case tossing_phase_out: + serv->state = tossing_phase_in; + break; + /* all answers received or the limit on card tossing was reached */ + case tossing_phase_in: + if(turn_queue[1]->defense_lost) { + if(is_empty_queue(serv->cq)) { + /* nobody's put any cards on the table */ + /* add shifting */ + set_state_for_client(serv, attack); + set_whose_turn(serv, attack); + serv->state = attack_phase_out; + } + else { + 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)) + { + 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; + } + } + } else { + if(is_empty_queue(serv->cq)) { + remove_cards_from_table(serv->cot); + /* add shifting of queue */ + set_state_for_client(serv, attack); + set_whose_turn(serv, attack); + serv->state = attack_phase_out; + } else { + if(check_defender_can_defend(serv->cq, serv->turn_queue[1], + serv->trump_suit)) { + put_one_card_from_queue_to_table(serv->cot, serv->cq); + set_state_for_client(serv, defense); + set_whose_turn(serv, defense); + serv->state = defense_phase_out; + } 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)) + { + 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; + } + } + } + } + set_record_status_for_all(serv); + update_card_quantity_arr(serv); + update_game_info(serv->gi, serv->connected_players_counter, + serv->shuffled_deck_size, serv->position_whose_turn); + } + serv->change_server_state = 0; +} + +static int new_player_tracking_condition(enum server_states state) +{ + return state == no_players || state == first_player || + state == confirmation_waiting; +} +/* + * when accepting new players + */ +static int server_state_change_condition(struct server *serv) +{ + return + serv->state == no_players || + (serv->state == first_player && check_playable_player_number(serv)) || + (serv->state == confirmation_waiting && + is_max_playable_player_number(serv)); + +} + +static int accept_new_player(struct server *serv) +{ + int accept_result, i; + accept_result = accept_client(serv); + if(accept_result == -1) { + syslog(LOG_ERR, "accept error"); + return -1; + } + /* update info about connected players */ + set_record_status_for_all(serv); + if(server_state_change_condition(serv)) + serv->change_server_state = 1; + return 1; +} + + +static void set_up_player_tracking(struct server *serv, fd_set *readfds, + fd_set *writefds) +{ + int i; + for(i = 0; i < serv->sess_arr[i]; ++i) { + if(!serv->sess_arr[i]) + continue; + + switch(serv->state) { + case first_player: + if(serv->sess_arr[i]->record) + FD_SET(i, writefds); + break; + case confirmation_waiting: + FD_SET(i, readfds); + if(serv->sess_arr[i]->record) + FD_SET(i, writefds); + break; + case start_game: + case attack_phase_out: + case table: + case defense_phase_out: + case tossing_phase_out: + if(serv->sess_arr[i]->record) + FD_SET(i, writefds); + break; + case attack_phase_in: + if(serv->sess_arr[i]->state == attack) + FD_SET(i, readfds); + break; + case defense_phase_in: + if(serv->sess_arr[i]->state == defense) + FD_SET(i, readfds); + break; + case tossing_phase_in: + if(serv->sess_arr[i]->state == tossing && + serv->sess_arr[i]->tm == answer_wait) + FD_SET(i, readfds); + break; + } + } +} + +static int check_server_state_change_conditions(int is_tossing_limit, + enum server_states state) +{ + switch(state) { + case start_game: + case attack_phase_out: + case attack_phase_in: + case defense_phase_out: + case defense_phase_in: + case tossing_phase_out: + return 1; + case tossing_phase_in: + if(tossing_limit || check_all_answers_were_received(serv->turn_queue, + serv->connected_players_counter)) + return 1; + } + return 0; +} + +static void make_data_transfer(struct server *serv, fd_set *readfds, + fd_set *writefds) +{ + int i, result, tossing_limit = 0; + for(i = 0; i < serv->max_sess_arr_size; ++i) { + if(!serv->sess_arr[i]) + continue; + + switch(serv->state) { + case first_player: + if(FD_ISSET(i, writefds)) { + result = print_message_for_first_player(i); + serv->sess_arr[i]->record = 0; + } + break; + case confirmation_waiting: + if(FD_ISSET(i, writefds) && serv->sess_arr[i]->record) { + result = + print_connected_players(i, serv->connected_players_counter); + serv->sess_arr[i]->record = 0; + } + if(FD_ISSET(i, readfds)) { + result = check_readiness(serv->sess_arr[i]); + if(result == 1) + serv->change_server_state = 1; + } + break; + case attack_phase_out: + case defense_phase_out: + 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); + serv->sess_arr[i]->record = 0; + break; + case attack_phase_in: + if(FD_ISSET(i, readfds)) + result = get_cards_from_attacker(serv->sess_arr[i], serv->cq); + break; + case defense_phase_in: + if(FD_ISSET(i, readfds)) + result = get_card_from_defender(serv->sess_arr[i], serv->cot); + break; + case tossing_phase_in: + if(FD_ISSET(i, readfds)) { + /* to determine that the player can no longer tossing */ + if(tossing_limit) + serv->sess_arr[i]->tm = cancel; + result = + get_cards_from_tossing_player(serv->sess_arr[i], + serv->turn_queue[1]->deck, + serv->cot, serv->cq); + if(result == 1 || result == 2) + serv->sess_arr[i]->tm = answer_got; + + if(result == 2) + tossing_limit = 1; + else if(result == 3) + serv->sess_arr[i]-> = cancel; + } + break; + } + } + if(serv->state == start_game || serv->state == table) + sleep(2); + if(check_server_state_change_conditions(tossing_limit, serv->state)) + serv->change_server_state = 1; +} + +int main_loop(struct server *serv) +{ + int i, maxfd, accept_result; + fd_set readfds, writefds; + + for(;;) { + if(serv->change_server_state) + determine_server_state(serv); + FD_ZERO(&readfds); + FD_ZERO(&writefds); + + if(new_player_tracking_condition(serv->state)) { + FD_SET(serv->listen_socket, &readfds); + maxfd = serv->listen_socket; + } + + set_up_player_tracking(serv, &readfds, &writefds); + + select(maxfd + 1, &readfds, &writefds, NULL, NULL); + + if(FD_ISSET(serv->listen_socket, &readfds)) { + accept_result = accept_new_player(serv); + if(accept_result == -1) + return 4; + } + make_data_transfer(serv, &readfds, &writefds); + } +} + +/* + * 0 - error + * 1 - success + */ +static int init_server(struct server *serv, int port) +{ + int opt, i; + struct sockaddr_in addr; + + serv->listen_socket = socket(AF_INET, SOCK_STREAM, 0); + if(serv->listen_socket == -1) + return 0; + + opt = 1; + setsockopt(serv->listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, + sizeof(opt)); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(port); + + if(bind(serv->listen_socket, (struct sockaddr*) &addr, sizeof(addr)) == -1) + return 0; + + serv->sess_arr = malloc(sizeof(*serv->sess_arr) * + init_sess_arr_size); + serv->max_sess_arr_size = init_sess_arr_size; + for(i = 0; i < init_sess_arr_size; i++) + serv->sess_arr[i] = NULL; + + serv->state = no_players; + serv->change_server_state = 0; + serv->connected_players_counter = 0; + serv->confirmation_status = 0; + serv->shuffled_deck = NULL; + serv->shuffled_deck_size = max_shuffled_deck_size; + serv->gi = NULL; + serv->card_quantity_arr = NULL; + serv->cq = NULL; + serv->cot = NULL; + + listen(serv->listen_socket, listen_qlen); + return 1; +} + +#if 0 +static void demonization() +{ + int pid; + + close(0); + close(1); + close(2); + open("/dev/null", O_RDONLY); + open("/dev/null", O_WRONLY); + open("/dev/null", O_WRONLY); + chdir("/"); + pid = fork(); + if(pid) + exit(0); + setsid(); + pid = fork(); + if(pid) + exit(0); +} +#endif + +int main(int argc, char **argv) +{ + unsigned short port; + struct server serv; + + if(argc != 2) { + fprintf(stderr, + "Usage: <port>\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.h b/server.h new file mode 100644 index 0000000..787d767 --- /dev/null +++ b/server.h @@ -0,0 +1,80 @@ +#ifndef SERVER_H_SENTRY +#define SERVER_H_SENTRY + +#include "card_qeueu.h" + +enum { + max_buffer_size = 4096, + listen_qlen = 32, + init_sess_arr_size = 32 +}; + +enum server_states { + no_players, + first_player, + confirmation_waiting, + start_game, + attack_phase_out, + attack_phase_in, + defense_phase_out, + defense_phase_in, + tossing_phase_out, + tossing_phase_in, + table +}; + +enum client_game_states { + display_only_table, + attack_expectation, + defense_expectation, + tossing_expectation, + attack, + defense, + tossing +}; + +enum tossing_mode { + cancel, + answer_wait, + answer_got, + none +}; + +struct session { + int fd; + enum client_game states state; + /* read data from client */ + char buffer[max_buffer_size]; + int buffer_used; + int record; + player_cards deck; + int player_position; + enum tossing_mode tm; + int defense_lost; +}; + +struct cards_on_table { + /* + * example: 2^ \ - 10# \ K# + */ + const char* card_arr[max_card_arr_size]; + int card_arr_idx; +}; + +struct server { + int change_server_state; + int listen_socket; + struct session **sess_arr; + int max_sess_arr_size; + int connected_players_counter; + char **shuffled_deck; + int shuffled_deck_size; + struct game_info *gi; + struct session **turn_queue; + int *card_quantity_arr; + int number_whose_turn; + struct card_queue *cq; + struct cards_on_table *cot; +}; + +#endif diff --git a/server_data_processing.c b/server_data_processing.c new file mode 100644 index 0000000..c313013 --- /dev/null +++ b/server_data_processing.c @@ -0,0 +1,301 @@ +#include "server_data_processing.h" +#include "server.h" + +#include <fcntl.h> +#include <stdio.h> +#include <string.h> + +enum { + output_buffer_size = 1024; +}; + +static char output_buffer[output_buffer_size]; + +static int write_to_client(int fd, int length) +{ + return write(fd, output_buffer, length); +} + +static int read_from_client(int fd, char *buffer, int max_buffer_size) +{ + int read_result; + read_result = read(fd, buffer, max_buffer_size); + if(read_result <= 0) + return 0; + /* buffer overflow */ + if(read_result >= max_buffer_size) + return 0; +} + +int print_message_for_first_player(int fd) +{ + char *str_end; + str_end = stpcpy(output_buffer, "first\n"); + return write_to_client(fd, strlen("first\n")); +} + +int print_connected_players(int fd, int number) +{ + int data_size; + data_size = sprintf(output_buffer, "%u\n", number); + return write_to_client(fd, data_size); +} + +/* + * 1 - ready + * 0 - buffer overflow or player closed session + * -1 - not ready + */ +int check_readiness(const struct session *client) +{ + int read_result; + read_result = read_from_client(client->fd, client->buffer, max_buffer_size); + if(!read_result) + return read_result; + if(client->buffer[0] == '\n') + return 1; + else + return -1; +} + +static void copy_card_queue(int *offset, struct card_queue *cq) +{ + int length, i; + struct card_queue_item *next_attack_card; + + next_attack_card = NULL; + while((next_attack_card = get_next_card_from_queue(cq, next_attack_card))) { + length = strlen(next_attack_card->str); + for(i = 0; i < length; ++i, ++*offset) + *(output_buffer + *offset) = (next_attack_card->str)[i]; + *(output_buffer + *offset) = '\'; + ++*offset; + } + *(output_buffer + *offset-1) = ':'; +} + +static void copy_cards_on_table(int *offset, struct cards_on_table *cot) +{ + int i, j, length; + for(i = 0; i <= cot->card_arr_idx; ++i) { + length = strlen(cot->card_arr[i]); + for(j = 0; j < length; ++j, ++*offset) + *(output_buffer + *offset) = cot->card_arr[i][j]; +#if 0 + *(output_buffer + *offset) = '\'; +#endif + } + *(output_buffer + *offset) = ':'; + /* free pos */ + ++*offset; +} + +static void copy_own_deck(int *offset, player_cards deck) +{ + const char *card; + int length, i; + + while(deck) { + card = deck->str; + length = strlen(card); + for(i = 0; i < length; ++i, ++*offset) + *(output_buffer + *offset) = card[i]; + *(output_buffer + *offset) = '\'; + deck = deck->next; + } + *(output_buffer + *offset) = ':'; + ++*offset; +} + +static void copy_base_info(int *free_pos, struct game_info *gi, + player_cards deck, int player_position) +{ + *free_pos = + sprintf(output_buffer, "%u:%u:%u:%u:%s:", state, gi->players_number, + gi->shuffled_cards_left, player_position, gi->trump_suit); + /* opponent's card count */ + for(i = 0; i < gi->players_number; ++i) { + + *free_pos += sprintf(output_buffer + *free_pos, "%u:", + gi->card_quantity_arr[i]); + } + if(gi->cot->card_arr_idx != -1) + copy_cards_on_table(free_pos, gi->cot); + if(!is_empty_stack(deck)) + copy_own_deck(free_pos, deck); +} + +int print_game_part(const struct session *client, struct game_info *gi) +{ + int free_pos, i; /* free_pos == data length */ + + switch(client->state) { + case display_only_table: + copy_base_info(&free_pos, gi, client->deck, client->player_position); + *(output_buffer + free_pos-1) = '\n'; + break; + case attack: + /* let the client print card tips and wait for input */ + copy_base_info(&free_pos, gi, client->deck, client->player_position); + *(output_buffer + free_pos-1) = '\n'; + break; + case attack_expectation: + /* other clents will be waiting particular player */ + copy_base_info(&free_pos, gi, deck, player_position); + free_pos += sprintf(output_buffer + free_pos, "%u:", + gi->position_whose_turn); + /* instead of last ':' */ + *(output_buffer + free_pos-1) = '\n'; + break; + case defense: + copy_base_info(&free_pos, gi, client->deck, client->player_position); + *(output_buffer + free_pos-1) = '\n'; + break; + case defense_expectation: + copy_base_info(&free_pos, gi, client->deck, client->player_position); + free_pos += sprintf(output_buffer + free_pos, "%u:", + gi->position_whose_turn); + copy_card_queue(&free_pos, gi->cq); + *(output_buffer + free_pos-1) = '\n'; + break; + /* + * who haven't got tossing card (including defender) must wait + * when other players make moves + */ + case tossing_expectation: + copy_base_info(&free_pos, gi, client->deck, client->player_position); + *(output_buffer + free_pos-1) = '\n'; + break; + case tossing: + copy_base_info(&free_pos, gi, client->deck, client->player_position); + *(output_buffer + free_pos-1) = '\n'; + break; + } + return write_to_client(client->fd, free_pos); +} + +int get_cards_from_attacker(struct session *client, struct card_queue *cq) +{ + int read_result, i, j; + char given_card[4]; + const char *stack_card = NULL; + + read_result = read_from_client(client->fd, client->buffer, max_buffer_size); + if(!read_result) + return read_result; + for(i = 0, j = 0; i < read_result && client->buffer[i] != '\n'; ++i) { + if(read_result[i] == '\') { + given_card[j] = '\0'; + j = 0; + stack_card = remove_card_from_stack(&client->deck, given_card); + push_queue(cq, stack_card); + continue; + } + given_card[j] = client->buffer[i]; + ++j; + } +} + +/* + * 0 - error + * 1 - card was bited, not bited, or + * defender didn't want to continue defense phase + * + */ +int get_card_from_defender(struct session *client, struct cards_on_table *cot) +{ + int read_result, i; + char given_card[4]; + const char *stack_card = NULL; + + read_result = read_from_client(client->fd, client->buffer, max_buffer_size); + if(!read_result) + return read_result; + for(i = 0; i < read_result && client->buffer[i] != '\n'; ++i) + given_card[i] = client->buffer[i]; + if(given_card[0] == '\n') + return 1; + given_card[i] = '\0'; + if(is_card_bit(cot->card_arr[card_arr_idx-2], given_card)) { + stack_card = remove_card_from_stack(&client->deck, given_card); + put_defender_card_on_table(cot, stack_card); + return 1; + } else + return 0; +} + +static int skip_cards_in_queue(int total_defense_cards, int total_attack_cards) +{ + 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; +} + +/* + * 0 - buffer overflow or client closed connection + * 1 - some number of cards added to card queue + * 2 - card toss limit was reached when accepting cards from this player + * 3 - player refused to toss the card + */ +int get_cards_from_tossing_player(struct session *client, + const player_cards defense_deck, + struct cards_on_table *cot, + struct card_queue *cq) +{ + int read_result, i, j, total_attack_cards, total_defense_cards; + int card_return_status = 0, all_cards_received_status = 1; + int data_length; + char given_card[4]; + const char *stack_card = NULL; + + read_result = read_from_client(client->fd, client->buffer, max_buffer_size); + if(!read_result) + return read_result; + + 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); + + for(i = 0, j = 0; i < read_result; ++i) { + if(read_result[i] == '\') { + /* cancellation */ + if(given_card[0] == '\n') + return 3; + /* tossing limit was set */ + if(client->tm == cancel) { + /* 8 - it's impossible to accept cards due to tossing limit */ + data_length = sprintf(output_buffer, "%d:%s\n", 8, + "tossing limit"); + write_to_client(client->fd, data_length); + return 3; + } + given_card[j] = '\0'; + j = 0; + if(card_return_status) { + all_cards_received_status = 0; + } else if(is_correct_tossing_card(given_card, cot)) { + stack_card = remove_card_from_stack(&client->deck, given_card); + push_queue(cq, stack_card); + total_attack_cards += find_out_card_quantity_in_cq(cq); + if(skip_cards_in_queue(total_defense_cards, total_attack_cards)) + { + card_return_status = 1; + } + } + continue; + } + given_card[j] = buffer[i]; + ++j; + } + /* 7 -- state for result of received cards */ + data_length = sprintf(output_buffer, "%d:%s\n", 7, + all_cards_received_status ? "all" : "not all"); + write_to_client(client->fd, data_length); + if(all_cards_received_status) + return 1; + else + return 2; +} diff --git a/server_data_processing.h b/server_data_processing.h new file mode 100644 index 0000000..f047ada --- /dev/null +++ b/server_data_processing.h @@ -0,0 +1,17 @@ +#ifndef SERVER_DATA_PROCESSING_H_SENTRY +#define SERVER_DATA_PROCESSING_H_SENTRY + +#include "server_game_process.h" + +int print_message_for_first_player(int fd); +int print_connected_players(int fd, int number); +int check_readiness(const struct session *client); +int print_game_part(const struct session *client, struct game_info *gi); +int get_cards_from_attacker(struct session *client, struct card_queue *cq); +int get_card_from_defender(struct session *client, struct cards_on_table *cot); +int get_cards_from_tossing_player(struct session *client, + const player_cards defense_deck, + struct cards_on_table *cot, + struct card_queue *cq); + +#endif diff --git a/server_game_process.c b/server_game_process.c new file mode 100644 index 0000000..5f1aacb --- /dev/null +++ b/server_game_process.c @@ -0,0 +1,397 @@ +#include "server_game_process.h" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +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)); +} + +char** get_shuffled_deck() +{ + int i, new_idx; + char **shuffled_deck = realloc(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(char **shuffled_deck, int *cards_left, player_cards *deck) +{ + int i, last_idx; + 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; + } + } +} + +const char* find_trump_suit(const char **shuffled_deck, int *cards_left) +{ + const char *trump_suit = NULL; + trump_suit = shuffled_deck[0] ? shuffled_deck[0] : NULL; + if(trump_suit) + shuffled_deck[0] = NULL; + trump_suit += strlen(trump_suit) - 1; + --*cards_left; + return trump_suit; +} + +int convert_rank_to_int(const char *card) +{ + int length, rank = 0; + char str_rand[2]; + + length = strlen(card); + /* 10 - the only one of its kind */ + if(length == 3) + return 10; + strncpy(str_rank, 1); + str_rank[1] = '\0'; + if(!strncmp(str_rank, "J", 1)) + rank = 11; + else if(!strncmp(str_rank, "Q", 1)) + rank = 12; + else if(!strncmp(str_rank, "K", 1)) + rank = 13; + else if(!strncmp(str_rank, "A", 1)) + rank = 14; + else + rank = strtol(str_rank, NULL, 10); + return rank; +} + +int find_lowest_trump(player_cards deck, char *trump_suit) +{ + const char *card; + int lowest_rank = 0; + + while(deck) { + if(!strncmp(card+length-1, trump_suit, 1)) { + lowest_rank = convert_rank_to_int(deck->str); + if(!lowest_rank || lowest_rank > rank) + lowest_rank = rank; + } + deck = deck->next; + } + return lowest_rank; +} + +void shift_turn_queue_by_one(struct session **turn_queue, int size) +{ + int i; + struct session *tmp = turn_queue[0]; + for(i = 1; i < size; ++i) + turn_queue[i-1] = turn_queue[i]; + turn_queue[i-1] = tmp; +} + +void update_card_quantity_arr(struct server *serv) +{ + int i, j; + + for(i = 0, j = 0; i < serv->max_sess_arr_size; ++i) + if(serv->sess_arr[i]) { + serv->card_quantity_arr[j] = + find_out_card_quantity_in_deck(serv->sess_arr[i]->deck); + ++j; + } +} + +struct game_info* get_new_game_info(int players_number, int *card_quantity_arr, + int shuffled_cards_left, char *trump_suit, + int position_whose_turn, + struct card_queue *cq, + struct cards_on_table *cot) + +{ + struct game_info *gi = malloc(sizeof(game_info)); + gi->players_number = players_number; + gi->card_quantity_arr = card_quantity_arr; + gi->shuffled_cards_left = shuffled_cards_left; + gi->trump_suit = trump_suit; + 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; + else + 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 i, is_bited_card; + struct card_stack_item *next_defend_card; + struct card_queue_item *next_attack_card; + player_cards involved_cards; + + is_bited_card = 0; + init_stack(&involved_cards); + + 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); + + /* stack traversal */ + while(next_defend_card) { + if(is_card_bit(next_attack_card->str, next_defend_card->str, + trump_suit)) + /* if card doesn't meet */ + if(!find_card_in_stack(involved_cards, next_defend_card->str)) { + push_stack(&involved_cards, next_defend_card->str); + is_bited_card = 1; + break; + } + get_next_card_from_stack(deck, next_defend_card); + } + if(is_bited_card) + is_bited_card = 0; + else + 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, + 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] == '-' || cot->card_arr[j] == '\') + 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; +} + +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] == '-' || cot->card_arr[i] == '\') + 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[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] == '-' || cot->card_arr[i] == '\') + 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[card_arr_idx] = card; + ++cot->card_arr_idx; + cot->card_arr[card_arr_idx] = "\\"; + ++cot->card_arr_idx; + cot->card_arr[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[card_arr_idx] = card; + ++cot->card_arr_idx; + cot->card_arr[card_arr_idx] = "\\"; + ++cot->card_arr_idx; + cot->card_arr[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[card_arr_idx] = card; +} + +void move_all_cards_to_defender(struct cards_on_table *cot, player_cards *deck) +{ + const char *card; + +#if 0 + while(!is_empty_queue(cq)) { + card = pop_card_queue(cq); + push_stack(deck, card); + } +#endif + for(i = cot->card_arr_idx; i >= 0; --i) { + if(cot->card_arr == '-' || cot->card_arr == '\') + continue; + push_stack(deck, card); + } + 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 session **turn_queue, int size) +{ + int i; + + for(i = 0; i < size; ++i) + if(turn_queue[i]->tm == answer_wait) + return 0; + return 1; +} diff --git a/server_game_process.h b/server_game_process.h new file mode 100644 index 0000000..1518c8c --- /dev/null +++ b/server_game_process.h @@ -0,0 +1,72 @@ +#ifndef SERVER_GAME_PROCESS_H_SENTRY +#define SERVER_GAME_PROCESS_H_SENTRY + +#include "card_stack.h" +#include "server.h" +#include "card_queue.h" + +enum { + start_deck_size = 6 +}; + +enum { + max_shuffled_deck_size = 52, + max_card_arr_size = 18 +}; + +struct game_info { + int players_number; + int *card_quantity_arr; + int shuffled_cards_left; + const char* trump_suit; + int position_whose_turn; + struct cards_on_table cot; + struct card_queue *cq; +}; + +char** get_shuffled_deck(); +void deal_first_cards(char **shuffled_deck, int *cards_left, + player_cards *deck); + +const char* find_trump_suit(char **shuffled_deck, int *cards_left); +int find_lowest_trump(player_cards deck, char *trump); +void shift_turn_queue_to_first(struct session **turn_queue, int size); +void update_card_quantity_arr(struct server *serv); + +struct game_info* get_new_game_info(int players_number, int *card_quantity_arr, + int shuffled_cards_left, char *trump_suit, + int number_whose_turn); + +int is_card_bit(const char *attack_card, const char *defend_card, + const char *trump_suit); + +int check_defender_can_defend(struct cards_on_table *cot, + struct player_cards deck, const char *trump_suit); + +void update_game_info(struct game_info *gi, int players_number, + int shuffled_cards_left, int position_whose_turn); + +int check_someone_can_toss_card(struct session **turn_queue, + int players_quantity, + struct card_queue *cq); + +int check_player_can_toss_card(player_cards deck, struct cards_on_table *cot); +int is_correct_tossing_card(const char *card, struct cards_on_table *cot); + +void put_all_cards_from_queue_to_table(struct cards_on_table *cot, + struct card_queue *cq); + +void put_one_card_from_queue_to_table(struct cards_on_table *cot, + struct card_queue *cq); + +void put_defender_card_on_table(struct cards_on_table *cot, const char *card) + +void move_all_cards_to_defender(struct cards_on_table *cot, + struct card_queue *cq, player_cards *deck); +void remove_cards_from_table(struct cards_on_table *cot); + +int calculate_defense_card_quantity_on_table(const struct cards_on_table *cot); +int calculate_attack_card_quantity_on_table(const struct cards_on_table *cot); +int check_all_answers_were_received(const session **turn_queue, int size); + +#endif |