+1 (812) 783-0640 

Client-server hangman assignment sample

Looking for professional help with client-server hangman? You found it. ProgrammingAssignmentHelper.com provides assistance with this topic to make completion of these tasks easier for students.

Process Management and Distributed Computing

Task 1: Client-Server Computing

You have been commissioned to develop a client/server system for an online games provider

to expand their current offerings to registered clients. The company wishes to offer to their

current clients the game of Hangman, which is a word guessing game.

In the game of Hangman the server randomly selects a two-word phrase from a given text

file. The word phrase is represented by a row of dashes representing each letter of the word

on the client machine. If the client selects a correct letter the letter should then appear in all

the correct places in which it occurs.

The client has a number of turns in which to guess all the letters in the two-word phrase. The

number of turns the client receives is proportional to the length of the two word phrase. If the

client guesses all the letters before running out of turns the client wins the game. If the client

fails to guess all the letters within the number of turns provided the client loses the game.

All the words that are to be used in the game have been provided by the company and they

have insisted that this list is not to be changed. The information stored in this text file is in the

form of object, object type (e.g. beach, place) – each line in the text file represents a pair of

words which are both used in a single game of Hangman.

The client and server will be implemented in the C programming language using BSDsockets on the Linux operating system. The programs (clients and server) are to run in a terminal reading input from thekeyboard and writing output to the screen.

Server

The server will automatically load the hangman_text.txt file which is to be located in the

same directory as the server binary file. The server will take only one command line

parameter that indicates which port the server is to listen on. If no port number is supplied the

default port of 12345 is to be used by the server. The following command will run the server

program on port 12345.

./Server 12345

The server is responsible for ensuring only registered clients of the system can play

Hangman. A file named Authentication.txt contains the names and the passwords of all

registered clients. This file should be located in the same directory as the server binary file.

This file is not to be changed.

The server should not be able to take any input from the terminal once it is running. The only

way that the server is to exit is upon receiving a SIGINT from the operating system (an

interrupt signal). SIGINT is a type of signal found on POSIX systems and in the Linux

environment this means ctrl+c has been pressed at the server terminal. You need to

implement a signal handler and ensure the server exits cleanly. This means the server needs

to deal elegantly with any threads that have been created as well as any open sockets,

dynamically allocated memory and/or open files. When the server receives a SIGINT, it is to

immediately commence the shutdown procedure even if there are currently connected clients.

Client

The client will take two (2) command line parameters: hostname and port number. The

following command will run the client program connecting to the server on port 12345.

./Client server_IP_address 12345

The game of Hangman is only available to registered clients of the company’s online gaming

system. Once the client program starts the client must authenticate by entering a registered

name and password which appear in the Authentication.txt file located on the server. After the

server validates the client’s credentials the client program can proceed to the main menu. If

the client does not authenticate correctly the socket is to be immediately closed.

The client program should be a menu driven application. The client program will have three

options: Play Hangman, Show Leader Board, and Exit.

Authentication.txt.pdf

Username Password

Maolin 111111

Jason 222222

Mike 333333

Peter 444444

Justin 555555

Anna 123123

Timothy 155222

Anthony 123123

Paul 248273

Richie 993844

 Solution:

 HANGMAN GAME PLAY MODE SERVER – CLIENT

1 How to compile the program

Compile via makefile of Hangman project.

client server hangman 1

Figure 1‑1: Compile the game

Client: This is client program of hangman game

Server: this is server program of hangman game

2 How to run

2.1 Server side:

./Server : Run server using portnumber to communicate with client side. Default port number is 12345 if did not have portnumber argument.

User/Pass using for authenticator when client connect to server store in Authentication.txt.

g: ./Server 12345

client server hangman 2

Figure 2‑1: Run Server Hangman

2.2 Client side:

./Client : Run client and will sent to server running in hostname with portnumber.

g: ./Client localhost 12345

client server hangman 3

Figure 2‑2: Run Client Hangman

The server will allow up to 10 clients to use the system at the same time.

3 Play:

client server hangman 4

Figure 3‑1: Play hangman 

Client.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include “client_game.h”

#include “client_leaderboard.h”

#define MAXDATASIZE 256 /* max number of bytes we can get at once */

#define ARRAY_SIZE 30

#define RETURNED_ERROR -1

