Akarsh Balaji 1 year ago
commit
f2f3a3828a
12 changed files with 995 additions and 0 deletions
  1. 19 0
      Makefile
  2. BIN
      demo_server
  3. 70 0
      dictionary.c
  4. 22 0
      dictionary.h
  5. 161 0
      game.c
  6. 258 0
      game_server.c
  7. 110 0
      game_server.h
  8. 23 0
      players.c
  9. BIN
      user_data
  10. 162 0
      users.c
  11. 27 0
      utils.h
  12. 143 0
      words.c

+ 19 - 0
Makefile

@@ -0,0 +1,19 @@
+CC = gcc
+CFLAGS = -Wall -std=gnu99
+
+default: boggle
+
+boggle: game.o words.o users.o dictionary.o
+	$(CC) $(CFLAGS) -o boggle game.o words.o users.o dictionary.o
+
+game.o: game.c utils.h
+	$(CC) $(CFLAGS) -c game.c
+words.o: words.c utils.h dictionary.h
+	$(CC) $(CFLAGS) -c words.c dictionary.c
+users.o: users.c utils.h
+	$(CC) $(CFLAGS) -c users.c
+dictionary.o: dictionary.c
+	$(CC) $(CFLAGS) -c dictionary.c
+
+clean:
+	rm game.o words.o users.o

BIN
demo_server


+ 70 - 0
dictionary.c

@@ -0,0 +1,70 @@
+
+#include <string.h>
+#include "dictionary.h"
+
+
+unsigned hash(const char *s) {
+	unsigned hashval;
+	for (hashval = 0; *s != '\0'; s++)
+		hashval = *s + 31 * hashval;
+	return hashval ;
+}
+
+
+DNode * lookup (DNode ** dictionary, int hash_size, const char *key) {
+	DNode * np;
+	unsigned int hashval = hash(key);
+	for (np = dictionary [hashval % hash_size]; np !=NULL; np = np->next)
+		if (strcmp (key, np->key) == 0)
+			return np; //found
+	return NULL; //not found
+}
+
+DNode * insert (DNode ** dictionary, int hash_size,  const char * key) {
+	unsigned int hashval;
+	DNode *np;
+
+	if ((np = lookup (dictionary, hash_size, key)) == NULL ) { //
+		np = (DNode *) malloc (sizeof (*np));
+
+		if (np == NULL || (np->key = copystr (key)) == NULL)
+			return NULL;
+
+		hashval = hash (key) % hash_size;
+
+		//now links itself on top of array entry
+		np->next = dictionary [hashval];
+		dictionary [hashval] = np;
+	}
+	return np;
+}
+
+void free_dictionary (DNode ** dictionary, int hash_size) {
+	int i;
+	for (i=0; i<hash_size; i++) { //iterate over hash array
+		if (dictionary [i]!=NULL) { //if there is an entry at position i
+			DNode *head = dictionary[i]; //find the head of the linked list
+			DNode *current = head;
+			while (current != NULL) {
+				DNode * temp = current;
+				current = current->next;
+                if (temp->key !=NULL)
+                    free (temp->key);
+				free (temp);
+			}
+			dictionary[i] = NULL;  //BUG fix
+		}
+	}
+}
+
+char *copystr(const char *s) { /* make a duplicate of s */
+	char *p;
+	int len = strlen(s);
+
+	p = (char *) malloc(len+1); /* +1 for �\0� */
+	if (p != NULL)
+		strncpy(p, s, len);
+	p[len] = '\0';
+
+	return p;
+}

+ 22 - 0
dictionary.h

@@ -0,0 +1,22 @@
+#ifndef DICTIONARY_H
+#define DICTIONARY_H
+
+#include <stdlib.h>
+#define BIG_HASH_SIZE 20000
+#define SMALL_HASH_SIZE 100
+
+typedef struct d_node {
+	char* key;
+    struct d_node *next;
+}DNode;
+
+char * copystr (const char *);
+unsigned hash(const char *s);
+
+DNode * lookup (DNode ** dictionary, int hash_size, const char *key);
+
+DNode * insert (DNode ** dictionary, int hash_size, const char * key);
+
+void free_dictionary (DNode ** dictionary, int hash_size);
+
+#endif

+ 161 - 0
game.c

