From a2d696dea797faaa3157046c8ae89cd70e965bff Mon Sep 17 00:00:00 2001 From: scratko Date: Sat, 10 Aug 2024 02:46:56 +0300 Subject: Prefinal version Added client. Moved files to directories. --- Makefile | 17 - card_queue.c | 61 --- card_queue.h | 22 -- card_stack.c | 79 ---- card_stack.h | 21 - client/Makefile | 18 + client/card_handling.c | 64 ++++ client/card_handling.h | 9 + client/card_stack.c | 193 ++++++++++ client/card_stack.h | 29 ++ client/client.c | 245 ++++++++++++ client/client.h | 71 ++++ client/data_decryption.c | 169 +++++++++ client/data_decryption.h | 14 + client/printing_game_frames.c | 104 +++++ client/printing_game_frames.h | 14 + client/verification_client_input.c | 46 +++ client/verification_client_input.h | 12 + server.c | 733 ----------------------------------- server.h | 88 ----- server/Makefile | 17 + server/card_queue.c | 61 +++ server/card_queue.h | 22 ++ server/card_stack.c | 79 ++++ server/card_stack.h | 21 + server/server.c | 759 +++++++++++++++++++++++++++++++++++++ server/server.h | 99 +++++ server/server_data_processing.c | 337 ++++++++++++++++ server/server_data_processing.h | 21 + server/server_game_process.c | 475 +++++++++++++++++++++++ server/server_game_process.h | 78 ++++ server_data_processing.c | 294 -------------- server_data_processing.h | 18 - server_game_process.c | 440 --------------------- server_game_process.h | 73 ---- 35 files changed, 2957 insertions(+), 1846 deletions(-) delete mode 100644 Makefile delete mode 100644 card_queue.c delete mode 100644 card_queue.h delete mode 100644 card_stack.c delete mode 100644 card_stack.h create mode 100644 client/Makefile create mode 100644 client/card_handling.c create mode 100644 client/card_handling.h create mode 100644 client/card_stack.c create mode 100644 client/card_stack.h create mode 100644 client/client.c create mode 100644 client/client.h create mode 100644 client/data_decryption.c create mode 100644 client/data_decryption.h create mode 100644 client/printing_game_frames.c create mode 100644 client/printing_game_frames.h create mode 100644 client/verification_client_input.c create mode 100644 client/verification_client_input.h delete mode 100644 server.c delete mode 100644 server.h create mode 100644 server/Makefile create mode 100644 server/card_queue.c create mode 100644 server/card_queue.h create mode 100644 server/card_stack.c create mode 100644 server/card_stack.h create mode 100644 server/server.c create mode 100644 server/server.h create mode 100644 server/server_data_processing.c create mode 100644 server/server_data_processing.h create mode 100644 server/server_game_process.c create mode 100644 server/server_game_process.h delete mode 100644 server_data_processing.c delete mode 100644 server_data_processing.h delete mode 100644 server_game_process.c delete mode 100644 server_game_process.h diff --git a/Makefile b/Makefile deleted file mode 100644 index 6fb2c5c..0000000 --- a/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -SRCMODULES = card_stack.c card_queue.c server_data_processing.c server_game_process.c server.c -OBJMODULES = $(SRCMODULES:.c=.o) -CC = gcc -CFLAGS = -Wall -g -c - -all: server - -%.o: %.с %.h - $(CC) $(CFLAGS) $< -o $@ - -server: $(OBJMODULES) - $(CC) $(LIBS) $^ -o $@ - --include deps.mk - -deps.mk: $(SRCMODULES) - $(CC) -MM $^ > $@ diff --git a/card_queue.c b/card_queue.c deleted file mode 100644 index 194ea0c..0000000 --- a/card_queue.c +++ /dev/null @@ -1,61 +0,0 @@ -#include "card_queue.h" - -#include - -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) { - cq->first = tmp; - cq->last = tmp; - } else { - cq->last->next = tmp; - cq->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; - struct card_queue_item *tmp = cq->first; - - while(tmp) { - ++counter; - tmp = tmp->next; - } - return counter; -} diff --git a/card_queue.h b/card_queue.h deleted file mode 100644 index 778ece4..0000000 --- a/card_queue.h +++ /dev/null @@ -1,22 +0,0 @@ -#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); -int is_empty_queue(struct card_queue *cq); -const char* pop_card_queue(struct card_queue *cq); - -#endif diff --git a/card_stack.c b/card_stack.c deleted file mode 100644 index aa8af71..0000000 --- a/card_stack.c +++ /dev/null @@ -1,79 +0,0 @@ -#include "card_stack.h" - -#include -#include - -void init_stack(player_cards *deck) -{ - *deck = NULL; -} - -void push_stack(player_cards *deck, const 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(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 deleted file mode 100644 index d380ded..0000000 --- a/card_stack.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef CARD_STACK_H_SENTRY -#define CARD_STACK_H_SENTRY - -struct card_stack_item { - const 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, const char *str); -int is_empty_stack(const player_cards deck); -int find_out_card_quantity_in_deck(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); - -#endif diff --git a/client/Makefile b/client/Makefile new file mode 100644 index 0000000..eeae6c6 --- /dev/null +++ b/client/Makefile @@ -0,0 +1,18 @@ +SRCMODULES = card_handling.c card_stack.c data_decryption.c\ + printing_game_frames.c verification_client_input.c client.c +OBJMODULES = $(SRCMODULES:.c=.o) +CC = gcc +CFLAGS = -Wall -g -c + +all: client + +%.o: %.с %.h + $(CC) $(CFLAGS) $< -o $@ + +client: $(OBJMODULES) + $(CC) $(LIBS) $^ -o $@ + +-include deps.mk + +deps.mk: $(SRCMODULES) + $(CC) -MM $^ > $@ diff --git a/client/card_handling.c b/client/card_handling.c new file mode 100644 index 0000000..011ad40 --- /dev/null +++ b/client/card_handling.c @@ -0,0 +1,64 @@ +#include "card_handling.h" + +#include +#include + +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 is_card_beaten(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; +} + +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; +} diff --git a/client/card_handling.h b/client/card_handling.h new file mode 100644 index 0000000..8dcb072 --- /dev/null +++ b/client/card_handling.h @@ -0,0 +1,9 @@ +#ifndef CARD_HANDLING_H_SENTRY +#define CARD_HANDLING_H_SENTRY + +int convert_rank_to_int(const char *card); +int is_card_beaten(const char *attack_card, const char *defend_card, + const char *trump_suit); +int check_matched_ranks(const char *attack_card, const char *not_defender_card); + +#endif diff --git a/client/card_stack.c b/client/card_stack.c new file mode 100644 index 0000000..5d0700b --- /dev/null +++ b/client/card_stack.c @@ -0,0 +1,193 @@ +#include "card_stack.h" +#include "card_handling.h" +#include "client.h" + +#include +#include + +void init_stack(player_cards *deck) +{ + *deck = NULL; +} + +void push_stack(player_cards *deck, char *str) +{ + struct card_stack_item *tmp = malloc(sizeof(struct card_stack_item)); + tmp->str = str; + tmp->tip = ' '; + tmp->is_usable = 0; + tmp->next = *deck; + *deck = tmp; +} + +void clear_stack(player_cards *deck) +{ + struct card_stack_item *tmp; + + while(*deck) { + tmp = *deck; + *deck = tmp->next; + if(tmp->str) + free(tmp->str); + free(tmp); + } +} + +int is_empty_stack(player_cards deck) +{ + return deck == NULL; +} + +#if 0 +static 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; +} +#endif + +void add_hint_letters_stack(player_cards deck) +{ + unsigned char letter = 'a'; + + while(deck) { + deck->tip = letter; + ++letter; + if(letter > 'z') + letter = 'A'; + deck = deck->next; + } +} + +void mark_card_for_attackers_stack(player_cards deck) +{ + char *card = NULL, *found_card; + struct card_stack_item *search_deck = NULL; + int target_rank, found_rank; + + while(deck) { + /* is the card already marked? */ + if(deck->is_usable) { + deck = deck->next; + continue; + } + card = deck->str; + target_rank = convert_rank_to_int(card); + search_deck = deck->next; + while(search_deck) { + if(search_deck->is_usable) { + search_deck = search_deck->next; + continue; + } + found_card = search_deck->str; + found_rank = convert_rank_to_int(found_card); + if(found_rank == target_rank) + search_deck->is_usable = 1; + search_deck = search_deck->next; + } + deck = deck->next; + } +} +#if 0 +static int is_card_beaten(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; +} +#endif + +void mark_card_for_defenders_stack(player_cards deck, + struct cards_on_table *cot, char *trump_suit) +{ + int i; + + while(deck) { + for(i = 0; i <= cot->card_arr_idx; ++i) + if((i == 0 || !(i % 3)) && is_card_beaten(cot->card_arr[i], + deck->str, trump_suit)) + { + deck->is_usable = 1; + break; + } + deck = deck->next; + } +} +#if 0 +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; +} +#endif + +void mark_card_for_tossing_stack(player_cards deck, struct cards_on_table *cot) +{ + int i; + + while(deck) { + for(i = 0; i <= cot->card_arr_idx; ++i) { + if(cot->card_arr[i][0] == '-' || cot->card_arr[i][0] == '\\') + continue; + if(check_matched_ranks(cot->card_arr[i], deck->str)) { + deck->is_usable = 1; + break; + } + } + deck = deck->next; + } +} + +int card_search_by_letter(player_cards deck, int letter) +{ + while(deck) { + if(deck->tip == letter && deck->is_usable) { + deck->is_usable = 0; + return 1; + } + deck = deck->next; + } + return 0; +} diff --git a/client/card_stack.h b/client/card_stack.h new file mode 100644 index 0000000..7cb5798 --- /dev/null +++ b/client/card_stack.h @@ -0,0 +1,29 @@ +#ifndef CARD_STACK_H_SENTRY +#define CARD_STACK_H_SENTRY + +struct card_stack_item { + char *str; + struct card_stack_item *next; + /* like a, b, c etc */ + unsigned char tip; + /* 1 - can be used, 0 - can't take it */ + int is_usable; +}; + +typedef struct card_stack_item* player_cards; + +void init_stack(player_cards *deck); +void push_stack(player_cards *deck, char *str); +void clear_stack(player_cards *deck); +int is_empty_stack(player_cards deck); +void add_hint_letters_stack(player_cards deck); +void mark_card_for_attackers_stack(player_cards deck); + +struct cards_on_table; +void mark_card_for_defenders_stack(player_cards deck, + struct cards_on_table *cot, + char* trump_suit); +void mark_card_for_tossing_stack(player_cards deck, struct cards_on_table *cot); +int card_search_by_letter(player_cards deck, int letter); + +#endif diff --git a/client/client.c b/client/client.c new file mode 100644 index 0000000..d932a51 --- /dev/null +++ b/client/client.c @@ -0,0 +1,245 @@ +#include +#include +#include +#include +#include +#include + +#include "client.h" +#include "data_decryption.h" +#include "printing_game_frames.h" +#include "verification_client_input.h" + +static const char *ip = "127.0.0.1"; +static const int port = 8082; + +static void get_data_from_server(struct client *cl, fd_set *readfds) +{ + int update_info = 0; + /* pointer to delimeter (:) that is behind extract data */ + char *end_p; + + if(FD_ISSET(cl->fd, readfds)) { + read(cl->fd, cl->buffer, max_buffer_size); + decrypt_set_state(cl, &end_p); + update_info = 1; + cl->display_new_frame = 1; + } + if(update_info) { + switch(cl->state) { + case first_player: + break; + case confirmation_waiting: + cl->total_players = decrypt_get_number(end_p+1, &end_p); + break; + case display_only_table: + case attack: + case defense: + case tossing_expectation: + case tossing: + /* last arg will contain pointer to '\n' */ + decrypt_set_base_info(cl, end_p+1, &end_p); + break; + case attack_expectation: + decrypt_set_base_info(cl, end_p+1, &end_p); + decrypt_set_position_whose_turn(cl, end_p+1, &end_p); + break; + case defense_expectation: + decrypt_set_base_info(cl, end_p+1, &end_p); + decrypt_set_position_whose_turn(cl, end_p+1, &end_p); + decrypt_set_card_queue(cl, end_p+1); + break; + case card_acceptance_status: + decrypt_set_card_acceptance_status(cl, cl->buffer); + break; + /* no data to extract */ + case tossing_limit_status: + default: + {} + } + } +} + +static void prepare_tips_for_client(struct client *cl) +{ + char *trump_suit = NULL; + + if(!is_empty_stack(cl->deck)) + add_hint_letters_stack(cl->deck); + + switch(cl->state) { + case attack: + mark_card_for_attackers_stack(cl->deck); + break; + case defense: + trump_suit = cl->trump_card + strlen(cl->trump_card) - 1; + mark_card_for_defenders_stack(cl->deck, &cl->cot, trump_suit); + break; + case tossing: + mark_card_for_tossing_stack(cl->deck, &cl->cot); + break; + default: + {} + } +} + +static void change_client_frame(struct client *cl) +{ + if(cl->display_new_frame) { + switch(cl->state) { + case first_player: + pgf_first_player(); + break; + case confirmation_waiting: + pgf_confirmation_waiting(cl->total_players); + break; + case display_only_table: + case attack_expectation: + case defense_expectation: + case tossing_expectation: + pgf_table(cl); + if(cl->state == attack_expectation || + cl->state == defense_expectation || + cl->state == tossing_expectation) + { + pgf_select_idle_mode_message(cl->state); + } + break; + case attack: + case defense: + case tossing: + pgf_table(cl); + pgf_suggestions(cl); + break; + case card_acceptance_status: + pgf_card_acceptance_status(cl->all_input_cards_accepted); + break; + case tossing_limit_status: + pgf_tossing_limit_status(); + break; + default: + {} + } + cl->display_new_frame = 0; + } +} + +static void send_data_to_server(struct client *cl, fd_set *readfds) +{ + int input_result; + + if(FD_ISSET(0, readfds)) { /* 0 - stdin */ + read(0, cl->buffer, max_buffer_size); + switch(cl->state) { + case confirmation_waiting: + input_result = vci_confirmation_waiting(cl->fd, cl->buffer); + break; + case attack: + case tossing: + input_result = vci_attack_or_tossing(cl->fd, cl->buffer, cl->deck, + cl->state); + break; + case defense: + input_result = vci_defense(cl->fd, cl->buffer, cl->deck); + break; + default: + {} + } + /* if 0, then re-tracking the input client */ + if(input_result) + cl->pending_server_response = 1; + } +} + +static int check_tracking_client_input(enum client_states state, + int pending_server_response) +{ + if(pending_server_response) + return 0; + + switch(state) { + case confirmation_waiting: + case attack: + case defense: + case tossing: + return 1; + default: + return 0; + } + return 0; +} + +int main_loop(struct client *cl) +{ + int select_result; + fd_set readfds; + + for(;;) { + FD_ZERO(&readfds); + + FD_SET(cl->fd, &readfds); + if(check_tracking_client_input(cl->state, cl->pending_server_response)) + FD_SET(0, &readfds); + + select_result = select(cl->fd + 1, &readfds, NULL, NULL, NULL); + if(select_result == -1) + return 2; + get_data_from_server(cl, &readfds); + prepare_tips_for_client(cl); + if(cl->display_new_frame) + change_client_frame(cl); + send_data_to_server(cl, &readfds); + } +} + +static void init_client(struct client *cl) +{ + cl->fd = -1; + cl->state = none; + cl->total_players = 0; + cl->total_cards_left = 0; + cl->player_position = 0; + cl->cc.number_arr = NULL; +#if 0 + cl->cc.number_arr_idx = -1; +#endif + cl->cot.card_arr_idx = -1; + cl->deck = NULL; + cl->pending_server_response = 0; + cl->cq.card_arr_idx = -1; + cl->position_whose_turn = 0; + cl->display_new_frame = 0; + cl->all_input_cards_accepted = 0; +} + +/* + * 0 - failure + * 1 - success + */ +static int connect_to_server(struct client *cl) +{ + int connect_result; + struct sockaddr_in addr; + + cl->fd = socket(AF_INET, SOCK_STREAM, 0); + if(cl->fd == -1) + return 0; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(ip); + addr.sin_port = htons(port); + + connect_result = connect(cl->fd, (struct sockaddr*) &addr, sizeof(addr)); + if(connect_result == -1) + return 0; + return 1; +} + +int main() +{ + struct client cl; + + init_client(&cl); + if(!connect_to_server(&cl)) + return 1; + return main_loop(&cl); +} diff --git a/client/client.h b/client/client.h new file mode 100644 index 0000000..f73cdce --- /dev/null +++ b/client/client.h @@ -0,0 +1,71 @@ +#ifndef CLIENT_H_SENTRY +#define CLIENT_H_SENTRY + +#include "card_stack.h" + +enum { + max_buffer_size = 4096, + max_cot_arr_size = 18, + card_size = 4, + max_cq_arr_size = 5 +}; + +enum client_states { + none, + first_player, + confirmation_waiting, + /* in game */ + display_only_table, + attack_expectation, + defense_expectation, + tossing_expectation, + attack, + defense, + tossing, + card_acceptance_status, + tossing_limit_status +}; + +struct cards_on_table { + /* + * example: 2^ \ - 10# \ K# + * [2 ^ '\0' ][1 0 # '\0'][\ '\0' ] + */ + char card_arr[max_cot_arr_size][card_size]; + /* index of the last filled element */ + int card_arr_idx; +}; + +struct card_queue { + char card_arr[max_cq_arr_size][card_size]; + int card_arr_idx; +}; + +struct card_count { + int *number_arr; + /* + * will only store the initial number of players + * (idx: total_players - 1 + */ + int number_arr_idx; +}; + +struct client { + int fd; + enum client_states state; + char buffer[max_buffer_size]; + int total_players; + int total_cards_left; + int player_position; + char trump_card[4]; + struct card_count cc; + struct cards_on_table cot; + player_cards deck; + int pending_server_response; + struct card_queue cq; + int position_whose_turn; + int display_new_frame; + int all_input_cards_accepted; +}; + +#endif diff --git a/client/data_decryption.c b/client/data_decryption.c new file mode 100644 index 0000000..2d10561 --- /dev/null +++ b/client/data_decryption.c @@ -0,0 +1,169 @@ +#include "data_decryption.h" +#include "client.h" +#include "card_stack.h" + +#include +#include + +void decrypt_set_state(struct client *cl, char **end_p) +{ + enum client_states found_state; + + found_state = (enum client_states) strtol(cl->buffer, end_p, 10); + cl->state = found_state; +} + +/* return convert number from str */ +int decrypt_get_number(char *start_p, char **end_p) +{ + return strtol(start_p, end_p, 10); +} + +static void decrypt_set_trump_card(struct client *cl, char *start_p, + char **end_p) +{ + int i; + + for(i = 0; *start_p != '\0'; ++start_p, ++i) + cl->trump_card[i] = *start_p; + cl->trump_card[i] = '\0'; + /* move to : */ + ++start_p; + *end_p = start_p; +} + +void decrypt_set_base_info(struct client *cl, char *start_p, char **end_p) +{ + int i, j; + char tmp_card[4]; + char *card = NULL; + + cl->total_players = decrypt_get_number(start_p, end_p); + cl->total_cards_left = decrypt_get_number(*end_p+1, end_p); + cl->player_position = decrypt_get_number(*end_p+1, end_p); + decrypt_set_trump_card(cl, *end_p+1, end_p); + + if(!cl->cc.number_arr) { + cl->cc.number_arr = malloc(cl->total_players * sizeof(int)); + /* + * memorize the size of the array, + * because later the number of players may change (client disconnection) + */ + cl->cc.number_arr_idx = cl->total_players-1; + } + + /* ============== extraction quantity of cards =============== */ + + /* numbers are separated by '\' */ + i = 0; + do { + cl->cc.number_arr[i] = decrypt_get_number(*end_p+1, end_p); + ++i; + } while(**end_p != ':'); + + /* ============== extraction cards on table =============== */ + i = 0, j = 0; + for(start_p = *end_p + 1; *start_p != ':'; ++start_p) { + /* empty table */ + if(*start_p == '0') { + /* to delimiter : */ + ++start_p; + i = -1; + break; + } + /* delimiter between cards on table */ + if(*start_p == '+') { + cl->cot.card_arr[i][j] = '\0'; + ++i; + j = 0; + continue; + } + cl->cot.card_arr[i][j] = *start_p; + ++j; + } + /* for the last card we need to add a null character */ + if(i != -1) + cl->cot.card_arr[i][j] = '\0'; + cl->cot.card_arr_idx = i; + + /* ================= extraction player's deck ================*/ + /* clear previous stack */ + if(cl->deck) + clear_stack(&cl->deck); + init_stack(&cl->deck); + + for(++start_p, i = 0; *start_p != ':' && *start_p != '\n'; ++start_p) { + /* empty deck */ + if(*start_p == '0') { + i = -1; + /* to delimiter ':' or '\n' */ + ++start_p; + break; + } + /* delimiter */ + if(*start_p == '\\') { + tmp_card[i] = '\0'; + card = malloc(strlen(tmp_card) + 1); + strcpy(card, tmp_card); + push_stack(&cl->deck, card); + i = 0; + } + tmp_card[i] = *start_p; + ++i; + } + if(i != -1) { + tmp_card[i] = '\0'; + card = malloc(strlen(tmp_card) + 1); + strcpy(card, tmp_card); + push_stack(&cl->deck, card); + } + *end_p = start_p; +} + +void decrypt_set_position_whose_turn(struct client *cl, char *start_p, + char **end_p) +{ + cl->position_whose_turn = decrypt_get_number(start_p, end_p); +} + +void decrypt_set_card_queue(struct client *cl, char *start_p) +{ + int i, j; + + for(i = 0, j = 0; *start_p != '\n'; ++start_p) { + /* empty queue */ + if(*start_p == '0') { + i = -1; + break; + } + /* delimiter '\' */ + if(*start_p == '\\') { + cl->cq.card_arr[i][j] = '\0'; + j = 0; + ++i; + continue; + } + cl->cq.card_arr[i][j] = *start_p; + ++j; + } + /* last element */ + if(i != -1) + cl->cq.card_arr[i][j] = '\0'; + cl->cq.card_arr_idx = i; +} + +void decrypt_set_card_acceptance_status(struct client *cl, char *start_p) +{ + int i; + char tmp_buffer[8]; + + for(i = 0; *start_p != '\n'; ++start_p, ++i) + tmp_buffer[i] = *start_p; + tmp_buffer[i] = '\0'; + if(!strcmp(tmp_buffer, "all")) { + cl->all_input_cards_accepted = 1; + return; + } + if(!strcmp(tmp_buffer, "not all")) + cl->all_input_cards_accepted = 0; +} diff --git a/client/data_decryption.h b/client/data_decryption.h new file mode 100644 index 0000000..b53e53f --- /dev/null +++ b/client/data_decryption.h @@ -0,0 +1,14 @@ +#ifndef DATA_DECRYPTION_H_SENTRY +#define DATA_DECRYPTION_H_SENTRY + +#include "client.h" + +void decrypt_set_state(struct client *cl, char **end_p); +int decrypt_get_number(char *start_p, char **end_p); +void decrypt_set_base_info(struct client *cl, char *start_p, char **end_p); +void decrypt_set_position_whose_turn(struct client *cl, char *start_p, + char **end_p); +void decrypt_set_card_queue(struct client *cl, char *start_p); +void decrypt_set_card_acceptance_status(struct client *cl, char *start_p); + +#endif diff --git a/client/printing_game_frames.c b/client/printing_game_frames.c new file mode 100644 index 0000000..38f1a78 --- /dev/null +++ b/client/printing_game_frames.c @@ -0,0 +1,104 @@ +#include "printing_game_frames.h" +#include "card_stack.h" + +#include + +void pgf_first_player() +{ + printf("=======================================" + " You're the first player" + "Waiting for other players to connect..." + "=======================================\n"); +} + +void pgf_confirmation_waiting(int total_players) +{ + printf("=======================================" + " To start game press key " + "Connected players: %u/8 " + "=======================================\n", total_players); +} + +void pgf_table(struct client *cl) +{ + struct card_stack_item *deck = NULL; + int i; + + for(i = 0; i < cl->cc.number_arr_idx; ++i) + /* printing who will move */ + if(cl->state == attack_expectation || cl->state == defense_expectation) + printf("<%c%u > ", cl->position_whose_turn-1 == i ? '*' : ' ', + cl->cc.number_arr[i]); + else + printf("< %u > ", cl->cc.number_arr[i]); + printf(" %s [ %u ]", cl->trump_card, cl->total_cards_left); + printf("\n\n\n"); + /* ================= cards on table ================ */ + for(i = 0; i <= cl->cot.card_arr_idx; i += 3) + printf(" %s %s %s\n", cl->cot.card_arr[i], cl->cot.card_arr[i+1], + cl->cot.card_arr[i+2]); + /* for the defender, the cards in the queue are hidden */ + if(cl->state == defense_expectation) + for(i = 0; i <= cl->cq.card_arr_idx; ++i) + printf(" %s \\ -\n", cl->cq.card_arr[i]); + printf("\n\n"); + /* ================ player's deck ================ */ + deck = cl->deck; + i = 0; + while(deck) { + printf("%c: %s ", deck->tip, deck->str); + ++i; + /* line break every 6 cards */ + if(!(i % 6)) + printf("\n"); + deck = deck->next; + } + printf("\n"); +} + +void pgf_suggestions(struct client *cl) +{ + struct card_stack_item *deck = NULL; + + if(cl->state == attack || cl->state == tossing) + printf("you can specify more than one card " + "(under certain conditions)\n"); + deck = cl->deck; + while(deck) { + if(deck->is_usable) + printf("%c", deck->tip); + deck = deck->next; + } + printf(" > "); +} + +void pgf_select_idle_mode_message(enum client_states state) +{ + switch(state) { + case attack_expectation: + printf("waiting for the attacker's turn\n"); + break; + case defense_expectation: + printf("waiting for the defender's turn\n"); + break; + case tossing_expectation: + printf("waiting for other players to toss cards\n"); + break; + default: + {} + } +} + +void pgf_card_acceptance_status(int all_input_cards_accepted) +{ + if(all_input_cards_accepted) + printf("all cards accepted\n"); + else + printf("not all cards were accepted\n"); +} + +void pgf_tossing_limit_status() +{ + printf("the cards were not accepted.\n" + "The other players have already tossed cards.\n"); +} diff --git a/client/printing_game_frames.h b/client/printing_game_frames.h new file mode 100644 index 0000000..e3c844a --- /dev/null +++ b/client/printing_game_frames.h @@ -0,0 +1,14 @@ +#ifndef PRINTING_GAME_FRAMES_H_SENTRY +#define PRINTING_GAME_FRAMES_H_SENTRY + +#include "client.h" + +void pgf_first_player(); +void pgf_confirmation_waiting(int total_players); +void pgf_table(struct client *cl); +void pgf_suggestions(struct client *cl); +void pgf_select_idle_mode_message(enum client_states state); +void pgf_card_acceptance_status(int all_input_cards_accepted); +void pgf_tossing_limit_status(); + +#endif diff --git a/client/verification_client_input.c b/client/verification_client_input.c new file mode 100644 index 0000000..2134f30 --- /dev/null +++ b/client/verification_client_input.c @@ -0,0 +1,46 @@ +#include "verification_client_input.h" + +#include +#include + +/* + * 1 - response received + * 0 - waiting for re-entry of data + */ +int vci_confirmation_waiting(int fd, char *buffer) +{ + if(buffer[0] == '\n') { + write(fd, buffer, 1); + return 1; + } + else + printf("please press enter\n"); + return 0; +} + +int vci_attack_or_tossing(int fd, char *buffer, player_cards deck, + enum client_states state) +{ + int i; + + if(state == tossing && buffer[0] == '\n') /* cancel card tossing */ + return 1; + + for(i = 0; buffer[i] != '\n'; ++i) + if(!card_search_by_letter(deck, buffer[i])) { + printf("incorrect input\n"); + return 0; + } + return 1; +} + +int vci_defense(int fd, char *buffer, player_cards deck) +{ + if(buffer[0] == '\n') /* the player does not want to keep the defense */ + return 1; + if(!card_search_by_letter(deck, buffer[0])) + return 0; + if(buffer[1] != '\n') + return 0; + return 1; +} diff --git a/client/verification_client_input.h b/client/verification_client_input.h new file mode 100644 index 0000000..690f36e --- /dev/null +++ b/client/verification_client_input.h @@ -0,0 +1,12 @@ +#ifndef VERIFICATION_CLIENT_INPUT_H_SENTRY +#define VERIFICATION_CLIENT_INPUT_H_SENTRY + +#include "card_stack.h" +#include "client.h" + +int vci_confirmation_waiting(int fd, char *buffer); +int vci_attack_or_tossing(int fd, char *buffer, player_cards deck, + enum client_states state); +int vci_defense(int fd, char *buffer, player_cards deck); + +#endif diff --git a/server.c b/server.c deleted file mode 100644 index 5153107..0000000 --- a/server.c +++ /dev/null @@ -1,733 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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; - 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->shuffled_deck_size, - &serv->sess_arr[i]->deck); - current_trump = find_lowest_trump(serv->sess_arr[i]->deck, - serv->trump_suit); - if(current_trump) - if(!lowest_trump || current_trump < lowest_trump) { - lowest_trump = current_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: - default: - 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; - default: - {} - } - - for(i = 0; i < serv->connected_players_counter; ++i) { - switch(state) { - case attack: - if(serv->turn_queue[i] && serv->turn_queue[i] != - serv->turn_queue[0]) - serv->turn_queue[i]->state = attack_expectation; - break; - case defense: - if(serv->turn_queue[i] && serv->turn_queue[i] != - serv->turn_queue[1]) - serv->turn_queue[i]->state = defense_expectation; - break; - case tossing: - if(serv->turn_queue[i] && serv->turn_queue[i] != - serv->turn_queue[1]) { - if(check_player_can_toss_card(serv->turn_queue[i]->deck, - serv->cot)) - { - serv->turn_queue[i]->tm = answer_wait; - serv->turn_queue[i]->state = tossing; - } else { - serv->turn_queue[i]->tm = none; - serv->turn_queue[i]->state = tossing_expectation; - } - } - break; - case display_only_table: - if(serv->turn_queue[i]) - serv->turn_queue[i]->state = display_only_table; - break; - default: - {} - } - } -} - -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_attack(struct server *serv) -{ - 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; - } 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->turn_queue[1]->defense_lost = 1; - serv->state = tossing_phase_out; - } -} - -static void define_phase_after_defense(struct server *serv) -{ - /* card wasn't beated */ - if(serv->cot->card_arr[serv->cot->card_arr_idx][0] == '-') { - 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 { - set_state_for_client(serv, display_only_table); - serv->state = table; - } - /* can defender continue defense? */ - } else { - if(is_empty_queue(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; - } - /* 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 */ -#if 0 - } 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; - } - } -#endif - } - } -} - -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 */ - set_state_for_client(serv, display_only_table); - serv->state = table; - } - 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; - } - } - /* defense continue? */ - } else { - if(is_empty_queue(serv->cq)) { - set_state_for_client(serv, display_only_table); - serv->state = table; - } else { - if(check_defender_can_defend(serv->cq, serv->turn_queue[1]->deck, - 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; - } - } - } - } -} - -static void determine_server_state(struct server *serv) -{ - 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: - 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: - case defense_phase_in: - case tossing_phase_in: - if(serv->state == attack_phase_in) - define_phase_after_attack(serv); - else if(serv->state == defense_phase_in) - define_phase_after_defense(serv); - else - /* 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_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) { - 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); - } - else { - remove_cards_from_table(serv->cot); - shift_turn_queue_by_one(serv->turn_queue, - serv->connected_players_counter); - } - set_record_status_for_all(serv); - set_state_for_client(serv, attack); - set_whose_turn(serv, attack); - update_card_quantity_arr(serv); - deal_cards(serv->shuffled_deck, &serv->shuffled_deck_size, - serv->turn_queue, serv->connected_players_counter, - serv->card_quantity_arr); - serv->state = attack_phase_out; - break; - case defense_phase_out: - serv->state = defense_phase_in; - break; - case tossing_phase_out: - serv->state = tossing_phase_in; - break; - } - 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; - 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->max_sess_arr_size; ++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; - case no_players: - {} - } - } -} - -static int check_server_state_change_conditions(int is_tossing_limit, - struct server *serv) -{ - switch(serv->state) { - case start_game: - case attack_phase_out: - case attack_phase_in: - case defense_phase_out: - case defense_phase_in: - case tossing_phase_out: - case table: - return 1; - case tossing_phase_in: - if(is_tossing_limit || - check_all_answers_were_received((const struct session**) - serv->turn_queue, - serv->connected_players_counter)) - return 1; - default: - return 0; - } - 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; - 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 start_game: - 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, - serv->trump_suit); - 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]->tm = cancel; - } - break; - case no_players: - {} - } - } - if(serv->state == start_game || serv->state == table) - sleep(2); - if(check_server_state_change_conditions(tossing_limit, serv)) - serv->change_server_state = 1; - /* connection is closed */ - if(!result) - close_connection(); -} - -int main_loop(struct server *serv) -{ - int 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->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: \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 deleted file mode 100644 index a97109f..0000000 --- a/server.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef SERVER_H_SENTRY -#define SERVER_H_SENTRY - -#include "card_queue.h" -#include "card_stack.h" - -enum { - max_buffer_size = 4096, - listen_qlen = 32, - init_sess_arr_size = 32 -}; - -enum { - max_shuffled_deck_size = 52, - max_card_arr_size = 18 -}; - -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; - enum server_states state; - int listen_socket; - struct session **sess_arr; - int max_sess_arr_size; - int connected_players_counter; - const char **shuffled_deck; - int shuffled_deck_size; - const char *trump_suit; - struct game_info *gi; - struct session **turn_queue; - int *card_quantity_arr; - int position_whose_turn; - struct card_queue *cq; - struct cards_on_table *cot; -}; - -#endif diff --git a/server/Makefile b/server/Makefile new file mode 100644 index 0000000..6fb2c5c --- /dev/null +++ b/server/Makefile @@ -0,0 +1,17 @@ +SRCMODULES = card_stack.c card_queue.c server_data_processing.c server_game_process.c server.c +OBJMODULES = $(SRCMODULES:.c=.o) +CC = gcc +CFLAGS = -Wall -g -c + +all: server + +%.o: %.с %.h + $(CC) $(CFLAGS) $< -o $@ + +server: $(OBJMODULES) + $(CC) $(LIBS) $^ -o $@ + +-include deps.mk + +deps.mk: $(SRCMODULES) + $(CC) -MM $^ > $@ diff --git a/server/card_queue.c b/server/card_queue.c new file mode 100644 index 0000000..194ea0c --- /dev/null +++ b/server/card_queue.c @@ -0,0 +1,61 @@ +#include "card_queue.h" + +#include + +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) { + cq->first = tmp; + cq->last = tmp; + } else { + cq->last->next = tmp; + cq->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; + struct card_queue_item *tmp = cq->first; + + while(tmp) { + ++counter; + tmp = tmp->next; + } + return counter; +} diff --git a/server/card_queue.h b/server/card_queue.h new file mode 100644 index 0000000..778ece4 --- /dev/null +++ b/server/card_queue.h @@ -0,0 +1,22 @@ +#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); +int is_empty_queue(struct card_queue *cq); +const char* pop_card_queue(struct card_queue *cq); + +#endif diff --git a/server/card_stack.c b/server/card_stack.c new file mode 100644 index 0000000..aa8af71 --- /dev/null +++ b/server/card_stack.c @@ -0,0 +1,79 @@ +#include "card_stack.h" + +#include +#include + +void init_stack(player_cards *deck) +{ + *deck = NULL; +} + +void push_stack(player_cards *deck, const 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(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/server/card_stack.h b/server/card_stack.h new file mode 100644 index 0000000..d380ded --- /dev/null +++ b/server/card_stack.h @@ -0,0 +1,21 @@ +#ifndef CARD_STACK_H_SENTRY +#define CARD_STACK_H_SENTRY + +struct card_stack_item { + const 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, const char *str); +int is_empty_stack(const player_cards deck); +int find_out_card_quantity_in_deck(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); + +#endif diff --git a/server/server.c b/server/server.c new file mode 100644 index 0000000..0a2bd0f --- /dev/null +++ b/server/server.c @@ -0,0 +1,759 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + 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_card = + extract_trump_card(serv->shuffled_deck, &serv->shuffled_deck_size); + serv->trump_suit = serv->trump_card + strlen(serv->trump_card) - 1; +#if 0 + serv->trump_suit = find_trump_suit(serv->shuffled_deck, + &serv->shuffled_deck_size); +#endif + serv->turn_queue = malloc(sizeof(struct session*) * + 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); + serv->position_whose_turn = 0; + serv->cot.card_arr_idx = -1; + /* + * 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->shuffled_deck_size, + &serv->sess_arr[i]->deck); + current_trump = find_lowest_trump(serv->sess_arr[i]->deck, + serv->trump_suit); + if(current_trump) + if(!lowest_trump || current_trump < lowest_trump) { + lowest_trump = current_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->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); +} + +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: + default: + 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; + default: + {} + } + + for(i = 0; i < serv->connected_players_counter; ++i) { + switch(state) { + case attack: + if(serv->turn_queue[i] && serv->turn_queue[i] != + serv->turn_queue[0]) + serv->turn_queue[i]->state = attack_expectation; + break; + case defense: + if(serv->turn_queue[i] && serv->turn_queue[i] != + serv->turn_queue[1]) + serv->turn_queue[i]->state = defense_expectation; + break; + case tossing: + if(serv->turn_queue[i] && serv->turn_queue[i] != + serv->turn_queue[1]) { + if(check_player_can_toss_card(serv->turn_queue[i]->deck, + &serv->cot)) + { + serv->turn_queue[i]->tm = answer_wait; + serv->turn_queue[i]->state = tossing; + } else { + serv->turn_queue[i]->tm = none; + serv->turn_queue[i]->state = tossing_expectation; + } + } + break; + case display_only_table: + if(serv->turn_queue[i]) + serv->turn_queue[i]->state = display_only_table; + break; + default: + {} + } + } +} + +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); +} +/* + * TODO refactoring + */ +static void define_phase_after_attack(struct server *serv) +{ + 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; + } 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 { + 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)) { + set_state_for_client(serv, display_only_table); + serv->state = table; + } else { + set_state_for_client(serv, tossing); + set_whose_turn(serv, tossing); + serv->state = tossing_phase_out; + } + + } +} + +static void define_phase_after_defense(struct server *serv) +{ + /* card wasn't beated */ + if(serv->cot.card_arr[serv->cot.card_arr_idx][0] == '-') { + serv->turn_queue[1]->defense_lost = 1; + put_all_cards_from_queue_to_table(&serv->cot, &serv->cq); + /* go to tossing cards */ + 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->cq, &serv->cot)) + { + set_state_for_client(serv, tossing); + set_whose_turn(serv, tossing); + serv->state = tossing_phase_out; + /* then begin new attack */ + } else { + set_state_for_client(serv, display_only_table); + serv->state = table; + } + /* can defender continue defense? */ + } else { + /* the defender has beaten the attack or tossing phase completely */ + if(is_empty_queue(&serv->cq)) { + 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->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; + } + /* 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 */ +#if 0 + } 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; + } + } +#endif + } + } +} + +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 */ + set_state_for_client(serv, display_only_table); + serv->state = table; + } + 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) && + 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; + } + } + /* defense continue? */ + } else { + if(is_empty_queue(&serv->cq)) { + set_state_for_client(serv, display_only_table); + serv->state = table; + } else { + if(check_defender_can_defend(&serv->cq, serv->turn_queue[1]->deck, + 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(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->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; + } + } + } + } +} + +static void determine_server_state(struct server *serv) +{ + 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: + 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: + case defense_phase_in: + case tossing_phase_in: + if(serv->state == attack_phase_in) + define_phase_after_attack(serv); + else if(serv->state == defense_phase_in) + define_phase_after_defense(serv); + else + /* 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_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) { + 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); + } + else { + remove_cards_from_table(&serv->cot); + shift_turn_queue_by_one(serv->turn_queue, + serv->connected_players_counter); + } + set_record_status_for_all(serv); + set_state_for_client(serv, attack); + set_whose_turn(serv, attack); + 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); + serv->state = attack_phase_out; + break; + case defense_phase_out: + serv->state = defense_phase_in; + break; + case tossing_phase_out: + serv->state = tossing_phase_in; + break; + } + 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; + 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->max_sess_arr_size; ++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; + case no_players: + {} + } + } +} + +static int check_server_state_change_conditions(int is_tossing_limit, + struct server *serv) +{ + switch(serv->state) { + case start_game: + case attack_phase_out: + case attack_phase_in: + case defense_phase_out: + case defense_phase_in: + case tossing_phase_out: + case table: + return 1; + case tossing_phase_in: + if(is_tossing_limit || + check_all_answers_were_received((const struct session**) + serv->turn_queue, + serv->connected_players_counter)) + return 1; + default: + return 0; + } + 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; + 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 start_game: + 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->cot, + serv->turn_queue[1]->deck, + &serv->cq); + break; + case defense_phase_in: + if(FD_ISSET(i, readfds)) + result = get_card_from_defender(serv->sess_arr[i], &serv->cot, + serv->trump_suit); + 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]->tm = cancel; + } + break; + case no_players: + {} + } + } + if(serv->state == start_game || serv->state == table) + sleep(2); + if(check_server_state_change_conditions(tossing_limit, serv)) + serv->change_server_state = 1; + /* connection is closed */ + if(!result) + close_connection(); +} + +int main_loop(struct server *serv) +{ + int maxfd, accept_result, select_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_result = select(maxfd + 1, &readfds, &writefds, NULL, NULL); + if(select_result == -1) + return 3; + + 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->shuffled_deck = NULL; + serv->shuffled_deck_size = max_shuffled_deck_size; + serv->gi = NULL; + serv->cc.number_arr = 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: \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 new file mode 100644 index 0000000..46c965b --- /dev/null +++ b/server/server.h @@ -0,0 +1,99 @@ +#ifndef SERVER_H_SENTRY +#define SERVER_H_SENTRY + +#include "card_queue.h" +#include "card_stack.h" + +enum { + max_buffer_size = 4096, + listen_qlen = 32, + init_sess_arr_size = 32 +}; + +enum { + max_shuffled_deck_size = 52, + max_card_arr_size = 18 +}; + +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 { + /* in game */ + display_only_table = 3, + attack_expectation, + defense_expectation, + tossing_expectation, + attack, + defense, + tossing, + card_acceptance_status, + tossing_limit_status +}; + +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 card_count { + int *number_arr; + /* will only store the initial number of players (idx) */ + int number_arr_idx; +}; + +struct server { + int change_server_state; + enum server_states state; + int listen_socket; + struct session **sess_arr; + int max_sess_arr_size; + int connected_players_counter; + /* TODO: make static allocation memory */ + const char **shuffled_deck; + int shuffled_deck_size; + const char *trump_suit; + const char *trump_card; + struct game_info *gi; + struct session **turn_queue; + struct card_count cc; + int position_whose_turn; + struct card_queue cq; + struct cards_on_table cot; +}; + +#endif diff --git a/server/server_data_processing.c b/server/server_data_processing.c new file mode 100644 index 0000000..30953bf --- /dev/null +++ b/server/server_data_processing.c @@ -0,0 +1,337 @@ +#include "server_data_processing.h" +#include "server.h" + +#include +#include +#include +#include + +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; + return read_result; +} + +int print_message_for_first_player(int fd) +{ + int data_size; + + data_size = sprintf(output_buffer, "%u\n", first_player); + return write_to_client(fd, data_size); +} + +int print_connected_players(int fd, int number) +{ + int data_size; + + data_size = sprintf(output_buffer, "%u:%u\n", confirmation_waiting, number); + return write_to_client(fd, data_size); +} + +/* + * 1 - ready + * 0 - buffer overflow or player closed session + * -1 - not ready + */ +int check_readiness(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; +} +/* + * example: 10#\A^\7v'\n' + * or 0'\n' + */ +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]; + /* delimiter */ + *(output_buffer + *offset) = '\\'; + ++*offset; + } + *(output_buffer + *offset-1) = ':'; +} + +/* + * example: 10#+\+Q#+A^+\+-+7v: + * or 0: + */ +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]; + /* delimiter */ + *(output_buffer + *offset) = '+'; + ++*offset; + } + *(output_buffer + *offset-1) = ':'; +} +/* + * example: 10#\A^\7v: + * or 10#\A^\7v'\n' + * or 0: + * or 0'\n' + */ +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) = '\\'; + ++*offset; + deck = deck->next; + } + *(output_buffer + *offset-1) = ':'; +} + +static void copy_base_info(int *free_pos, struct game_info *gi, + enum client_game_states state, player_cards deck, + int player_position) +{ + int i; + + *free_pos = + sprintf(output_buffer, "%u:%u:%u:%u:%s:", state, gi->players_number, + gi->shuffled_cards_left, player_position, gi->trump_card); + /* + * opponent's card count + * example: 2\6\3: + */ + for(i = 0; i < gi->players_number; ++i) { + + *free_pos += sprintf(output_buffer + *free_pos, "%u\\", + gi->card_quantity_arr[i]); + } + *(output_buffer + *free_pos-1) = ':'; + + if(gi->cot->card_arr_idx != -1) + copy_cards_on_table(free_pos, *gi->cot); + else + *free_pos += sprintf(output_buffer + *free_pos, "0:"); + + if(!is_empty_stack(deck)) + copy_own_deck(free_pos, deck); + else + *free_pos += sprintf(output_buffer + *free_pos, "0:"); +} + +int print_game_part(const struct session *client, struct game_info *gi) +{ + int free_pos; /* free_pos == data length */ + + copy_base_info(&free_pos, gi, client->state, client->deck, + client->player_position); + + switch(client->state) { + case display_only_table: + /* let the client print card tips and wait for input */ + case attack: + case defense: + /* + * who haven't got tossing card (including defender) must wait + * when other players make moves + */ + case tossing_expectation: + case tossing: + /* instead of last ':' */ + *(output_buffer + free_pos-1) = '\n'; + break; + /* other clents will be waiting particular player */ + case attack_expectation: + free_pos += sprintf(output_buffer + free_pos, "%u:", + gi->position_whose_turn); + *(output_buffer + free_pos-1) = '\n'; + break; + case defense_expectation: + /* copying whose turn */ + free_pos += sprintf(output_buffer + free_pos, "%u:", + gi->position_whose_turn); + /* copying card queue */ + if(is_empty_queue(gi->cq)) + free_pos += sprintf(output_buffer + free_pos, "0:"); + else + copy_card_queue(&free_pos, gi->cq); + *(output_buffer + free_pos-1) = '\n'; + default: + {} + } + return write_to_client(client->fd, free_pos); +} +#if 0 +static int is_receiving_cards_limit(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; +} +#endif + +int get_cards_from_attacker(struct session *client, + const struct cards_on_table *cot, + const player_cards defense_deck, + struct card_queue *cq) +{ + int read_result, i, j; + 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; + for(i = 0, j = 0; i < read_result && client->buffer[i] != '\n'; ++i) { + if(client->buffer[i] == '\\') { + given_card[j] = '\0'; + j = 0; + if(card_return_status) { + all_cards_received_status = 0; + break; + } + stack_card = remove_card_from_stack(&client->deck, given_card); + push_queue(cq, stack_card); + if(is_receiving_cards_limit(cot, defense_deck, cq)) + card_return_status = 1; + continue; + } + given_card[j] = client->buffer[i]; + ++j; + } + 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); + return read_result; +} + +/* + * 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, + const char * trump_suit) +{ + 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[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; + } else + 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 + * + * example: 10#\A^\7v\'\n' + */ +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; + 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; + + for(i = 0, j = 0; i < read_result; ++i) { + if(client->buffer[i] == '\\') { + /* cancellation */ + if(given_card[0] == '\n') + return 3; + /* tossing limit was set */ + if(client->tm == cancel) { + /* it's impossible to accept cards due to tossing limit */ + data_length = + sprintf(output_buffer, "%d\n", tossing_limit_status); + 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); + if(is_receiving_cards_limit(cot, defense_deck, cq)) + { + card_return_status = 1; + } + } + continue; + } + given_card[j] = client->buffer[i]; + ++j; + } + /* 7 -- state for result of received cards */ + 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) + return 1; + else + return 2; +} diff --git a/server/server_data_processing.h b/server/server_data_processing.h new file mode 100644 index 0000000..875fd98 --- /dev/null +++ b/server/server_data_processing.h @@ -0,0 +1,21 @@ +#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(struct session *client); +int print_game_part(const struct session *client, struct game_info *gi); +int get_cards_from_attacker(struct session *client, + const struct cards_on_table *cot, + const player_cards defense_deck, + struct card_queue *cq); +int get_card_from_defender(struct session *client, struct cards_on_table *cot, + const char *trump_suit); +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/server_game_process.c b/server/server_game_process.c new file mode 100644 index 0000000..8bf4e60 --- /dev/null +++ b/server/server_game_process.c @@ -0,0 +1,475 @@ +#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 players_number, + int *card_quantity_arr) +{ + int i, j, key, player_deck_size, card_shortage_quantity, last_idx; + const char *extracted_card = NULL; + + for(i = 0; i < players_number; ++i) { + key = turn_queue[i]->player_position - 1; + player_deck_size = card_quantity_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 || 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[0] ? shuffled_deck[0] : NULL; + if(trump_card) { + shuffled_deck[0] = NULL; + --*cards_left; + } + return trump_card; +} +#if 0 +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; +} +#endif + +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; +} + +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 move_turn_queue_two_players_ahead(struct session **turn_queue, int size) +{ + int i; + + for(i = 0; i < 2; ++i) + shift_turn_queue_by_one(turn_queue, size); +} + +void update_card_quantity_arr(struct server *serv) +{ + int i, player_position_idx; + + for(i = 0; i < serv->max_sess_arr_size; ++i) + if(serv->sess_arr[i]) { + player_position_idx = serv->sess_arr[i]->player_position - 1; + serv->cc.number_arr[player_position_idx] = + find_out_card_quantity_in_deck(serv->sess_arr[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; +} +/* + * 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 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][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; +#if 0 + const char *card; + + 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[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 size) +{ + int i; + + for(i = 0; i < 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; +} diff --git a/server/server_game_process.h b/server/server_game_process.h new file mode 100644 index 0000000..8891a56 --- /dev/null +++ b/server/server_game_process.h @@ -0,0 +1,78 @@ +#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 +}; + +struct game_info { + int players_number; + int *card_quantity_arr; + int shuffled_cards_left; + const char* trump_card; + int position_whose_turn; + struct cards_on_table *cot; + struct card_queue *cq; +}; + +const char** get_shuffled_deck(); +void deal_first_cards(const char **shuffled_deck, int *cards_left, + player_cards *deck); +void deal_cards(const char **shuffled_deck, int *shuffled_cards_left, + struct session **turn_queue, int players_number, + int *card_quantity_arr); +const char* extract_trump_card(const char **shuffled_deck, int *cards_left); +#if 0 +const char* find_trump_suit(const char **shuffled_deck, int *cards_left); +#endif +int find_lowest_trump(player_cards deck, const char *trump); +void shift_turn_queue_by_one(struct session **turn_queue, int size); +void move_turn_queue_two_players_ahead(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, + const char *trump_card, + int position_whose_turn, + 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 check_defender_can_defend(struct card_queue *cq, 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, + struct cards_on_table *cot); + +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, 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 struct session **turn_queue, + int size); +int is_receiving_cards_limit(const struct cards_on_table *cot, + player_cards defense_deck, + const struct card_queue *cq); +#endif diff --git a/server_data_processing.c b/server_data_processing.c deleted file mode 100644 index 5c78f78..0000000 --- a/server_data_processing.c +++ /dev/null @@ -1,294 +0,0 @@ -#include "server_data_processing.h" -#include "server.h" - -#include -#include -#include -#include - -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; - return read_result; -} - -int print_message_for_first_player(int fd) -{ - 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(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, - enum client_game_states state, player_cards deck, - int player_position) -{ - int i; - - *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; /* free_pos == data length */ - - copy_base_info(&free_pos, gi, client->state, client->deck, - client->player_position); - - switch(client->state) { - case display_only_table: - /* let the client print card tips and wait for input */ - case attack: - case defense: - /* - * who haven't got tossing card (including defender) must wait - * when other players make moves - */ - case tossing_expectation: - case tossing: - /* instead of last ':' */ - *(output_buffer + free_pos-1) = '\n'; - break; - /* other clents will be waiting particular player */ - case attack_expectation: - free_pos += sprintf(output_buffer + free_pos, "%u:", - gi->position_whose_turn); - *(output_buffer + free_pos-1) = '\n'; - break; - case defense_expectation: - 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'; - } - 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(client->buffer[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; - } - return read_result; -} - -/* - * 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, - const char * trump_suit) -{ - 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[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; - } 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(client->buffer[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] = client->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 deleted file mode 100644 index 9ebe5ad..0000000 --- a/server_data_processing.h +++ /dev/null @@ -1,18 +0,0 @@ -#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(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, - const char *trump_suit); -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 deleted file mode 100644 index 99b50fe..0000000 --- a/server_game_process.c +++ /dev/null @@ -1,440 +0,0 @@ -#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 players_number, - int *card_quantity_arr) -{ - int i, j, key, player_deck_size, card_shortage_quantity, last_idx; - const char *extracted_card = NULL; - - for(i = 0; i < players_number; ++i) { - key = turn_queue[i]->player_position - 1; - player_deck_size = card_quantity_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 || 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* 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; - 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; -} - -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 move_turn_queue_two_players_ahead(struct session **turn_queue, int size) -{ - int i; - - for(i = 0; i < 2; ++i) - shift_turn_queue_by_one(turn_queue, size); -} - -void update_card_quantity_arr(struct server *serv) -{ - int i, player_position_idx; - - for(i = 0; i < serv->max_sess_arr_size; ++i) - if(serv->sess_arr[i]) { - player_position_idx = serv->sess_arr[i]->player_position - 1; - serv->card_quantity_arr[player_position_idx] = - find_out_card_quantity_in_deck(serv->sess_arr[i]->deck); - } -} - -struct game_info* get_new_game_info(int players_number, int *card_quantity_arr, - int shuffled_cards_left, - const char *trump_suit, - 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_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; - 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 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][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; -} - -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; -#if 0 - const char *card; - - 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[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 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 deleted file mode 100644 index 5cddc27..0000000 --- a/server_game_process.h +++ /dev/null @@ -1,73 +0,0 @@ -#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 -}; - -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; -}; - -const char** get_shuffled_deck(); -void deal_first_cards(const char **shuffled_deck, int *cards_left, - player_cards *deck); -void deal_cards(const char **shuffled_deck, int *shuffled_cards_left, - struct session **turn_queue, int players_number, - int *card_quantity_arr); -const char* find_trump_suit(const char **shuffled_deck, int *cards_left); -int find_lowest_trump(player_cards deck, const char *trump); -void shift_turn_queue_by_one(struct session **turn_queue, int size); -void move_turn_queue_two_players_ahead(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, - const char *trump_suit, - int position_whose_turn, - 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 check_defender_can_defend(struct card_queue *cq, 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, - struct cards_on_table *cot); - -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, 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 struct session **turn_queue, - int size); - -#endif -- cgit v1.2.3