void client_game_loop(int socket_identifier);

int show_menu();

void greeting_message();

//global socket id

int sockfd;

void client_game_loop(int socket_identifier)

{

int socket_id = socket_identifier;

greeting_message();

printf(“Please enter your username–>”);

char* send_buf;

send_buf = calloc(MAXDATASIZE, sizeof(char));

scanf(“%s”, send_buf);

if (send(socket_id, send_buf, MAXDATASIZE, 0) <= 0)

{

return;

}

printf(“Please enter your password–>”);

send_buf = calloc(MAXDATASIZE, sizeof(char));

scanf(“%s”, send_buf);

if (send(socket_id, send_buf, MAXDATASIZE, 0) <= 0)

{

return;

}

//Get the user_id result back from login validation

uint16_t statistics;

if (recv(socket_id, &statistics, sizeof(uint16_t), 0) <= 0)

{

return;

}

int user_id = ntohs(statistics);

if (user_id <= 0)

{

printf(“\nYou entered either an incorrect username or password – disconnection\n”);

close(socket_id);

exit(1);

}

else

{

char username[MAXDATASIZE];

if (recv(socket_id, username, MAXDATASIZE, 0) <= 0)

{

return;

}

printf(“\nWelcome to the Hangman Gaming System\n\n\n”);

int menu_option = 0;

while (menu_option != 3)

{

menu_option = show_menu();

//Send option to server

statistics = htons(menu_option);

if (send(socket_id, &statistics, sizeof(uint16_t), 0) <= 0)

{

return;

}

switch (menu_option)

{

case 1:

if (client_hangman_game(socket_id, username) == RETURNED_ERROR)

{

return;

}

break;

case 2:

if (client_leaderboard(socket_id) == RETURNED_ERROR)

{

return;

}

break;

case 3:

printf(“Quit here\n”);

break;

}

}

}

}

int show_menu()

{

printf(“Please enter a selection\n”);

printf(“<1> Play Hangman\n”);

printf(“<2> Show Leaderboard\n”);

printf(“<3> Quit\n\n”);

int menu_option = 0;

while ((menu_option < 1) || (menu_option > 3))

{

printf(“Selection option 1-3 ->”);

char input;

scanf(“%s”, &input);

menu_option = input – ‘0’;

}

return menu_option;

}

void greeting_message()

{

printf(“============================================\n\n\n”);

printf(“Welcome to the Online Hangman Gaming System\n\n\n”);

printf(“============================================\n\n\n”);

printf(“You are required to login with your registered username and Password \n\n”);

}

//client singal handler for CTRL+C

void handler(int sigtype)

{

close(sockfd);

exit(1);

}

int main(int argc, char *argv[])

{

signal(SIGINT, handler);

struct hostent *he;

struct sockaddr_in their_addr; /* connector’s address information */

if (argc != 3)

{

fprintf(stderr, “usage: client_hostname port_number\n”);

exit(1);

}

if ((he = gethostbyname(argv[1])) == NULL)

{ /* get the host info */

herror(“gethostbyname”);

exit(1);

}

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)

{

perror(“socket”);

exit(1);

}

their_addr.sin_family = AF_INET; /* host byte order */

their_addr.sin_port = htons(atoi(argv[2])); /* short, network byte order */

their_addr.sin_addr = *((struct in_addr *) he->h_addr);

bzero(&(their_addr.sin_zero), 8); /* zero the rest of the struct */

if (connect(sockfd, (struct sockaddr *) &their_addr, sizeof(struct sockaddr)) == -1)

{

perror(“connect”);

exit(1);

}

printf(“Waiting for server response…\n”);

uint16_t statistics;

if (recv(sockfd, &statistics, sizeof(uint16_t), 0) > 0)

{

// Client game loop

client_game_loop(sockfd);

}

printf(“Disconnected\n”);

close(sockfd);

return 0;

client_game.c

#include “client_game.h”

int client_hangman_game(int socket_id, char* username)