@@ -0,0 +1,161 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include <signal.h>
+#include <unistd.h>
+#include "utils.h"
+
+int round_num;
+int score;
+int word_score;
+int old_score;
+int skip;
+
+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"};
+
+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) {
+  system("clear");
+  printf("Round %d\n", round_num);
+  for (int i = 0; i < 4; i++) {
+    for (int j = 0; j < 4; j++) {
+      printf("%c ", board[4*i+j]);
+    }
+    printf("\n");
+  }
+  printf("Score: %d\n", score);
+  if (bonus > 0) {
+    printf("Last Word: %s (%d points)\n", prev, bonus);
+  }
+  else {
+    printf("%s\n", messages[0-bonus]);
+  }
+}
+
+void handler(int code) {
+  if (code == SIGALRM) {
+    round_num++;
+    reset_words();
+    generate_board();
+    if (word_score > -4) {
+      word_score = -6;
+    }
+    refresh_screen(score, word_score, NULL);
+    skip = 0;
+    alarm(TIME_INTERVAL);
+  }
+  else if (code == SIGINT) {
+    system("clear");
+    scoreboard();
+    printf("Game Over\n");
+    write_users();
+    free_dictionaries();
+    free_players();
+    exit(0);
+  }
+}
+
+int main() {
+  int action;
+  char input[17];
+  strcpy(input, "a");
+  initialzie_dictionary();
+  read_users();
+  struct sigaction newact;
+  newact.sa_handler = handler;
+  newact.sa_flags = 0;
+  sigemptyset(&newact.sa_mask);
+  sigaction(SIGALRM, &newact, NULL);
+  sigaction(SIGINT, &newact, NULL);
+  word_score = login();
+  skip = 0;
+  round_num = 0;
+
+  while (1) {
+    score = 0;
+    old_score = 0;
+    strcpy(input, "a");
+    raise(SIGALRM);
+    skip = 1;
+    while (1) {
+      scanf("%16s", input);
+      if (skip) {
+        word_score = verify_word(input);
+        if (word_score > 0) {
+          score += word_score;
+        }
+        refresh_screen(score, word_score, input);
+      }
+      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();
+        printf("Type y to confirm %s.  Type anything else to cancel\n", actions[action]);
+        scanf("%1s", input);
+        if (input[0] == 'y') {
+          break;
+        }
+        else {
+          old_score = score;
+        }
+      }
+    }
+    if (action == 0) {
+      raise(SIGINT);
+    }
+    else {
+      word_score = login();
+      round_num = 0;
+    }
+  }
+}

+ 258 - 0
game_server.c

