diff --git a/http-parser.c b/http-parser.c index 6afa3d4f06163f400f04c4f990eedb5944ae227e..a5a5a27e83f58a38fe73c91a9e568c9d37fb8416 100644 --- a/http-parser.c +++ b/http-parser.c @@ -1,3 +1,7 @@ +/** + * Written by Abhisha Nirmalathas 913405 for COMP30023 Project 1 + * This program deals with the parsing of http requests + * */ #include <errno.h> #include <stdbool.h> #include <stdio.h> @@ -6,15 +10,21 @@ #include <assert.h> #include "http-parser.h" +// user-determined constants for requests #define MAX_URL_SIZE 60 #define MAX_HEADER_SIZE 600 #define MAX_VERSION_SIZE 10 +#define MAX_HEADERS 10 Request* parse_request(char* request_message){ + /** + * Reads a requests and creates a request object containing the parsed information + * */ Request *req = calloc(1, sizeof(Request)); assert(req); memset(req, 0, sizeof(Request)); - int n_headers = 10; + + // parses the method of the request if (strncmp(request_message, "GET ", 4) == 0){ req->method = GET; request_message += 4; @@ -25,11 +35,17 @@ Request* parse_request(char* request_message){ req->method = POST; // printf("Its a post\n"); } + + //parses the url req->url = strtok(request_message, " "); request_message += strlen(req->url)+1; + + //parses the version req->version = strtok(request_message, "\r\n"); request_message+= strlen(req->version)+2; - req->header = new_hash_table(10); + + //parses the headers + req->header = new_hash_table(MAX_HEADERS); char header_field_name[MAX_HEADER_SIZE]; char header_value[MAX_HEADER_SIZE]; @@ -44,6 +60,8 @@ Request* parse_request(char* request_message){ hash_table_put(req->header, header_field_name, header_value); } request_message += strcspn(request_message, "\r\n")+2; + + // parses the body if(*request_message != '\r'||*request_message != '\n'){ req->body = request_message; } @@ -54,6 +72,9 @@ Request* parse_request(char* request_message){ } void free_request(Request* req){ - free_hash_table(req->header); + /** + * Deallocates memory + * */ + free_hash_table(req->header); free(req); } diff --git a/http-parser.h b/http-parser.h index 501f33206e16e4d32bfdb074f26724f0207e64c2..203079e02a40928617fcebe05b6c2d1f8dbfadfd 100644 --- a/http-parser.h +++ b/http-parser.h @@ -1,5 +1,11 @@ +/** + * Written by Abhisha Nirmalathas 913405 for COMP30023 Project 1 + * This program deals with the parsing of http requests + * */ #include <stdbool.h> #include "hashtable.h" + +// Supported HTTP Request Methods typedef enum { GET, @@ -7,6 +13,7 @@ typedef enum UNKNOWN } METHOD; +// HTTP request structure typedef struct Request { METHOD method; char *url; @@ -16,7 +23,8 @@ typedef struct Request { } Request; -//Creates a new hash table of input size +// Parses the request and stores request information Request* parse_request(char* request_message); +// Deallocates memory void free_request(Request* req); \ No newline at end of file diff --git a/http-response.c b/http-response.c index fa2a0e07ca661ff990cd80d98ee5c2cb24eb8aa7..626b5d95ee0c02f51e5055ec4daacbd8937f5868 100644 --- a/http-response.c +++ b/http-response.c @@ -1,3 +1,7 @@ +/** + * Written by Abhisha Nirmalathas 913405 for COMP30023 Project 1 + * This program deals with all HTTP responses sent. + * */ #include <errno.h> #include <stdbool.h> #include <stdio.h> @@ -8,11 +12,16 @@ #include "http-parser.h" #include "http-response.h" +// constants for responses #define MAX_URL_SIZE 60 #define MAX_HEADER_SIZE 300 #define MAX_VERSION_SIZE 10 +#define MAX_N_HEADERS 2 char* cookie_generator(){ + /** + * Creates a cookie token and formats it accordingly to HTTP + * */ char* cookie_value; cookie_value = (char*) malloc(sizeof(char)*60); snprintf(cookie_value, 60, "sessionToken=%d; Expires=Wed, 01 Apr 2019 10:10:10 GMT", rand()); @@ -21,19 +30,31 @@ char* cookie_generator(){ Response* initialise_session(Request* request){ + /** + * Creates a new browser session for a user, where a cookie is created + * */ Response *resp = calloc(1, sizeof *resp); assert(resp); + + // Sets the HTTP Response status code to a 200 OK resp->status_code=200; resp->version = request->version; resp->phrase = "OK"; - resp->header = new_hash_table(2); + resp->header = new_hash_table(MAX_N_HEADERS); + + // sets the cookies char *cookie = cookie_generator(); hash_table_put(resp->header, "Set-cookie: ", cookie); + + // sends empty body resp->body=""; return resp; } char* parse_response(Response* response){ + /** + * Parses a response and returns it as a string + * */ char* response_string; char int_buff[4]; response_string = calloc(100,sizeof(char)); @@ -54,6 +75,9 @@ char* parse_response(Response* response){ void free_response(Response* resp){ + /** + * Deallocates response memory + * */ free_cookie(resp->header); free_hash_table(resp->header); free(resp); diff --git a/http-response.h b/http-response.h index 63fdbb30275c61b0dbfcaefcf29aa904e91c43a3..31bef7400c67adf953643d098ceffb83ee05079a 100644 --- a/http-response.h +++ b/http-response.h @@ -1,6 +1,11 @@ +/** + * Written by Abhisha Nirmalathas 913405 for COMP30023 Project 1 + * This program deals with all HTTP responses sent. + * */ #include <stdbool.h> #include "hashtable.h" +// Response message sent over HTTP typedef struct Response { int status_code; char *version; @@ -9,14 +14,14 @@ typedef struct Response { char *body; } Response; - -//Creates a new hash table of input size -Response *redirect(Request *req, char* url_string); - +// Parses a response object as a string char* parse_response(Response* response); +// Creates a cookie char* cookie_generator(); +// Deallocates memory from Response struct void free_response(Response* resp); +// Creates a cookie for a new user Response* initialise_session(Request* request); diff --git a/http-server.c b/http-server.c index c91fb1ebc3cf1c82b8c69f8c3094cac103e2acde..8aba4032cfae966afecc0daee55b6f166316e22e 100644 --- a/http-server.c +++ b/http-server.c @@ -1,8 +1,11 @@ -/* -** http-server.c -*/ +/*** + * Written originally by COMP30023 for lab 6 but modified by Abhisha Nirmalathas 913405 for Project 1 + * Builds a http server, using a persistent TCP connection to create an image tagging game. + * + * */ #include <errno.h> +#include <unistd.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -37,24 +40,23 @@ static int const HTTP_400_LENGTH = 47; static char const * const HTTP_404 = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n"; static int const HTTP_404_LENGTH = 45; -static int keep_alive = 1; +int keep_alive = 1; bool player_session(char* buff, int sockfd, char* file_name, char* response){ - // get the size of the file - // printf("runnning player session functin\n"); + /** + * Sends response which creates a cookie for user + * */ struct stat st; stat(file_name, &st); int n = sprintf(buff, response, st.st_size); // send the header first - // printf("sending header\n"); if (write(sockfd, buff, n) < 0) { perror("write"); return false; } // send the file - // printf("sending file\n"); int filefd = open(file_name, O_RDONLY); do { @@ -67,11 +69,13 @@ bool player_session(char* buff, int sockfd, char* file_name, char* response){ close(filefd); return false; } - // printf("about to close"); close(filefd); return true; } -bool text_render_request(char *buff, int sockfd, char* file_name, char* text){ +bool text_render_response(char *buff, int sockfd, char* file_name, char* text){ + /** + * Sends a response which adds text to the html webpage + * */ char *user_name = calloc(200,sizeof(char)); assert(user_name); strcpy(user_name, text); @@ -88,6 +92,7 @@ bool text_render_request(char *buff, int sockfd, char* file_name, char* text){ // read the content of the HTML file int filefd = open(file_name, O_RDONLY); n = read(filefd, buff, size); + // adds text to the response html render_text(buff, user_name); clean_trailing_buffer(buff); if (n < 0) @@ -97,7 +102,6 @@ bool text_render_request(char *buff, int sockfd, char* file_name, char* text){ return false; } close(filefd); - // move the trailing part backward free(user_name); if (write(sockfd, buff, size) < 0) { @@ -107,7 +111,10 @@ bool text_render_request(char *buff, int sockfd, char* file_name, char* text){ return true; } -bool request(char *buff, int sockfd, char* file_name){ +bool response(char *buff, int sockfd, char* file_name){ + /** + * Sends a response with the given webpage + * */ struct stat st; stat(file_name, &st); int n = sprintf(buff, HTTP_200_FORMAT, st.st_size); @@ -137,6 +144,10 @@ bool request(char *buff, int sockfd, char* file_name){ } bool game_change(char* buff, int sockfd, char* file_name, int round){ + /** + * Sends a response with the given webpage, ensuring that the right game image is rendered + * depending on users current round + * */ struct stat st; stat(file_name, &st); int n = sprintf(buff, HTTP_200_FORMAT, st.st_size); @@ -149,9 +160,9 @@ bool game_change(char* buff, int sockfd, char* file_name, int round){ // read the content of the HTML file int filefd = open(file_name, O_RDONLY); n = read(filefd, buff, st.st_size); + // changes the image of response html change_game_image(buff, round); clean_trailing_buffer(buff); - // printf("the buffer is game change is \n%s\n", buff); if (n < 0) { perror("read"); @@ -167,6 +178,10 @@ bool game_change(char* buff, int sockfd, char* file_name, int round){ return true; } bool text_render_game_play(char *buff, int sockfd, char* file_name, char* text, int round){ + /** + * Sends a response with the given webpage, ensuring that the right game image is rendered + * depending on users current round, whilst rendering some text on game page + * */ char *user_name = calloc(200,sizeof(char)); assert(user_name); strcpy(user_name, text); @@ -183,7 +198,9 @@ bool text_render_game_play(char *buff, int sockfd, char* file_name, char* text, // read the content of the HTML file int filefd = open(file_name, O_RDONLY); n = read(filefd, buff, size); + // change image to match current round change_game_image(buff, round); + // add the text to response html render_text(buff, user_name); clean_trailing_buffer(buff); if (n < 0) @@ -203,10 +220,10 @@ bool text_render_game_play(char *buff, int sockfd, char* file_name, char* text, return true; } -static bool handle_http_request(int sockfd, User_list *users) -{ - // try to read the request - // printf("THE NUMBER OF USERS IS (in http req) %d\n", users->n_users); +static bool handle_http_request(int sockfd, User_list *users){ + /** + * Parses the http request and sends the approapriate response + * */ char buff[2049]; memset(buff, '\0', 2049); int n = read(sockfd, buff, 2049); @@ -226,16 +243,21 @@ static bool handle_http_request(int sockfd, User_list *users) // parse the method Request* req = parse_request(curr); User* user = get_current_user(users, sockfd); - printf("REQUEST BODY IS \n\n%s\n", req->url); + // printf("REQUEST BODY IS \n\n%s\n", req->url); + + // user should quit game if(strncmp(req->body, "quit=Quit", 9) == 0){ printf("run\n\n\n\n\\n"); change_player_status(sockfd,users, QUIT); - request(buff,sockfd, "7_gameover.html"); + response(buff,sockfd, "7_gameover.html"); // free_request(req); // return false; } + + // user starting game else if (strncmp(req->url, "/?start=Start", 24) == 0){ - // printf("matches start"); + + // user on first turn if (req->method == GET){ change_player_status(sockfd, users, READY); int round = change_player_round(sockfd, users); @@ -243,32 +265,43 @@ static bool handle_http_request(int sockfd, User_list *users) } if (req->method == POST){ if(strncmp(req->body, "keyword=", 8) == 0){ + + // checks if other player has quit if(should_player_quit(users)){ printf("is quit"); change_player_status(sockfd,users, QUIT); - request(buff,sockfd, "7_gameover.html"); + response(buff,sockfd, "7_gameover.html"); // free_request(req); // keep_alive = 0; // return false; } + + // checks if other player has not completed previous round else if (different_round_discard(sockfd,users)){ game_change(buff,sockfd, "5_discarded.html", user->round); } + + // checks if game won else if(player_won(users)){ - request(buff,sockfd, "6_endgame.html"); + response(buff,sockfd, "6_endgame.html"); change_player_status(sockfd, users, WAIT); } + + //checks if the other player is not ready and discards keyword else if(!players_ready(users) && user!= NULL){ game_change(buff,sockfd, "5_discarded.html", user->round); //request(buff,sockfd, "5_discarded.html"); } else{ char* keyword = add_keyword(sockfd, users, req->body); + + // game ends as submitted keyword has been submitted by other player if(has_match_ended(users, keyword, sockfd)){ - request(buff,sockfd, "6_endgame.html"); + response(buff,sockfd, "6_endgame.html"); change_all_status(users, COMPLETE); } else{ + // keyword hasn't been submitted yet so is accepted and rendered on screen if(user!= NULL){ char* keywords = return_all_keywords(user); text_render_game_play(buff,sockfd, "4_accepted.html", keywords, user->round); @@ -279,7 +312,11 @@ static bool handle_http_request(int sockfd, User_list *users) } } } + + // game start screen else if (*req->url == '/' && (strlen(req->url) == 1)){ + + // user's name stored and rendered on screen if (req->method == POST) { char *name = strchr(req->body, '=')+1; @@ -291,9 +328,11 @@ static bool handle_http_request(int sockfd, User_list *users) } } // get_request(buff,sockfd, "2_start.html"); - text_render_request(buff,sockfd, "2_start.html", req->body+5); + text_render_response(buff,sockfd, "2_start.html", req->body+5); } } + + // user is created else if (req->method == GET) { // printf("matches a / url but url isize is %zu\n\n", strlen(req->url)); @@ -308,6 +347,8 @@ static bool handle_http_request(int sockfd, User_list *users) // printf("the cookie token is %s*****\n", cookie); // free(resp_string); // free_response(resp); + + // ensures user is not already playing/in system for(int i =0; i< users->n_users; i++){ if(sockfd == users->users[i]->id){ return false; @@ -315,10 +356,10 @@ static bool handle_http_request(int sockfd, User_list *users) } User* new_player = new_user(sockfd); add_user(new_player, users); - request(buff,sockfd, "1_welcome.html"); + response(buff,sockfd, "1_welcome.html"); } else - // never used, just for completeness + // unrecognised methods fprintf(stderr, "no other methods supported"); } // send 404 @@ -351,14 +392,16 @@ static bool handle_http_request(int sockfd, User_list *users) return true; } -void exit_handler(); - -void exit_handler(){ - printf("break loop"); +static void exit_handler(int sig){ + /** + * Closes TCP Connection + */ keep_alive = 0; + printf("keep alive changed"); } + int main(int argc, char * argv[]) { if (argc < 3) @@ -406,6 +449,8 @@ int main(int argc, char * argv[]) FD_SET(sockfd, &masterfds); // record the maximum socket number int maxfd = sockfd; + + // game players User_list* users = initialise_player_list(); signal(SIGINT, exit_handler); while (keep_alive) @@ -457,6 +502,7 @@ int main(int argc, char * argv[]) } } } + printf("break loop"); free_users(users); return 0; } diff --git a/response-formatter.c b/response-formatter.c index 4bf477a937ac0bf0e4e0b2777c6f938ab838cac3..fec2dfec7ad74cada76f311e9cabab223e28e1f5 100644 --- a/response-formatter.c +++ b/response-formatter.c @@ -1,3 +1,10 @@ +/** + * Written by Abhisha Nirmalathas 913405 for COMP30023 Project 1 + * This program deals with all html manipulation, including insertion, cleaning and + * dynamic images for each round. + * */ + + #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -6,47 +13,62 @@ #include "response-formatter.h" +//constants which define the image src for each round static char const ROUND_1='2'; static char const ROUND_2='3'; static char const ROUND_3='4'; static char const ROUND_4='1'; -char *substring(char *string, int position, int length) -{ - char *p; - int c; - p = calloc(length+1, sizeof(char)); - assert(p); - // printf("size of length %d\n", length); - for(c = 0 ; c < length ; c++ ) - *(p+c) = *((string+position-1)+c); - - *(p+c) = '\0'; - - return p; +char *substring(char *string, int position, int length){ + /** + * Returns the substring of from a given position, for a given size + * */ + char *substring; + int i; + substring = calloc(length+1, sizeof(char)); + assert(substring); + for(i = 0 ; i < length ; i++ ) + // adds characters from given position of string + *(substring+i) = *((string+position-1)+i); + + *(substring+i) = '\0'; + + return substring; } -void insert_substring(char *a, char *b, int position) -{ - char *start, *end; - int length; - - length = strlen(a); - - start = substring(a, 1, position); - end = substring(a, position+1, length-position); - sprintf(a, "%s%s%s", start, b, end); - free(start); - free(end); +void insert_substring(char *dest, char *insert_text, int position){ + /** + * Inserts a string into another string, at a given position + */ + char *start, *end; + int length; + + length = strlen(dest); + // gets first half of string + start = substring(dest, 1, position); + // gets second half a string + end = substring(dest, position+1, length-position); + // formats the string with new string in the middle + sprintf(dest, "%s%s%s", start, insert_text, end); + free(start); + free(end); } void clean_trailing_buffer(char* buff){ + /** + * Cleans any trailing characters after end of html tag + * */ const char needle[10] = "</html>"; + // gets position of final html tag char *result = strstr(buff, needle)+strlen(needle); int position = result - buff; + // overwrites buff to exclude trailing characters memcpy(buff, buff, position); } void render_text(char* buff, char* text){ + /** + * Inserts text into buff after the image + * */ const char new_needle[10] = "\">"; char* result = strstr(buff, new_needle)+strlen(new_needle); int position = result - buff; @@ -54,6 +76,9 @@ void render_text(char* buff, char* text){ } void change_game_image(char* buff, int round){ + /** + * Changes the image src accordingly to the game round + * */ const char needle[10] = "/image-"; char* result = strstr(buff, needle)+strlen(needle); int position = result - buff; diff --git a/response-formatter.h b/response-formatter.h index 7f37f33db23065c2f81f715fe27d732e3e55a42d..3de81ef800133468b038a5dcbcd82c6550324762 100644 --- a/response-formatter.h +++ b/response-formatter.h @@ -1,12 +1,21 @@ +/** + * Written by Abhisha Nirmalathas 913405 for COMP30023 Project 1 + * This program deals with all html manipulation, including insertion, cleaning and + * dynamic images for each round. + * */ #include <stdbool.h> - +// Returns the substring of from a given position, for a given size char *substring(char *string, int position, int length); +// Inserts a string into another string, at a given position void insert_substring(char *a, char *b, int position); +// Cleans any trailing characters after end of html tag void clean_trailing_buffer(char* buff); +// Inserts text into buff after the image void render_text(char* buff, char* text); +// Changes image of html accordingly to round void change_game_image(char* buff, int round); \ No newline at end of file diff --git a/user.c b/user.c index 22b67bc48472e686bb132fc2fdb71251c2da8cbb..1bf913a767920d33a34e19ba387133921d30dd2e 100644 --- a/user.c +++ b/user.c @@ -1,3 +1,7 @@ +/** + * Written by Abhisha Nirmalathas 913405 for COMP30023 Project 1 + * This program handles all clients/game players. + * */ #include <stdio.h> #include <stdlib.h> #include <assert.h> @@ -6,37 +10,54 @@ #include "user.h" +// implementation specific constants for users #define INITIAL_KEYWORDS 5 #define INITAL_N_USERS 5 #define INITIAL_KEYWORD_LENGTH 30 User* new_user(int id){ + /** + * Creates a new user/client + * */ User *user = calloc(1, sizeof *user); assert(user); user->id = id; user->n_capacity = INITIAL_KEYWORDS; user->n_keywords = 0; + + // user is set to WAIT by default user->status = WAIT; user->keywords = calloc(user->n_capacity,sizeof(char*)); + + // user is on round 0 initially user->round = 0; assert(user->keywords); return user; } User_list* initialise_player_list(){ - User_list *users = calloc(1, sizeof(User_list)); - assert(users); - users->n_users = 0; - users->users = calloc(INITAL_N_USERS, sizeof(User*)); - assert(users->users); - return users; + /** + * Initialises a list of clients/users + * */ + User_list *user_list = calloc(1, sizeof(User_list)); + assert(user_list); + user_list->n_users = 0; + user_list->users = calloc(INITAL_N_USERS, sizeof(User*)); + assert(user_list->users); + return user_list; } void resize_keywords(User* user, char* keyword){ + /** + * Adds keyword to the user + * */ + + // adds more space if max keywords of user reached if(user->n_capacity == user->n_keywords){ user->n_capacity *= 2; user->keywords = realloc(user->keywords,sizeof(char*) * (user->n_capacity)); } + // adds keyword to user user->keywords[user->n_keywords] = keyword; user->n_keywords++; for(int j=0; j<user->n_keywords; j++){ @@ -45,98 +66,124 @@ void resize_keywords(User* user, char* keyword){ } -char* add_keyword(int id, User_list* users, char* query){ +char* add_keyword(int id, User_list* user_list, char* query){ + /** + * Parses submitted keyword and adds to the user + * */ const char s[2] = "&"; char * curr = query; char * token = calloc(INITIAL_KEYWORD_LENGTH, sizeof(char)); token[0] = '\0'; assert(token); + + // Skips keyword= curr += 8; + + // Parses keyword strcat(token, strtok(curr, s)); - printf("the keywod is %s\n", token); - for(int i=0; i < users->n_users; i++){ - if(users->users[i]->id == id){ - resize_keywords(users->users[i], token); + for(int i=0; i < user_list->n_users; i++){ + if(user_list->users[i]->id == id){ + // adds keyword to user + resize_keywords(user_list->users[i], token); } } return token; } -void add_user(User* user, User_list* users){ - users->users[users->n_users] = user; - users->n_users++; +void add_user(User* user, User_list* user_list){ + /** + * Adds user to list of users + * */ + // Adds user and updates number of users + user_list->users[user_list->n_users] = user; + user_list->n_users++; } -void free_users(User_list* users){ - for (int i=0; i <users->n_users; i++){ +void free_users(User_list* user_list){ + /** + * Deallocate memory + * */ + for (int i=0; i <user_list->n_users; i++){ // for(int j=0; j < users->users[i]->n_keywords; j++){ // free(&users->users[i]->keywords[j]); // } - free(users->users[i]->keywords); - free(users->users[i]); - } - free(users->users); - free(users); -} - -bool is_players_ready(User_list* users){ - for(int i=0; i < users->n_users; i++){ - if (users->users[i]->status != READY){ - return false; - } + free(user_list->users[i]->keywords); + free(user_list->users[i]); } - return true; + free(user_list->users); + free(user_list); } -bool should_player_quit(User_list* users){ - for(int i=0; i < users->n_users; i++){ - if (users->users[i]->status == QUIT){ +bool should_player_quit(User_list* user_list){ + /** + * Checks if any player has quit, and tells player to quit if so + * */ + for(int i=0; i < user_list->n_users; i++){ + if (user_list->users[i]->status == QUIT){ return true; } } return false; } -bool players_ready(User_list* users){ - for(int i=0; i < users->n_users; i++){ - if (users->users[i]->status != READY){ +bool players_ready(User_list* user_list){ + /** + * checks if all players are ready + * */ + for(int i=0; i < user_list->n_users; i++){ + if (user_list->users[i]->status != READY){ return false; } } return true; } -void change_player_status(int user_id, User_list* users, STATUS status){ - for(int i=0; i < users->n_users; i++){ - if (users->users[i]->id == user_id){ - users->users[i]->status = status; +void change_player_status(int user_id, User_list* user_list, STATUS status){ + /** + * Changes A player's status + * */ + for(int i=0; i < user_list->n_users; i++){ + if (user_list->users[i]->id == user_id){ + user_list->users[i]->status = status; } } } -void change_all_status(User_list* users, STATUS status){ - for(int i=0; i < users->n_users; i++){ - users->users[i]->status = status; +void change_all_status(User_list* user_list, STATUS status){ + /** + * Changes all player's status + * */ + for(int i=0; i < user_list->n_users; i++){ + user_list->users[i]->status = status; } } -int change_player_round(int user_id, User_list* users){ +int change_player_round(int user_id, User_list* user_list){ + /** + * Changes players round based on current round + * */ int round = 1; - for(int i=0; i < users->n_users; i++){ - if (users->users[i]->id == user_id){ - if (users->users[i]->round < 4){ - users->users[i]->round++; + for(int i=0; i < user_list->n_users; i++){ + if (user_list->users[i]->id == user_id){ + if (user_list->users[i]->round < 4){ + user_list->users[i]->round++; } + // resets round to 1 else{ - users->users[i]->round = 1; + user_list->users[i]->round = 1; } - round = users->users[i]->round; + round = user_list->users[i]->round; } }return round; } -bool different_round_discard(int user_id,User_list* users){ - User *user = get_current_user(users, user_id); +bool different_round_discard(int user_id,User_list* user_list){ + /** + * Checks if current player is on a different game round and + * is trying to submit a keyword whilst previous player still + * in previous round + * */ + User *user = get_current_user(user_list, user_id); if (user != NULL && user->status ==READY){ - for(int i=1; i< users->n_users; i++){ - if(users->users[i]->round != users->users[i-1]->round){ + for(int i=1; i< user_list->n_users; i++){ + if(user_list->users[i]->round != user_list->users[i-1]->round){ return true; } } @@ -145,6 +192,9 @@ bool different_round_discard(int user_id,User_list* users){ } bool keyword_match(User* user, char* keyword){ + /** + * Checks if keyword has already been submitted + * */ printf("keyword is %s\n\n", keyword); for(int i=0; i <user->n_keywords;i++){ printf("words being matched is with %s and %s\n", keyword, user->keywords[i]); @@ -156,17 +206,26 @@ bool keyword_match(User* user, char* keyword){ return false; } -void reset_players(User_list *users){ - for(int i=0; i< users->n_users;i++){ - users->users[i]->n_keywords = 0; +void reset_players(User_list *user_list){ + /** + * Resets players keywords + * */ + for(int i=0; i< user_list->n_users;i++){ + user_list->users[i]->n_keywords = 0; } } -bool has_match_ended(User_list* users, char* keyword, int id){ - for(int i=0; i< users->n_users;i++){ - if(users->users[i]->status == READY && id != users->users[i]->id){ - if(keyword_match(users->users[i], keyword)){ - reset_players(users); +bool has_match_ended(User_list* user_list, char* keyword, int id){ + /** + * Checks if the round is completed + * */ + for(int i=0; i< user_list->n_users;i++){ + // Checks that players are READY to play + if(user_list->users[i]->status == READY && id != user_list->users[i]->id){ + // checks if the keyword has been submitted + if(keyword_match(user_list->users[i], keyword)){ + // game has been won and players reset + reset_players(user_list); return true; } } @@ -174,20 +233,26 @@ bool has_match_ended(User_list* users, char* keyword, int id){ return false; } -bool player_won(User_list *users){ - for(int i=0; i < users->n_users; i++){ - if (users->users[i]->status == COMPLETE){ +bool player_won(User_list *user_list){ + /** + * Checks if the game has been completed + * */ + for(int i=0; i < user_list->n_users; i++){ + if (user_list->users[i]->status == COMPLETE){ return true; } } return false; } -User* get_current_user(User_list* users, int id){ +User* get_current_user(User_list* user_list, int id){ + /** + * Gets the user with matching id in list of users/players + * */ User *user = NULL; - for(int i=0; i < users->n_users; i++){ - if (users->users[i]->id == id){ - user = users->users[i]; + for(int i=0; i < user_list->n_users; i++){ + if (user_list->users[i]->id == id){ + user = user_list->users[i]; } } return user; @@ -195,14 +260,21 @@ User* get_current_user(User_list* users, int id){ char* return_all_keywords(User* user){ //RETURNS ADDRESS OF LOCAL VARIABLE + /** + * Returns all the keywords for a particular user + * */ printf("%d\n\n\n", user->n_keywords); + int length = (user->n_keywords)*(INITIAL_KEYWORD_LENGTH+1); char *keywords = calloc(length, user->n_keywords); assert(keywords); + + // adds each keywords for(int i=0; i< user->n_keywords; i++){ strcat(keywords, user->keywords[i]); strcat(keywords,","); } + // terminating byte keywords[strlen(keywords)-1] = '\0'; printf("**** %s \n ", keywords); return keywords; diff --git a/user.h b/user.h index d39ef993ab1a04e66f571fe1d6d037f62ca09652..0b50ef069eae6fcd6c3aeff4fad7bbb7229e3904 100644 --- a/user.h +++ b/user.h @@ -1,4 +1,10 @@ +/** + * Written by Abhisha Nirmalathas 913405 for COMP30023 Project 1 + * This program handles all clients/game players. + * */ #include <stdbool.h> + +// the different status' a user can have typedef enum { READY, @@ -24,40 +30,56 @@ typedef struct User_list{ User **users; }User_list; +// Creates a new user/client User* new_user(int id); +// Initialises a list of clients/users User_list* initialise_player_list(); +// Adds keyword to the user void resize_keywords(User* user, char* keyword); +// Parses submitted keyword and adds to the user char* add_keyword(int id, User_list* users, char* query); +// Adds user and updates number of users void add_user(User* user, User_list* users); +// Deallocate memory void free_users(User_list* users); -bool is_players_ready(User_list* users); - +// Checks if any player has quit, and tells player to quit if so bool should_player_quit(User_list* users); +// Checks if all players are ready bool players_ready(User_list* users); +// Changes A players status void change_player_status(int user_id, User_list* users, STATUS status); +// Changes ALL players status void change_all_status(User_list* users, STATUS status); +// Changes players round based on current round int change_player_round(int user_id, User_list* users); +// Checks if current player is trying to submit keyword on a different round bool different_round_discard(int user_id, User_list* users); +// Checks if keyword has been submitted bool keyword_match(User* user, char* keyword); +// Resets players keywords void reset_players(User_list *users); +// Checks if the round is completed bool has_match_ended(User_list* users, char* keyword, int id); +// Checks if the game has been completed bool player_won(User_list *users); +// Gets the user with matching id in list of users/players User* get_current_user(User_list* users, int id); +// Returns all the keywords for a particular user char* return_all_keywords(User* user); \ No newline at end of file