{

char current_guessed_letters[MAXDATASIZE];

int num_guesses_left;

uint16_t statistics;

char guessed_word1[MAXDATASIZE];

char guessed_word2[MAXDATASIZE];

int isGameOver = 0;

int isWon = 0;

while (1)

{

//recv game over flag

if (recv(socket_id, &statistics, sizeof(uint16_t), 0) <= 0)

{

return RETURNED_ERROR;

}

isGameOver = ntohs(statistics);

//recv game won flag

if (recv(socket_id, &statistics, sizeof(uint16_t), 0) <= 0)

{

return RETURNED_ERROR;

}

isWon = ntohs(statistics);

 

printf(“\n=======================================================\n”);

//recv current guessed letters

if (recv(socket_id, current_guessed_letters, MAXDATASIZE, 0) <= 0)

{

return RETURNED_ERROR;

}

printf(“\nGuessed letters: %s”, current_guessed_letters);

//recv number of guessed left

if (recv(socket_id, &statistics, sizeof(uint16_t), 0) <= 0)

{

return RETURNED_ERROR;

}

num_guesses_left = ntohs(statistics);

printf(“\n\nNumber of guesses left: %d\n”, num_guesses_left);

//recv guessed word 1

if (recv(socket_id, guessed_word1, MAXDATASIZE, 0) <= 0)

{

return RETURNED_ERROR;

}

//recv guessed word 2

if (recv(socket_id, guessed_word2, MAXDATASIZE, 0) <= 0)

{

return RETURNED_ERROR;

}

display_guessed_word(guessed_word1, guessed_word2);

//User is won the game

if (isWon)

{

printf(“Game over\n”);

printf(“\n\nWell done %s! You won this round of Hangman!\n\n”, username);

break;

}

//Game over

if (isGameOver)

{

printf(“Game Over\n”);

printf(“\n\nBad luck %s! You have run out of guesses. The hangman got you!\n\n”, username);

break;

}

//Ask user to guess

char send_letter;

printf(“Enter your guess – “);

scanf(“%s”, &send_letter);

//send guessed letter to server

if (send(socket_id, &send_letter, sizeof(char), 0) <= 0)

{

return RETURNED_ERROR;

}

}

return 0;

}

void display_guessed_word(char* word1, char* word2)