@@ -0,0 +1,258 @@
+#define _GNU_SOURCE 
+#include "game_server.h"
+
+Player *player_list = NULL;
+
+Client *client_list = NULL;
+
+short port = -1;
+
+int main(int argc, char* argv[]) {
+    struct client *p;
+	if (argc > 1)
+		port = (short)(atoi(argv[1]));
+	else
+		port = PORT;
+	
+	//get listen file descriptor
+    int listenfd = setup();
+    
+    //TODO install timer signal handler
+   
+	//start timer
+    alarm(TIMER_TICK);
+
+	//TODO: implement select()
+    while (1) {
+        
+    }
+    return 0;
+}
+
+/*
+ * Sets up server socket: bind and listen
+ * Returns a file descriptor for listening and accepting new connections
+ */
+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"); // probably means port is in use
+		exit(1);
+	}
+
+	if (listen(listenfd, 5) == -1) {
+		perror("listen");
+		exit(1);
+	}
+  
+	return listenfd;
+}
+
+
+/* timer signal handler */
+void timer_handler(int sig) {
+	//broadcast current game end to all connected clients
+	Client *curr;
+	for (curr = top; curr!=NULL; curr = curr->next) {
+            sendclient(curr, "Game over\r\n");
+    }
+	
+	//TODO - generate new game board
+	
+	//reset the timer so we get called again in 120 seconds
+	alarm(TIMER_TICK);
+}
+
+/* accepts new connection and adds a client-specific fd */
+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);    
+}
+
+/* creates a new client struct and 
+TODO - adds it to the list of clients */
+void add_client(int fd, struct in_addr addr){
+    struct client *p = 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; //needs yet to identify new client by name
+    p->inbuf = 0;
+    //TODO - add it to the list of clients
+
+    
+	sendclient(p, "What is your player name?\n");
+}
+
+
+void receiveclient(struct client *p) {
+    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);
+            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);
+    }
+}
+
+/*
+ * Acts according to the client state
+ */
+void interpret_message(Client *p) {
+    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);
+    } else {
+        parse_line(p, &player_list);
+    }
+}
+
+int parse_line(Client *p) {
+	char * input = p->buf;
+    
+	// cmd_argv will held arguments to individual commands passed to sub-procedure
+    char *cmd_argv[INPUT_ARG_MAX_NUM];
+    int cmd_argc;
+
+    // tokenize arguments
+    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));
+}
+
+/* 
+ * Process player commands
+ * Return:  -1 for quit command
+ *          0 otherwise
+ */
+int do_command(struct client * p, int cmd_argc, char **cmd_argv) {
+   
+    if (cmd_argc <= 0) {
+        return 0;
+    } else if (strcmp(cmd_argv[0], "q") == 0 && cmd_argc == 1) {
+        return -1;
+    } else if (strcmp(cmd_argv[0], "all_players") == 0 && cmd_argc == 1) {
+		//TODO produce list of all players and their stats in nice text format and sendclient
+        
+    } else if (strcmp(cmd_argv[0], "top_3") == 0 && cmd_argc == 1) {
+		//TODO produce list of top 3 players with their total score and sentclient as a text
+       
+    } else if (strcmp(cmd_argv[0], "add_score") == 0 && cmd_argc == 2) {
+        char str [BUFFER_SIZE - 10];
+        int score =atoi(cmd_argv[1]);
+        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) {
+        //TODO -- transmit current board to be presented as a 2D array of chars
+    }else {
+        sendclient(p, "Incorrect syntax\r\n");
+    }
+    return 0;
+}
+
+
+
+
+
+   
+
+
+
+
+void sendclient(struct client *p, char *msg) {
+    write(p->fd, msg, strlen(msg));
+}
+
+
+/*
+ * Search the first inbuf characters of buf for a network newline.
+ * Return the location of the '\r' if the network newline is found, or -1 otherwise.
+ */
+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;
+}
+
+
+
+
+
+
+
+

+ 110 - 0
game_server.h

@@ -0,0 +1,110 @@
+#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		//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
+
+//Node for the linked list which stores currently connected clients
+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;
+
+//Node for linked list which stores all players ever played - these are never removed
+typedef struct player {
+    char name[MAX_NAME]; 
+    int max_score;
+    int total_games;
+    int total_score; 
+    struct player *next;
+} Player;
+
+
+//=====================================
+// These are implemented in players.c
+//=====================================
+
+/*
+ * Create a new player with the given name.  Insert it at the tail of the list
+ * of players whose head is pointed to by *player_ptr_add.
+ *
+ * Return:
+ *   - 0 if successful
+ *   - 1 if a player by this name already exists in this list
+ *   - 2 if the given name cannot fit in the 'name' array 
+ *   - in this case truncate the name (don't forget about the null terminator), 
+ *		add to the list, and return 2 to send message to the client that name was truncated.
+ *       
+ */
+int create_player(const char *name, Player **player_ptr_add);
+
+
+/*
+ * Return a pointer to the player with this name in
+ * the list starting with head. Return NULL if no such player exists.
+ *
+ * NOTE: You'll likely need to cast a (const Player *) to a (Player *)
+ * to satisfy the prototype without warnings.
+ */
+Player *find_player(const char *name, const Player *head);
+
+
+//=====================================
+// These implemented in game_server.c
+//=====================================
+
+/*
+ * Sets up server socket: bind and listen
+ * Returns a file descriptor for listening and accepting new connections
+ */
+int setup (void);
+
+void timer_handler(int sig);
+
+/* accept new connection and calls add_client */
+void new_connection(int listenfd) ;
+
+/* Sets up Client fields, add to the list, and ask for the name */
+void add_client(int fd, struct in_addr addr);
+/* remove client from the list */
+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);
+
+#endif

+ 23 - 0
players.c

@@ -0,0 +1,23 @@
+#define _GNU_SOURCE 
+#include "game_server.h"
+
+
+//TODO - implement this
+/*
+ * Create a new player with the given name.  Insert it at the tail of the list
+ * of players whose head is pointed to by *player_ptr_add.
+ */
+int create_player(const char *name, Player **player_ptr_add) {
+   return 0;
+}
+
+//TODO - implement this
+/* 
+ * Return a pointer to the player with this name in
+ * the list starting with head. Return NULL if no such player exists. 
+ */
+Player *find_player(const char *name, const Player *head) {    
+    return NULL;
+}
+
+

