Xinghang Sun 1 year ago
parent
commit
32310342d6
7 changed files with 277732 additions and 0 deletions
  1. 14 0
      Makefile
  2. 760 0
      game_server.c
  3. 74 0
      game_server.h
  4. BIN
      user_data
  5. 162 0
      users.c
  6. 79 0
      utils.h
  7. 276643 0
      wordlist.txt

+ 14 - 0
Makefile

@@ -0,0 +1,14 @@
+PORT = 8829
+CFLAGS += -DPORT=\$(PORT)
+all:users.c game_server.o boggle_server
+
+users.o:utils.h game_server.h
+	gcc $(CFLAGS) -c -std=gnu99 -Wall -Werror users.c
+
+game_server.o: utils.h game_server.h
+	gcc $(CFLAGS) -c -std=gnu99 -Wall -Werror game_server.c
+
+boggle_server: users.o game_server.o
+	gcc $(CFLAGS) -o boggle_server users.o game_server.o
+clean:
+	rm users.o game_server.o boggle_server

+ 760 - 0
game_server.c

@@ -0,0 +1,760 @@
+#define _GNU_SOURCE
+#include "game_server.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <ctype.h>
+#include "utils.h"
+//#include "users.c"
+#include "boggle4/dictionary.c"
+#include "boggle4/words.c"
+
+
+Player *player_list = NULL;
+
+Client *client_list = NULL;
+int round_num =0 ;
+int score;
+int word_score;
+int old_score;
+int skip=0;
+Client special_client;
+short port = -1;
+int in_newgame = 0;
+int action;
+char input[17];
+struct sigaction newact;
+
+
+char dice[16][6] = {
+        {'R', 'I', 'F', 'O', 'B', 'X'},
+        {'I', 'F', 'E', 'H', 'E', 'Y'},
+        {'D', 'E', 'N', 'O', 'W', 'S'},
+        {'U', 'T', 'O', 'K', 'N', 'D'},
+        {'H', 'M', 'S', 'R', 'A', 'O'},
+        {'L', 'U', 'P', 'E', 'T', 'S'},
+        {'A', 'C', 'I', 'T', 'O', 'A'},
+        {'Y', 'L', 'G', 'K', 'U', 'E'},
+        {'Q', 'B', 'M', 'J', 'O', 'A'},
+        {'E', 'H', 'I', 'S', 'P', 'N'},
+        {'V', 'E', 'T', 'I', 'G', 'N'},
+        {'B', 'A', 'L', 'I', 'Y', 'T'},
+        {'E', 'Z', 'A', 'V', 'N', 'D'},
+        {'R', 'A', 'L', 'E', 'S', 'C'},
+        {'U', 'W', 'I', 'L', 'R', 'G'},
+        {'P', 'A', 'C', 'E', 'M', 'D'}
+};
+char* actions[2] = {"quit", "logout"};
+char* messages[7] = {"Too Short", "Already Found", "Not on Board", "Not a Word", "Welcome to Boggle", "Hello Again", "New Round"};
+int listenfd;
+int board[16];
+void swap(int* i, int* j) {
+    int temp = *i;
+    *i = *j;
+    *j = temp;
+}
+void generate_board() {
+    srand(time(0));
+    int order[16];
+    int i;
+    for (i = 0; i < 16; i++) {
+        order[i] = i;
+    }
+    for (i = 0; i < 16; i++) {
+        swap(order + i, order + (rand() % (16-i)) + i);
+    }
+    for (i = 0; i < 16; i++) {
+        board[i] = dice[order[i]][rand() % 6];
+    }
+}
+
+
+
+void refresh_screen(int score, int bonus, char* prev, Client * p) {
+    char mes[256];
+    sprintf(mes, "Round %d\n", round_num);
+    sendclient(p, mes);
+    for (int i = 0; i < 4; ++i) {
+        for (int j = 0; j < 4; ++j) {
+            char arr[3];
+            arr[0] = (char)board[i*4+j];
+            arr[1] = ' ';
+            arr[2] = '\0';
+            sendclient(p, arr);
+        }
+        sendclient(p, "\n");
+    }
+    sprintf(mes, "Score: %d\n", score);
+    sendclient(p, mes);
+    if (bonus > 0) {
+        sprintf(mes, "Last Word: %s (%d points)\n", prev, bonus);
+        sendclient(p, mes);
+    }
+    else {
+        sprintf(mes, "%s\n", messages[0-bonus]);
+        sendclient(p, mes);
+    }
+}
+
+void get_info(struct client * p, char * mess){
+    char *after = p->buf + p->inbuf;
+    int room = BUFFER_SIZE - p->inbuf;
+    int nbytes;
+    if ((nbytes = read(p->fd, after, room)) > 0) {
+        p->inbuf += nbytes;
+        int where = find_network_newline(p->buf, p->inbuf);
+        if (where >= 0) {
+            p->buf[where] = '\0';
+            p->buf[where+1] = '\0';
+            strcpy(mess, p->buf);
+            where+=2;  
+            p->inbuf -= where;
+            memmove(p->buf, p->buf + where, p->inbuf);
+        }
+        room = sizeof(p->buf) - p->inbuf;
+        after = p->buf + p->inbuf;
+    } else {
+        remove_client(p->fd);
+    }
+}
+
+
+
+void handler(int code) {
+    if (code == SIGALRM) {
+    }
+    else if (code == SIGINT) {
+        scoreboard();
+        sendclient(&special_client, "Game Over\n");
+        write_users();
+        free_dictionaries();
+        free_players();
+        exit(0);
+    }
+}
+
+
+
+void start_game(Client * p){
+    score = 0;
+    old_score = 0;
+    skip = 0;
+
+    round_num++;
+    reset_words();
+    generate_board();
+    if (word_score > -4) {
+        word_score = -6;
+    }
+    refresh_screen(score, word_score, NULL, &special_client);
+
+
+    if (skip) {
+        word_score = verify_word(input);
+        if (word_score > 0) {
+            score += word_score;
+        }
+        refresh_screen(score, word_score, input, p);
+    }
+    else
+    {
+        skip = 1;
+    }
+    if (!(strcmp(input, "q") && strcmp(input, "u"))) {
+        if (input[0] == 'q') {
+            action = 0;
+        }
+        else {
+            action = 1;
+        }
+        update_scores(score, old_score);
+        scoreboard();
+        char mes[256];
+        sprintf(mes, "Type y to confirm %s.  Type anything else to cancel\n", actions[action]);
+        sendclient(p, mes);
+        get_info(p, input);
+        if (input[0] == 'y') {
+        }
+        else {
+            old_score = score;
+        }
+    }
+}
+
+void check_word(Client * p, char * input){
+    if (skip) {
+        word_score = verify_word(input);
+        if (word_score > 0) {
+            score += word_score;
+        }
+        refresh_screen(score, word_score, input, p);
+    }
+    else
+    {
+        skip = 1;
+    }
+    if (!(strcmp(input, "q") && strcmp(input, "u"))) {
+        if (input[0] == 'q') {
+            action = 0;
+        }
+        else {
+            action = 1;
+        }
+        update_scores(score, old_score);
+        scoreboard();
+        char mes[256];
+        sprintf(mes, "Type y to confirm %s.  Type anything else to cancel\n", actions[action]);
+        sendclient(p, mes);
+        get_info(p, input);
+        if (input[0] == 'y') {
+        }
+        else {
+            old_score = score;
+        }
+    }
+}
+
+void game(Client * p){
+    while (1) {
+        score = 0;
+        old_score = 0;
+        strcpy(input, "a");
+        raise(SIGALRM);
+        skip = 1;
+        while (1) {
+            get_info(p, input);
+            sendclient(p, p->buf);
+            if (skip) {
+                word_score = verify_word(input);
+                if (word_score > 0) {
+                    score += word_score;
+                }
+                refresh_screen(score, word_score, input, p);
+            }
+            else
+            {
+                skip = 1;
+            }
+            if (!(strcmp(input, "q") && strcmp(input, "u"))) {
+                if (input[0] == 'q') {
+                    action = 0;
+                }
+                else {
+                    action = 1;
+                }
+                update_scores(score, old_score);
+                scoreboard();
+                char mes[256];
+                sprintf(mes, "Type y to confirm %s.  Type anything else to cancel\n", actions[action]);
+                sendclient(p, mes);
+                get_info(p, input);
+                if (input[0] == 'y') {
+                    break;
+                }
+                else {
+                    old_score = score;
+                }
+            }
+        }
+        if (action == 0) {
+            raise(SIGINT);
+        }
+        else {
+            round_num = 0;
+        }
+    }
+}
+
+
+int main(int argc, char* argv[]) {
+    struct client *p;
+    if (argc > 1)
+        port = (short)(atoi(argv[1]));
+    else
+        port = PORT;
+
+    
+    listenfd = setup();
+
+    
+    struct sigaction alarm_handler;
+    alarm_handler.sa_handler = timer_handler;
+    sigemptyset(&alarm_handler.sa_mask);
+    alarm_handler.sa_flags = 0;
+    sigaction(SIGALRM, &alarm_handler, NULL);
+    struct timeval select_wait_length;
+    select_wait_length.tv_sec = TIMER_TICK - 1;
+    select_wait_length.tv_usec = 0;
+    
+
+    alarm(TIMER_TICK);
+    strcpy(input, "a");
+    initialzie_dictionary();
+    read_users();
+
+    newact.sa_handler = handler;
+    newact.sa_flags = 0;
+    sigemptyset(&newact.sa_mask);
+    sigaction(SIGALRM, &newact, NULL);
+    sigaction(SIGINT, &newact, NULL);
+
+    while(1){
+        fd_set fds_to_read;
+        FD_ZERO(&fds_to_read);
+        FD_SET(listenfd, &fds_to_read);
+        int fd_max = listenfd + 1;
+        Client* current_client = client_list;
+        while (current_client != NULL) {
+            FD_SET(current_client->fd, &fds_to_read);
+            if (current_client->fd + 1 > fd_max) {
+                fd_max = current_client->fd + 1;
+            }
+            current_client = current_client->next;
+        }
+        int select_return_value;
+        if ((select_return_value = select(fd_max, &fds_to_read, NULL, NULL, &select_wait_length)) < 0) {
+        } else if (select_return_value == 0) {
+            fprintf(stderr, "Select() Timed Out\n");
+        } else {
+            current_client = client_list;
+            while (current_client != NULL) {
+                if (FD_ISSET(current_client->fd, &fds_to_read)) {
+                    p = current_client;
+                    receiveclient(p, 0);
+
+                    break;
+                }
+                current_client = current_client->next;
+            }
+            if (FD_ISSET(listenfd, &fds_to_read)) {
+                new_connection(listenfd);
+            }
+        }
+        select_wait_length.tv_sec = TIMER_TICK - 1;
+        select_wait_length.tv_usec = 0;
+    }
+    return 0;
+}
+
+
+
+void timer_handler(int sig) {
+    
+    Client *curr;
+    for (curr = client_list; curr!=NULL; curr = curr->next) {
+        sendclient(curr, "Game over\r\n");
+    }
+
+    
+    alarm(TIMER_TICK);
+}
+
+
+
+int setup (void) {
+	int on = 1, status;
+	struct sockaddr_in self;
+	int listenfd;
+	if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+		perror("socket");
+		exit(1);
+	}
+
+	status = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
+                      (const char *) &on, sizeof(on));
+	if(status == -1) {
+		perror("setsockopt -- REUSEADDR");
+	}
+
+	memset(&self, '\0', sizeof(self));
+	self.sin_family = AF_INET;
+	self.sin_addr.s_addr = INADDR_ANY;
+	self.sin_port = htons(port);
+	printf("Listening on %d\n", port);
+
+	if (bind(listenfd, (struct sockaddr *)&self, sizeof(self)) == -1) {
+		perror("bind"); 
+		exit(1);
+	}
+
+	if (listen(listenfd, 5) == -1) {
+		perror("listen");
+		exit(1);
+	}
+  
+	return listenfd;
+}
+
+
+
+void add_client(int fd, struct in_addr addr){
+    struct client *p = (Client *)malloc(sizeof(struct client));
+    if (!p) {
+        perror("malloc failure");
+        exit(1);
+    }
+    printf("Adding client %s\n", inet_ntoa(addr));
+    fflush(stdout);
+    p->fd = fd;
+    p->state = NAME; 
+    p->inbuf = 0;
+
+    if (client_list == NULL) {
+        client_list = p;
+        p->next = NULL;
+        sendclient(p, "What is your player name?\n");
+        return;
+    }else{
+        Client * head = client_list;
+        while (head->next != NULL) {
+            head = head->next;
+        }
+        head->next = p;
+        p->next = NULL;
+        sendclient(p, "What is your player name?\n");
+    }
+}
+
+
+
+void new_connection (int listenfd)  {
+    int fd;
+    struct sockaddr_in r;
+    socklen_t socklen = sizeof(r);
+
+    if ((fd = accept(listenfd, (struct sockaddr *)&r, &socklen)) < 0) {
+        perror("accept");
+        return;
+    } 
+    
+    printf("connection from %s\n", inet_ntoa(r.sin_addr));
+    add_client(fd, r.sin_addr);    
+}
+
+
+
+char * int2str(int n) {
+    if (n == 0) {
+        return "0";
+    }
+    char * str = (char*)malloc(sizeof(char) * 256);
+    char buf[10] = "";
+    int i = 0;
+    int len = 0;
+    int temp = n < 0 ? -n : n;
+
+
+    if (str == NULL) {
+        return NULL;
+    }
+    while (temp) {
+        buf[i++] = (temp % 10) + '0';
+        temp = temp / 10;
+    }
+    len = n < 0 ? ++i : i;
+    str[i] = 0;
+    while (1) {
+        i--;
+        if (buf[len - i - 1] == 0) {
+            break;
+        }
+        str[i] = buf[len - i - 1];
+    }
+    if (i == 0) {
+        str[i] = '-';
+    }
+    return str;
+}
+
+
+void remove_client(int fd) {
+    fd_set fds_to_read;
+    FD_ZERO(&fds_to_read);
+    FD_SET(fd, &fds_to_read);
+    int fd_max = listenfd + 1;
+    Client* current_client = client_list;
+    while (current_client != NULL) {
+        FD_SET(current_client->fd, &fds_to_read);
+        if (current_client->fd + 1 > fd_max) {
+            fd_max = current_client->fd + 1;
+        }
+        current_client = current_client->next;
+    }
+    current_client = client_list;
+
+    Client * ct = current_client;
+    Client * p = NULL;
+    while (current_client != NULL) {
+        if (FD_ISSET(current_client->fd, &fds_to_read)) {
+            p = current_client;
+            receiveclient(p, 0);
+
+            break;
+        }
+        ct = current_client;
+        current_client = current_client->next;
+    }
+    if (ct == current_client) {
+        player_list = player_list->next;
+    } else if(current != NULL){
+        ct->next = current_client->next;
+    }
+
+}
+
+
+
+
+void receiveclient(struct client *p, int flag) {
+    char *after = p->buf + p->inbuf;
+    int room = BUFFER_SIZE - p->inbuf;
+    int nbytes;
+    if ((nbytes = read(p->fd, after, room)) > 0) {
+        p->inbuf += nbytes;
+        int where = find_network_newline(p->buf, p->inbuf);
+        if (where >= 0) {
+            p->buf[where] = '\0';
+            p->buf[where+1] = '\0';
+            interpret_message(p, flag);
+            where+=2;  // skip over \r\n
+            p->inbuf -= where;
+            memmove(p->buf, p->buf + where, p->inbuf);
+        }
+        room = sizeof(p->buf) - p->inbuf;
+        after = p->buf + p->inbuf;
+    } else {
+        remove_client(p->fd);
+    }
+}
+
+int create_player(const char * name, Player ** list) {
+
+    Player * p = (Player *)malloc(sizeof(Player));
+    strcpy(p->name, name);
+    p->max_score = 0;
+    p->total_score = 0;
+    p->total_games = 0;
+    p->next = NULL;
+    if (player_list == NULL) {
+        player_list = p;
+    } else {
+        Player * cur = player_list;
+        while (cur->next != NULL) {
+            cur = cur->next;
+        }
+        cur->next = p;
+    }
+    return 0;
+}
+
+
+void interpret_message(Client *p, int flag) {
+    char *buf;
+    if (p->state == NAME) {
+        strcpy(p->name, p->buf);
+        switch (create_player(p->name, &player_list)) {
+            case 1:
+                sendclient(p, "Welcome back.\r\n");
+                break;
+            case 2: 
+                asprintf(&buf, "Username too long, truncated to %d chars.\r\n", (MAX_NAME-1));
+                sendclient(p, buf);
+                break;
+            case 0: 
+                sendclient(p, "Welcome, new player\r\n");
+                break;
+        }
+        printf("Added %s to the client list\n",p->name);
+        p->state = COMMAND;
+        sendclient(p, "Go ahead and enter player commands>\r\n");
+    } else if (!strcmp(p->buf, "q")) {
+        remove_client(p->fd);
+        parse_line(p, flag);
+    } else {
+        parse_line(p, flag);
+    }
+}
+
+int parse_line(Client *p, int flag) {
+	char * input = p->buf;
+    
+
+    char *cmd_argv[INPUT_ARG_MAX_NUM];
+    int cmd_argc;
+
+
+    char *next_token = strtok(input, DELIM);
+    cmd_argc = 0;
+    while (next_token != NULL) {        
+        cmd_argv[cmd_argc] = next_token;
+        cmd_argc++;
+        next_token = strtok(NULL, DELIM);
+    }
+    return (cmd_argc > 0 && do_command(p, cmd_argc, cmd_argv, flag));
+}
+
+
+int sort_player_by_score(const void * a1, const void * a2){
+    Player * p1 = (Player *) a1;
+    Player * p2 = (Player *) a2;
+    if (p1->total_score < p2->total_score) {
+        return -1;
+    } else if (p1->total_score > p2->total_score){
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+void print_list(Player * playlist){
+    Player * cur = playlist;
+    while (cur !=  NULL) {
+        cur = cur->next;
+    }
+}
+
+Player* find_player(const char * name, const Player * head){
+    Player * cur = player_list;
+    while (cur != NULL) {
+        if (strcmp(cur->name, name)==0) {
+            return cur;
+        }
+        cur = cur->next;
+    }
+    return NULL;
+}
+
+
+int do_command(struct client * p, int cmd_argc, char **cmd_argv, int flag) {
+    if (flag == 1) {
+        char a[256];
+        strcat(a, "input over:");
+        strcat(a, cmd_argv[0]);
+        strcat(a, "\n");
+        sendclient(p, a);
+        return 0;
+    }
+    if (cmd_argc <= 0) {
+        return 0;
+    } else if (strcmp(cmd_argv[0], "q") == 0 && cmd_argc == 1) {
+        sendclient(p, "close the connection with server\n");
+        sendclient(p, "exit\n");
+        remove_client(p->fd);
+        return -1;
+    } else if (strcmp(cmd_argv[0], "all_players") == 0 && cmd_argc == 1) {
+
+        Player * head = player_list;
+        while (head != NULL){
+            sendclient(p, "username: ");
+            sendclient(p, head->name);
+            sendclient(p, "; max_score: ");
+            sendclient(p, int2str(head->max_score));
+            sendclient(p, "; total_score: ");
+            sendclient(p, int2str(head->total_score));
+            sendclient(p, "; total_games: ");
+            sendclient(p, int2str(head->total_games));
+            sendclient(p, "\n");
+            head = head->next;
+        }
+    } else if (strcmp(cmd_argv[0], "top_3") == 0 && cmd_argc == 1) {
+		
+		Player * head = player_list;
+		Player * ct = player_list;
+		int count = 0;
+		while (ct != NULL) {
+		    ct = ct->next;
+		    count ++;
+		}
+        qsort(head, count, sizeof(Player), sort_player_by_score);
+		char * message = (char *)malloc(sizeof(char) * 256);
+		int index = 1;
+		while (head != NULL) {
+		    strcat(message, int2str(index));
+		    strcat(message, ". ");
+            strcat(message, head->name);
+
+            strcat(message, " ");
+            strcat(message, int2str(head->total_score));
+            strcat(message, "\n");
+            index += 1;
+            head = head->next;
+		}
+		if(count == 0) {
+		    sendclient(p, "there no players\n");
+		} else {
+            sendclient(p, message);
+		}
+    } else if (strcmp(cmd_argv[0], "add_score") == 0 && cmd_argc == 2) {
+        char str [BUFFER_SIZE - 10];
+        int score =atoi(cmd_argv[1]);
+        sendclient(p, p->name);
+        print_list(player_list);
+        sendclient(p, "\n");
+        Player *player = find_player(p->name, player_list);
+        player->total_score+=score;
+        if (score > player->max_score)
+            player->max_score = score;               
+        sprintf (str, "added score %d for player %s\r\n", score, p->name);
+        sendclient(p, str);
+    } else if (strcmp(cmd_argv[0], "new_game") == 0 && cmd_argc == 1) {
+       
+        special_client = * p;
+        start_game(p);
+        if(player_list == NULL) {
+            printf("Playerlist is null\n");
+        }
+        Player * pl = player_list;
+        while (pl != NULL) {
+            if (strcmp(pl->name,p->name)==0){
+                break;
+            }
+            pl = pl->next;
+        }
+        pl->total_games += 1;
+        in_newgame = 1;
+    }else if(in_newgame == 0){
+        sendclient(p, "Incorrect syntax\r\n");
+    } else {
+        
+        word_score = verify_word(cmd_argv[0]);
+        if (word_score > 0) {
+            score += word_score;
+        }
+        refresh_screen(score, word_score, input, p);
+        Player *player = find_player(p->name, player_list);
+
+        player->total_score+=word_score;
+        if (score > player->max_score)
+            player->max_score = score;
+    }
+    return 0;
+}
+
+
+
+
+
+
+void sendclient(Client *p, char *msg) {
+    write(p->fd, msg, strlen(msg));
+}
+
+int find_network_newline(char *buf, int inbuf) {
+	int i;
+	for (i = 0; i < inbuf - 1; i++)
+		if ((buf[i] == '\r') && (buf[i + 1] == '\n'))
+			return i;
+	return -1;
+}
+
+
+
+
+
+
+
+
+
+

+ 74 - 0
game_server.h

@@ -0,0 +1,74 @@
+#ifndef GAME_SERVER_H
+#define GAME_SERVER_H
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/select.h>
+#include <signal.h>
+#include <sys/time.h>
+
+
+#ifndef PORT
+  #define PORT 8888
+#endif
+
+
+#define NAME 0		
+#define COMMAND 1
+
+#define DELIM " \n"
+
+#define TIMER_TICK 120
+#define MAX_NAME 10    
+#define INPUT_ARG_MAX_NUM 10
+
+#define BUFFER_SIZE 1024
+
+typedef struct client {
+    int fd;
+    int state; 
+    char name[MAX_NAME];
+    char buf[BUFFER_SIZE]; 
+    int inbuf;              
+    struct client *next;
+} Client;
+
+typedef struct player {
+    char name[MAX_NAME]; 
+    int max_score;
+    int total_games;
+    int total_score; 
+    struct player *next;
+} Player;
+
+
+//int create_player(const char *name, Player **player_ptr_add);
+
+//Player *find_player(const char *name, const Player *head);
+
+
+int setup (void);
+
+void timer_handler(int sig);
+
+void new_connection(int listenfd) ;
+
+void add_client(int fd, struct in_addr addr);
+
+void remove_client(int fd);
+
+void sendclient(Client *p, char *msg);
+void receiveclient(Client *p, int flag);
+
+
+void interpret_message(Client *p, int flag);
+
+int parse_line(Client *p, int flag);
+int do_command(struct client * p, int cmd_argc, char **cmd_argv, int flag);
+
+int find_network_newline(char *buf, int inbuf);
+
+#endif

BIN
user_data


+ 162 - 0
users.c

@@ -0,0 +1,162 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include "boggle4/utils.h"
+
+User *head;
+User *current;
+User *array_end;
+
+int total_users;
+
+int read_users() {
+  FILE *users_file;
+  int error;
+
+  users_file = fopen("user_data", "rb");
+  if (users_file == NULL) {
+      fprintf(stderr, "Error: could not open file\n");
+      return 1;
+  }
+
+  error = fread(&total_users, sizeof(int), 1, users_file);
+  if (error) {
+    User* buffer = malloc(total_users*sizeof(User));
+    fread(buffer, sizeof(User), total_users, users_file);
+    head = buffer;
+    User *temp = head;
+    for (int i = 1; i < total_users; i++) {
+      temp->next = buffer+i;
+      temp = buffer+i;
+    }
+    array_end = buffer + total_users - 1;
+  }
+  else
+  {
+    total_users = 0;
+    array_end = NULL;
+  }
+  error = fclose(users_file);
+  if (error != 0) {
+      fprintf(stderr, "Error: fclose failed\n");
+      return 1;
+  }
+  return 0;
+}
+
+int write_users() {
+  User *temp = head;
+  User buffer[total_users];
+  FILE *users_file;
+  int error;
+  users_file = fopen("user_data", "wb");
+  if (users_file == NULL) {
+    fprintf(stderr, "Error: could not open file\n");
+    return 1;
+  }
+  fwrite(&total_users, sizeof(int), 1, users_file);
+  for (int i = 0; i < total_users; i++) {
+    buffer[i] = *temp;
+    temp = temp->next;
+  }
+  error = fwrite(buffer, sizeof(User), total_users, users_file);
+  if (error != total_users) {
+    fprintf(stderr, "Error: fwrite failed\n");
+    return 1;
+  }
+  error = fclose(users_file);
+  if (error != 0) {
+      fprintf(stderr, "Error: fclose failed\n");
+      return 1;
+  }
+  return 0;
+}
+
+int login(Client * p) {
+  char name[9];
+  char c;
+  int invalid_input = 1;
+  system("clear");
+  while(invalid_input) {
+    printf("Username: ");
+    scanf("%8s", name);
+    invalid_input = 0;
+    for (int i = 0; i < strlen(name); i++) {
+      c = name[i];
+      if ((!isalnum(c)) && (c != '-') && (c != '_')) {
+        printf("Invlaid character: %c\n", c);
+        invalid_input = 1;
+      }
+    }
+  }
+
+  if (head == NULL) {
+    head = malloc(sizeof(User));
+    strcpy(head->name, name);
+    head->max_score = 0;
+    head->total_games = 0;
+    head->total_score = 0;
+    head->next = NULL;
+    current = head;
+    total_users++;
+    return -4;
+  }
+  else {
+    User *temp = head;
+    while(temp->next != NULL && strcmp(name, temp->name)) {
+      temp = temp->next;
+    }
+    if (strcmp(name, temp->name)) {
+      User* new_user = malloc(sizeof(User));
+      strcpy(new_user->name, name);
+      new_user->max_score = 0;
+      new_user->total_games = 0;
+      new_user->total_score = 0;
+      new_user->next = NULL;
+      temp->next = new_user;
+      current = new_user;
+      total_users++;
+      return -4;
+    }
+    else {
+      current = temp;
+      return -5;
+    }
+  }
+}
+
+void update_scores(int new_score, int old_score) {
+  if (new_score > current->max_score) {
+    current->max_score = new_score;
+  }
+  if (!old_score) {
+    current->total_games++;
+  }
+  current->total_score += new_score - old_score;
+}
+
+void scoreboard() {
+  system("clear");
+  User *temp = head;
+  printf("Name | Max Score | Total Games | Total Score\n");
+  while (temp) {
+    printf("%s, %d, %d, %d\n", temp->name, temp->max_score, temp->total_games, temp->total_score);
+    temp = temp->next;
+  }
+}
+
+void free_players() {
+  if (array_end) {
+    User *curr = array_end->next;
+  	User *temp;
+  	while(curr) {
+  		temp = curr->next;
+  		free(curr);
+  		curr = temp;
+    }
+  }
+  if (head) {
+    free(head);
+  }
+}

+ 79 - 0
utils.h

@@ -0,0 +1,79 @@
+#ifndef UTILS_H
+#define UTILS_H
+#define TIME_INTERVAL 60
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/select.h>
+#include <signal.h>
+#include <sys/time.h>
+#ifndef PORT
+  #define PORT 8888
+#endif
+#define NAME 0		//reflects 2 states of client connection: 0 - identification, 1 - identified, can enter commands
+#define COMMAND 1
+#define DELIM " \n"
+#define TIMER_TICK 120
+#define MAX_NAME 10     // Max playername length
+#define INPUT_ARG_MAX_NUM 10
+#define BUFFER_SIZE 1024
+
+//typedef struct client {
+////    int fd;
+////    int state; // either NAME or COMMAND
+////    char name[MAX_NAME];
+////    char buf[BUFFER_SIZE];  // each client has its own buffer
+////    int inbuf;              // and a personal pointer to the current place in buffer
+////    struct client *next;
+////} Client;
+////
+////typedef struct player {
+////    char name[MAX_NAME];
+////    int max_score;
+////    int total_games;
+////    int total_score;
+////    struct player *next;
+////} Player;
+//
+//int create_player(const char *name, Player **player_ptr_add);
+//Player *find_player(const char *name, const Player *head);
+int setup (void);
+void timer_handler(int sig);
+void new_connection(int listenfd) ;
+void add_client(int fd, struct in_addr addr);
+void remove_client(int fd);
+////void sendclient(Client *p, char *msg);
+////void receiveclient(Client *p);
+////void interpret_message(Client *p);
+////int parse_line(Client *p);
+////int do_command(struct client * p, int cmd_argc, char **cmd_argv);
+int find_network_newline(char *buf, int inbuf);
+//
+typedef struct user {
+	char name[9];
+    	int max_score;
+      	int total_games;
+        int total_score;
+        struct user * next;
+} User;
+User *head;
+User *current;
+User *array_end;
+
+      int board[16];
+
+          int login();
+          int verify_word(char* word);
+          void scoreboard();
+          int initialzie_dictionary();
+          void update_scores(int new_score, int old_score);
+          void free_dictionaries();
+          void free_players();
+          void reset_words();
+          int write_users();
+          int read_users();
+
+         #endif

File diff suppressed because it is too large
+ 276643 - 0
wordlist.txt