{

printf(“\nWord: “);

for (int i = 0; i < strlen(word1); i++)

{

printf(“%c “, word1[i]);

}

for (int i = 0; i < strlen(word2); i++)

{

printf(” %c”, word2[i]);

}

printf(“\n\n”);

client_game.h

#ifndef CLIENT_GAME_H_

#define CLIENT_GAME_H_

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define MAXDATASIZE 256

#define RETURNED_ERROR -1

int client_hangman_game(int socket_id, char* username);

void display_guessed_word(char* word1, char* word2);

#endif /* CLIENT_GAME_H_ */ 

client_leaderboard.c

#include “client_leaderboard.h”

int client_leaderboard(int socket_id)

{

uint16_t statistics;

char username[MAXDATASIZE];

int games_played;

int games_won;

int board_users_num;

//recv board users num

recv(socket_id, &statistics, sizeof(uint16_t), 0);

board_users_num = ntohs(statistics);

if (board_users_num > 0)

{

for (int i = 0; i < board_users_num; i++)

{

//recv username

if (recv(socket_id, username, MAXDATASIZE, 0) <= 0)

{

return RETURNED_ERROR;

}

//recv games played

if (recv(socket_id, &statistics, sizeof(uint16_t), 0) <= 0)

{

return RETURNED_ERROR;

}

games_played = ntohs(statistics);

//recv games won

if (recv(socket_id, &statistics, sizeof(uint16_t), 0) <= 0)

{

return RETURNED_ERROR;

}

games_won = ntohs(statistics);

printf(“\n==================================================\n\n”);

printf(“Player – %s\n”, username);

printf(“Number of games won – %d\n”, games_won);

printf(“Number of games played – %d\n\n”, games_played);

printf(“==================================================\n\n”);

}

}

else

{

printf(“=============================================================================\n\n”);

printf(“There is no information currently stored in the Leader Board. Try again later\n”);

printf(“\n=============================================================================\n\n\n”);

}

return 0;

client_leaderboard.h

#ifndef CLIENT_LEADERBOARD_H_

#define CLIENT_LEADERBOARD_H_

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define MAXDATASIZE 256

#define RETURNED_ERROR -1

int client_leaderboard(int socket_id);

#endif /* CLIENT_LEADERBOARD_H_ */ 

load_file.c

#include “load_file.h”

void read_authentication_file()

{

char *input_line;

char *str1;

char *str2;

FILE *file;

int index = 0;

file = fopen(“Authentication.txt”, “r”);

if (file == NULL)

{

printf(“No authentication.txt file. \n”);

exit(1);

}

else

{

input_line = calloc(64, sizeof(char));

while (fgets(input_line, 64, file) != NULL)

{

str1 = calloc(64, sizeof(char));

str2 = calloc(64, sizeof(char));

sscanf(input_line, “%s%s”, str1, str2);

users[index].username = str1;

users[index].password = str2;

users[index].user_id = index;

index++;

}

}

fclose(file);

free(input_line);

}

void read_hangman_text_file()

{

char *input_line;

char *str1;

char *str2;

FILE *file;

int index = 0;

file = fopen(“hangman_text.txt”, “r”);

if (file == NULL)

{

printf(“NO hangman_text.txt file. \n”);

exit(1);

}

else

{

input_line = calloc(64, sizeof(char));

while (fgets(input_line, 64, file) != NULL)

{

str1 = calloc(64, sizeof(char));

str2 = calloc(64, sizeof(char));

sscanf(input_line, “%[^,],%s”, str1, str2);

hangman[index].word1 = str1;

hangman[index].word2 = str2;

index++;

}

fclose(file);

free(input_line);

}

}

void reset_users(void)

{

for (int i = 0; i < MAX_USERS_NUMBER; i++)

{

users[i].games_won = 0;

users[i].games_played = 0;

users[i].loggedin = 0;

}

load_file.h

#ifndef LOAD_FILE_H_

#define LOAD_FILE_H_

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define MAX_USERS_NUMBER 11

#define MAX_HANGMEN_WORDS 288

struct authentication

{

char* username;

char* password;

int games_won;

int games_played;

int loggedin;

int user_id;

};

struct hangman_text_file

{

char* word1;

char* word2;

};

typedef struct authentication users_array;

typedef struct hangman_text_file hangman_text;

extern users_array users[MAX_USERS_NUMBER];

extern hangman_text hangman[MAX_HANGMEN_WORDS];

void read_authentication_file(void);

void read_hangman_text_file(void);

void reset_users(void);

#endif /* LOAD_FILE_H_ */ 

Server.c

#define _GNU_SOURCE

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include “load_file.h”

#include “server_game.h”

#define MAXDATASIZE 256 /* max number of bytes we can get at once */

#define BACKLOG 10

#define MAX_USERS_NUMBER 11

#define MAX_HANGMEN_WORDS 288

#define DEFAULT_PORT 12345

#define NUM_HANDLER_THREADS 10

pthread_mutex_t request_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;

pthread_cond_t got_request = PTHREAD_COND_INITIALIZER;

int num_requests = 0;

struct request

{

int socket_id;

struct request* next;

};

struct request* requests_head = NULL;

struct request* last_request = NULL;

//GLOBAL THREADS

pthread_t p_threads[NUM_HANDLER_THREADS];

int thr_id[NUM_HANDLER_THREADS];

int connected_sockets[NUM_HANDLER_THREADS];

//listen socket

int sockfd;

void add_request(int request_num, pthread_mutex_t* p_mutex, pthread_cond_t* p_cond_var);

struct request* get_request(pthread_mutex_t* p_mutex);

void* handle_requests_loop(void* data);

int validate_user(char* name, char* password);

void add_request(int socket_id, pthread_mutex_t* p_mutex, pthread_cond_t* p_cond_var)

{

int rc; /* return code of pthreads functions. */

struct request* a_request; /* pointer to newly added request. */

/* create structure with new request */

a_request = (struct request*) malloc(sizeof(struct request));

if (!a_request)

{ /* malloc failed?? */

fprintf(stderr, “add_request: out of memory\n”);

exit(1);

}

a_request->socket_id = socket_id;

a_request->next = NULL;

/* lock the mutex, to assure exclusive access to the list */

rc = pthread_mutex_lock(p_mutex);

if (rc)

{

printf(“Can’t lock the mutex p_mutex \n”);

exit(1);

}

/* add new request to the end of the list, updating list */

/* pointers as required */

if (num_requests == 0)

{ /* special case – list is empty */

requests_head = a_request;

last_request = a_request;

}

else

{

last_request->next = a_request;

last_request = a_request;

}

/* increase total number of pending requests by one. */

num_requests++;

/* unlock mutex */

rc = pthread_mutex_unlock(p_mutex);

/* signal the condition variable – there’s a new request to handle */

rc = pthread_cond_signal(p_cond_var);

}

struct request* get_request(pthread_mutex_t* p_mutex)

{

int rc; /* return code of pthreads functions. */

struct request* a_request; /* pointer to request. */

/* lock the mutex, to assure exclusive access to the list */

rc = pthread_mutex_lock(p_mutex);

if (rc)

{

printf(“Can’t lock the mutex p_mutex \n”);

exit(1);

}

if (num_requests > 0)

{

a_request = requests_head;

requests_head = a_request->next;

if (requests_head == NULL)

{ /* this was the last request on the list */

last_request = NULL;

}

/* decrease the total number of pending requests */

num_requests–;

}

else

{ /* requests list is empty */

a_request = NULL;

}

/* unlock mutex */

rc = pthread_mutex_unlock(p_mutex);

if (rc)

{

printf(“Can’t unlock the mutex p_mutex \n”);

exit(1);

}

/* return the request to the caller. */

return a_request;

}

void* handle_requests_loop(void* data)

{

int rc; /* return code of pthreads functions. */

struct request* a_request; /* pointer to a request. */

int thread_id = *((int *) data);

uint16_t statistics;

/* lock the mutex, to access the requests list exclusively. */

rc = pthread_mutex_lock(&request_mutex);

if (rc)

{

printf(“Can’t lock the mutex request_mutex \n”);

exit(1);

}

/* do forever…. */

while (1)

{

if (num_requests > 0)

{ /* a request is pending */

a_request = get_request(&request_mutex);

if (a_request)

{ /* got a request – handle it and free it */

/* unlock mutex – so other threads would be able to handle */

/* other reqeusts waiting in the queue paralelly. */

rc = pthread_mutex_unlock(&request_mutex);

//get socket id from request

int socket_id = a_request->socket_id;

free(a_request);

//put the socket which is handling by this thread

//into the connect_socket array

connected_sockets[thread_id] = socket_id;

printf(“Thread %d is handle a request\n”, thread_id);

statistics = htons(thread_id);

rc = send(socket_id, &statistics, sizeof(uint16_t), 0);

if (rc > 0)

{

server_game_loop(socket_id);

}

close(connected_sockets[thread_id]);

printf(“Thread %d is finished\n”, thread_id);

/* and lock the mutex again. */

rc = pthread_mutex_lock(&request_mutex);

if (rc)

{

printf(“Can’t lock the mutex request_mutex \n”);

exit(1);

}

}

}

else

{

/* wait for a request to arrive. note the mutex will be */

/* unlocked here, thus allowing other threads access to */

/* requests list. */

rc = pthread_cond_wait(&got_request, &request_mutex);

/* and after we return from pthread_cond_wait, the mutex */

/* is locked again, so we don’t need to lock it ourselves */

}

}

}

void handler(int sigtype)

{

struct request* r_head = requests_head;

printf(“\n===============Caught a signal===================\n”);

printf(“Shutdown Server…\n”);

//Kill all the threads

for (int i = 0; i < NUM_HANDLER_THREADS; i++)

{

close(connected_sockets[i]);

pthread_cancel(p_threads[i]);

}

//Close all the socket in the request list

while (r_head)

{

close(r_head->socket_id);

r_head = r_head->next;

}

//Close the listen socket

close(sockfd);

//exit the server program

exit(1);

}

int main(int argc, char *argv[])

{

signal(SIGINT, handler);

pthread_attr_t attr;

pthread_attr_init(&attr);

int new_fd; /* listen on sock_fd, new connection on new_fd */

struct sockaddr_in my_addr; /* my address information */

struct sockaddr_in their_addr; /* connector’s address information */

socklen_t sin_size;

/* Get port number for server to listen on */

if (argc > 2)

{

fprintf(stderr, “usage: client port_number\n”);

exit(1);

}

int port_num;

if (argc == 1)

{

port_num = DEFAULT_PORT;

}

else

{

port_num = atoi(argv[1]);

}

//File IO

read_authentication_file();

read_hangman_text_file();

//initialse users

reset_users();

/* generate the socket */

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)

{

perror(“socket”);

exit(1);

}

// Set the socket value to SO_REUSEADDR so that

// the socket can be use after the server restart immediately

int reuseaddr = 1;

if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)) == -1)