BIN
user_data


+ 162 - 0
users.c

@@ -0,0 +1,162 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include "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() {
+  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);
+  }
+}

+ 27 - 0
utils.h

@@ -0,0 +1,27 @@
+#ifndef UTILS_H
+#define UTILS_H
+
+#define TIME_INTERVAL 60
+
+typedef struct user {
+  char name[9];
+  int max_score;
+  int total_games;
+  int total_score;
+  struct user * next;
+} User;
+
+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

+ 143 - 0
words.c

@@ -0,0 +1,143 @@
+#include "dictionary.h"
+#include "utils.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#define MAX_LINE 100
+
+
+int scores[5] = {1, 1, 2, 3, 5};
+int used[16];
+static DNode* dictionary [BIG_HASH_SIZE];
+static DNode* submitted_words [BIG_HASH_SIZE];
+DNode* result;
+
+int initialzie_dictionary() {
+	FILE *input_FP;
+	char line [MAX_LINE];
+	char * file_name;
+
+	file_name = "wordlist.txt";
+
+	if(!(input_FP = fopen ( file_name , "r" )))    {
+        fprintf(stderr,"Could not open file \"%s\" for reading dictionary words\n", file_name);
+        return 1;
+    }
+
+	while( fgets (line, MAX_LINE, input_FP)!=NULL ) {
+		line[strcspn(line, "\r\n")] = '\0';  //trim new line characters
+		insert (dictionary, BIG_HASH_SIZE, line);
+	}
+	fclose (input_FP);
+  return 0;
+}
+
+int search(char* word, int place, int depth) {
+  if (depth == strlen(word)) {
+    return 1;
+  }
+  else if (board[place] == word[depth] && !used[place]) {
+    used[place] = 1;
+    if (place%4) {
+      if (search(word, place-1, depth+1)) {
+        return 1;
+      }
+      if (place > 3) {
+        if (search(word, place-5, depth+1)) {
+          return 1;
+        }
+      }
+      if (place < 12)  {
+        if (search(word, place+3, depth+1)) {
+          return 1;
+        }
+      }
+    }
+
+    if (place%4 != 3) {
+      if (search(word, place+1, depth+1)) {
+        return 1;
+      }
+      if (place > 3) {
+        if (search(word, place-3, depth+1)) {
+          return 1;
+        }
+      }
+      if (place < 12) {
+        if (search(word, place+5, depth+1)) {
+          return 1;
+        }
+      }
+    }
+
+    if (place > 3) {
+      if (search(word, place-4, depth+1)) {
+        return 1;
+      }
+    }
+    if (place < 12) {
+      if (search(word, place+4, depth+1)) {
+        return 1;
+      }
+    }
+    used[place] = 0;
+    return 0;
+  }
+  else {
+    return 0;
+  }
+}
+
+int in_dictionary(char* word) {
+  result = lookup (dictionary, BIG_HASH_SIZE, word);
+	return result != NULL;
+}
+
+int already_submitted(char* word) {
+  result = lookup(submitted_words, BIG_HASH_SIZE, word);
+  return result != NULL;
+}
+
+int verify_word(char* word) {
+
+  int len = strlen(word);
+  if (len < 3) {
+    return 0;
+  }
+  for (int i = 0; i < len; i++) {
+    word[i] = toupper(word[i]);
+  }
+  if (already_submitted(word)) {
+    return -1;
+  }
+  else if (in_dictionary(word)) {
+    for (int i = 0; i < 16; i++) {
+      if (board[i] == word[0]) {
+        for (int j = 0; j < 16; j++) {
+          used[j] = 0;
+        }
+        if (search(word, i, 0)) {
+          insert (submitted_words, BIG_HASH_SIZE, word);
+          if (len > 7) {
+            return 11;
+          }
+          else {
+            return scores[len-3];
+          }
+        }
+      }
+    }
+    return -2;
+  }
+  return -3;
+}
+
+void reset_words() {
+	free_dictionary(submitted_words, BIG_HASH_SIZE);
+}
+
+void free_dictionaries() {
+  free_dictionary(dictionary, BIG_HASH_SIZE);
+	reset_words();
+}