{

perror(“setsockopt”);

}

/* generate the end point */

my_addr.sin_family = AF_INET; /* host byte order */

my_addr.sin_port = htons(port_num); /* short, network byte order */

my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */

/* bind the socket to the end point */

if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1)

{

perror(“bind”);

exit(1);

}

/* start listnening */

if (listen(sockfd, BACKLOG) == -1)

{

perror(“listen”);

exit(1);

}

for (int i = 0; i < NUM_HANDLER_THREADS; i++)

{

thr_id[i] = i;

pthread_create(&p_threads[i], &attr, handle_requests_loop, (void*) &thr_id[i]);

}

printf(“Server starts listnening …\n”);

/* repeat: accept, send, close the connection */

/* for every accepted connection, use a sepetate process or thread to serve it */

while (1)

{ /* main accept() loop */

sin_size = sizeof(struct sockaddr_in);

if ((new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &sin_size)) == -1)

{

perror(“accept”);

continue;

}

printf(“server: got connection from %s\n”, inet_ntoa(their_addr.sin_addr));

add_request(new_fd, &request_mutex, &got_request);

}

server_game.c

#include “server_game.h”

pthread_mutex_t users_mutex = PTHREAD_MUTEX_INITIALIZER;

int server_hangman_game(int socket_id, int user_id)

{

//get the random words

srand(time(NULL));

int r = rand() % 288;

uint16_t statistics;

printf(“Random %d \n”, r);

pthread_mutex_lock(&users_mutex);

char* first_word = hangman

[r]

.word1;

char* second_word = hangman

[r]

.word2;

pthread_mutex_unlock(&users_mutex);

printf(“Word1 is %s and word2 is %s \n”, first_word, second_word);

printf(“Word1 length is %zu and word2 length is %zu \n”, strlen(first_word), strlen(second_word));

//initialize client guessed letters

char* client_guessed_letters = calloc(MAXDATASIZE, sizeof(char));

//number of guesses left

int num_guesses = guesses_min(strlen(first_word) + strlen(second_word) + 10);

printf(“Number of guesses = %d \n”, num_guesses);

//initialise client guessed words

char client_guessed_word1[MAXDATASIZE];

char client_guessed_word2[MAXDATASIZE];

for (int i = 0; i < strlen(first_word); i++)

{

client_guessed_word1[i] = 95;

}

client_guessed_word1[strlen(first_word)] = ‘\0’;

for (int i = 0; i < strlen(second_word); i++)

{

client_guessed_word2[i] = 95;

}

client_guessed_word2[strlen(second_word)] = ‘\0’;

printf(“Client guessed word1 %s, word2 %s\n”, client_guessed_word1, client_guessed_word2);

//initialize client guessed single letter

char recv_letter;

int isGameOver = 0;

int isWon = 0;

while (1)

{

//gameover becuase number of guesses reach 0

if (num_guesses <= 0)

{

isGameOver = 1;

}

//check if two words are the same as client guessed words

if (strcmp(first_word, client_guessed_word1) == 0 && strcmp(second_word, client_guessed_word2) == 0)

{

isWon = 1;

}

//send game status isgameover

statistics = htons(isGameOver);

if (send(socket_id, &statistics, sizeof(uint16_t), 0) <= 0)

{

return RETURNED_ERROR;

}

statistics = htons(isWon);

if (send(socket_id, &statistics, sizeof(uint16_t), 0) <= 0)

{

return RETURNED_ERROR;

}

//send guessed letterd

if (send(socket_id, client_guessed_letters, MAXDATASIZE, 0) <= 0)

{

return RETURNED_ERROR;

}

//send number of guesses

statistics = htons(num_guesses);

if (send(socket_id, &statistics, sizeof(uint16_t), 0) <= 0)

{

return RETURNED_ERROR;

}

//send guessed word

if (send(socket_id, client_guessed_word1, MAXDATASIZE, 0) <= 0)

{

return RETURNED_ERROR;

}

if (send(socket_id, client_guessed_word2, MAXDATASIZE, 0) <= 0)

{

return RETURNED_ERROR;

}

//Player won the game

if (isWon)

{

printf(“\nPlayer %s win the game!\n”, users[user_id].username);

//Save the record to the leader board

pthread_mutex_lock(&users_mutex);

users[user_id].games_won++;

pthread_mutex_unlock(&users_mutex);

printf(“\nPlayer: %s , Games played : %d, Games won:%d \n”, users[user_id].username, users[user_id].games_played, users[user_id].games_won);

break;

}

//Game over

if (isGameOver)

{

printf(“\nPlayer %s lose the game!\n”, users[user_id].username);

printf(“\nPlayer: %s , Games played : %d, Games won:%d \n”, users[user_id].username, users[user_id].games_played, users[user_id].games_won);

break;

}

//receive next guess letter

if (recv(socket_id, &recv_letter, sizeof(char), 0) <= 0)

{

return RETURNED_ERROR;

}

//decrese number of guess by 1

num_guesses–;

//add the receive letter to the guesses letter if not exist

if (strchr(client_guessed_letters, recv_letter) == NULL)

{

strcat(client_guessed_letters, &recv_letter);

}

//put the receive letter into guessed words if the letter is right

for (int i = 0; i < strlen(first_word); i++)

{

if (first_word[i] == recv_letter)

{

client_guessed_word1[i] = first_word[i];

}

}

for (int i = 0; i < strlen(second_word); i++)

{

if (second_word[i] == recv_letter)

{

client_guessed_word2[i] = second_word[i];

}

}

}

return 0;

}

void server_game_loop(int socket_id)

{

char username[MAXDATASIZE];

char password[MAXDATASIZE];

if (recv(socket_id, username, MAXDATASIZE, 0) <= 0)

{

return;

}

printf(“Username : %s \n”, username);

if (recv(socket_id, password, MAXDATASIZE, 0) <= 0)

{

return;

}

printf(“Password : %s \n”, password);

int user_id = validate_user(username, password);

uint16_t statistics;

statistics = htons(user_id);

if (user_id <= 0)

{

printf(“User login fail \n”);

if (send(socket_id, &statistics, sizeof(uint16_t), 0) <= 0)

{

return;

}

}

else

{

//send user_id to client

printf(“User id : %d %s login successfully\n”, user_id, users[user_id].username);

if (send(socket_id, &statistics, sizeof(uint16_t), 0) <= 0)

{

return;

}

if (send(socket_id, users[user_id].username, MAXDATASIZE, 0) <= 0)

{

return;

}

int menu_option = 0;

while (menu_option != 3)

{

//receive menu option

if (recv(socket_id, &statistics, sizeof(uint16_t), 0) <= 0)

{

return;

}

menu_option = ntohs(statistics);

printf(“User menu option : %d \n”, menu_option);

 

//Check menu option in server

switch (menu_option)

{

case 1:

printf(“User %s just started Hangman game\n”, users[user_id].username);

//mutex

pthread_mutex_lock(&users_mutex);

users[user_id].games_played++;

pthread_mutex_unlock(&users_mutex);

if (server_hangman_game(socket_id, user_id) == RETURNED_ERROR)

{

return;

}

break;

case 2:

printf(“User %s open Leaderboard\n”, users[user_id].username);

 

if (server_leaderboard(socket_id) == RETURNED_ERROR)

{

return;

}

break;

case 3:

printf(“User %s Quit\n”, users[user_id].username);

break;

}

}

}

}

int validate_user(char* name, char* password)

{

int i;

for (i = 1; i < MAX_USERS_NUMBER; i++)

{

if (strcmp(name, users[i].username) == 0)

{

if (strcmp(password, users[i].password) == 0)

{

return i;

}

else

{

return 0;

}

}

}

return 0;

}

int guesses_min(int words_length)

{

if (words_length <= 26)

{

return words_length;

}

else

{

return 26;

}

server_game.h

#ifndef SERVER_GAME_H_

#define SERVER_GAME_H_

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include “pthread.h”

#include “load_file.h”

#include “server_leaderboard.h”

#define MAXDATASIZE 256

#define MAX_USERS_NUMBER 11

#define RETURNED_ERROR -1

extern pthread_mutex_t users_mutex;

//GLobal variables

users_array users[MAX_USERS_NUMBER];

hangman_text hangman[MAX_HANGMEN_WORDS];

int server_hangman_game(int socket_id, int user_id);

int guesses_min(int words_length);

int validate_user(char* name, char* password);

void server_game_loop(int socket_id);

#endif /* SERVER_GAME_H_ */ 

server_leaderboard.c

#include “server_leaderboard.h”

pthread_mutex_t board_mutex = PTHREAD_MUTEX_INITIALIZER;

int server_leaderboard(int socket_id)

{

//load user to a board linked list

load_leaderboard();

//sort the users

sort_leaderboard();

//print users for debugging

print_leaderboard();

//send leaderboard to client

if (send_leaderboard(socket_id) == RETURNED_ERROR)

{

pthread_mutex_unlock(&board_mutex);

return RETURNED_ERROR;

}

return 0;

}

int send_leaderboard(int socket_id)

{

uint16_t statistics;

pthread_mutex_lock(&board_mutex);

statistics = htons(board_users_num);

if (send(socket_id, &statistics, sizeof(uint16_t), 0) <= 0)

{

return RETURNED_ERROR;

}

if (board_users_num > 0)

{

for (int i = 0; i < board_users_num; i++)

{

//send username

if (send(socket_id, board[i].username, MAXDATASIZE, 0) <= 0)

{

return RETURNED_ERROR;

}

//send games played

statistics = htons(board[i].games_played);

if (send(socket_id, &statistics, sizeof(uint16_t), 0) <= 0)

{

return RETURNED_ERROR;

}

//send games won

statistics = htons(board[i].games_won);

if (send(socket_id, &statistics, sizeof(uint16_t), 0) <= 0)

{

return RETURNED_ERROR;

}

}

}

pthread_mutex_unlock(&board_mutex);

return 0;

}

void load_leaderboard()

{

int index = 0;

pthread_mutex_lock(&board_mutex);

pthread_mutex_lock(&users_mutex);

 

for (int i = 1; i < MAX_USERS_NUMBER; i++)

{

if (users[i].games_played > 0)

{

board[index].username = users[i].username;

board[index].games_played = users[i].games_played;

board[index].games_won = users[i].games_won;

index++;

}

}

board_users_num = index;

pthread_mutex_unlock(&users_mutex);

pthread_mutex_unlock(&board_mutex);

}

void sort_leaderboard()

{

leaderboard_node tmp;

pthread_mutex_lock(&board_mutex);

for (int i = 0; i < board_users_num; ++i)

{

for (int j = i + 1; j < board_users_num; ++j)

{

if (board[i].games_won > board[j].games_won)

{

tmp = board[j];

board[j] = board[i];

board[i] = tmp;

}

else if (board[i].games_won == board[j].games_won)

{

double win_per1 = board[i].games_won / board[i].games_played;

double win_per2 = board[j].games_won / board[j].games_played;

if (win_per1 > win_per2)

{

tmp = board[j];

board[j] = board[i];

board[i] = tmp;

}

else if (win_per1 == win_per2)

{

if (strcmp(board[i].username, board[j].username) > 0)

{

tmp = board[j];

board[j] = board[i];

board[i] = tmp;

}

 

}

}

}

}

pthread_mutex_unlock(&board_mutex);

}

void print_leaderboard()

{

pthread_mutex_lock(&board_mutex);

printf(“========Leaderboard==========\n”);

for (int i = 0; i < board_users_num; i++)

{

printf(“User: %s, Game played: %d, Game won: %d\n”, board[i].username, board[i].games_played, board[i].games_won);

}

pthread_mutex_unlock(&board_mutex);

server_leaderboard.h

#ifndef SERVER_LEADERBOARD_H_

#define SERVER_LEADERBOARD_H_

#define MAXDATASIZE 256

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include “load_file.h”

#include “server_game.h”

#define MAX_USERS_NUMBER 11

#define RETURNED_ERROR -1

struct leader_board

{

char* username;

int games_won;

int games_played;

int user_id;

};

typedef struct leader_board leaderboard_node;

leaderboard_node board[10];

int board_users_num;

int server_leaderboard(int socket_id);

//Sort the leaderboard

void sort_leaderboard();

//Load the leaderboard from the users array

void load_leaderboard();

//For debugging on server

void print_leaderboard();

//Send the leaderboard to the client

int send_leaderboard(int socket_id);

#endif /* SERVER_LEADERBOARD_H_ */