Lab 4 Part 1 : Let's Play Boggle

Deadlines

The deadline for odd-numbered groups is Tuesday 26 October 2004, 23:59:59 hours.
The deadline for even-numbered groups is Tuesday 2 November 2004, 23:59:59 hours.
Submission for even-numbered groups will not be available on Wednesday 27 October 2004 (due to the lab that is going on for odd-week).

Your file must be named boggle.c, incorrect filename will result in zero marks. This part of the lab is worth one mark.
You are strongly advised to complete and understand part 1.

Overview

As a grand finale to your labs, we'll apply all that we have learnt in this course and design a program for playing the classic Boggle game. The game of Boggle is played with a 4 x 4 tray filled with 16 random letters (not necessarily unique). The objective of the game is to form words by concatenating adjacent letters with the following rules of the game.

As an example, consider the following tray with 16 random letters.
   +---+---+---+---+
   | Y | A | T | R |
   +---+---+---+---+
   | P | H | N | E |
   +---+---+---+---+
   | X | C | E | Y |
   +---+---+---+---+
   | S | V | L | Q |
   +---+---+---+---+
Here are some words that can be found: Here are some words that are not valid in this puzzle:

Getting Started

We need to implement two main objects. The first object is the tray that is simulated using a two dimensional square array of a pre-defined size (usually four). Each element of the tray is a C structure of type Cell with the following members:
   typedef struct {
      char  letter;
      short visited;
   } Cell;
The tray is declared in the main function as Cell tray[SIZE][SIZE] with SIZE defined as a constant.

The second object is the dictionary which is realized using a linked list where each node refers to a single word. This is by far one of the worst implementations for the dictionary. But what to do? You have to learn how to construct linked lists anyway. The C structure WordNode for each node, together with their corresponding type definitions, is implemented as shown below. A separate but similar linked list structure will also be used to keep track of the list of words that have been found during the game.

   typedef struct WordStruct WordNode;
   typedef WordNode *WordPtr;
   struct WordStruct {
      char *word;
      WordPtr next;
   };

Your task is to design a program that allows the user to play a single game of Boggle. The program will terminate when the user enters any number. The skeleton code is provided below with details on the specific implementation.

Skeleton

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

#define SIZE 4
/**
   The constant SIZE can be defined to suit your needs.
   It need not necessarily denote the actual size of the tray.
**/

#define FILENAME "/usr/share/lib/dict/words"
/**
   The filename indicated above is the dictionary provided in sunfire.
   If you need an exact copy, you can download from here (right-click
   and choose "Save Link As... or Save Target As...")
   http://www.comp.nus.edu.sg/~cs1101cl/lab4/part1/words.txt
**/

typedef struct WordStruct WordNode;
typedef WordNode *WordPtr;
struct WordStruct {
   char *word;
   WordPtr next;
};

typedef struct {
   char letter;
   int  visited;
} Cell;


/**
   Function Prototypes.
   Please refer to the individual functions below for implementation details.
**/
void PlayBoggle(Cell [][], WordPtr);
void InitTray(Cell [][]);
void ResetFlag(Cell [][]);
void ReadDictionary(WordPtr *);
void AddWord(WordPtr *, char *);
void PrintTray(Cell [][]);
void PrintList(WordPtr);
int WordInTray(Cell [][], char *);
int WordInList(WordPtr, char *);


/**
   Function that plays the Boggle game.
   DO NOT MODIFY THE CODE.
**/
int main()
{
   Cell tray[SIZE][SIZE];   /* 2D array representation for the tray    */
   WordPtr dict;            /* Head of the dictionary linked list      */

   ReadDictionary(&dict);   /* Read in the dictionary as a linked list */

   PlayBoggle(tray,dict);   /* Play a single game of Boggle            */
}


/**
   Function that plays a single game of Boggle with the randomized tray
   and the dictionary linked list.
   Understand how the different sub functions are invoked and used.
   DO NOT MODIFY THE CODE.
**/
void PlayBoggle(Cell tray[][SIZE], WordPtr dict)
{
   char word[101];
   WordPtr wordList = NULL;

   /* Initialize the tray with random letters */
   InitTray(tray);
   /* Display the tray with letters */
   PrintTray(tray);

   /* Read in a word */
   printf("\nEnter word (any number to quit): ");
   gets(word);

   /*
      Check if a word has its first char as a digit.
      If yes, then terminate the loop
   */
   while (!isdigit(word[0]))
   {
      /* Reset the visited flag of all the cells on the tray */
      ResetFlag(tray);

      /* Condition 1: A word should be 3 letters or more */
      if (strlen(word) > 2)

         /* Condition 2: Check if the word can be found on the tray */
         if (WordInTray(tray,word))

            /* Condition 3: Check if the word is in the dictionary */
            if (WordInList(dict, word))

               /* Condition 4: Check if the word has been previously found */
               if (!WordInList(wordList,word))
               {
                  /* Add the valid word into the list of found words */
                  AddWord(&wordList,word);

                  /* Print the list of words already found */
                  printf("\n--- Word(s) Found ---\n");
                  PrintList(wordList);
                  printf("---------------------\n\n");

                  /* Display the tray with letters again */
                  PrintTray(tray);
               }
               else
                  printf("\"%s\" has already been found\n", word);
            else
               printf("\"%s\" is not found in the dictionary\n", word);
         else
            printf("\"%s\" is not found on the tray\n", word);
      else
         printf("Word must be at least 3 letters\n");

      /* Read in another word */
      printf("\nEnter another word (any number to quit): ");
      gets(word);
   }
   printf("\nProgram Terminated...\n");
}


/**
   This function initializes the tray with random letters.
   To simplify the implementation, each cell is simply randomized with any
   of the 26 capital letters from the alphabet.
**/
void InitTray(Cell tray[][SIZE])
{
   /* Enter your code here */
}


/**
   This function clears the visited flag (i.e. assign with zero) in all
   cells of the tray. The flags need to be cleared before we begin
   looking for a new word on the tray.
**/
void ResetFlag(Cell tray[][SIZE])
{
   /* Enter your code here */
}


/**
   Read the dictionary file and represent each word as a node of the linked list dict.
   In each node, you need to dynamically allocate an array for storing the word.
   The code for reading each word from the dictionary is given below. In each loop,
   a new word from the dictionary is stored into the variable word.
   You task is to create the desired linked list. You can assume that the
   file that is read is already in proper sorted order.
**/
void ReadDictionary(WordPtr *dict)
{
   char word[101];
   FILE *filein;
   /** include other variables **/

   if ( (filein = fopen(FILENAME, "r")) == NULL )
   {
      fprintf(stderr, "Error reading file\n");
      exit(1);
   }

   fscanf(filein, "%s", word);
   while (!feof(filein))
   {
      /**
         include the code to store a copy of word
         into a node in the linked list.
      **/

      fscanf(filein, "%s", word);
   }

   fclose(filein);
}


/**
   Function that inserts a node representing the word at the appropriate
   position in the linked list wordList.
   In each node, you need to dynamically allocate an array for storing the word.
   The linked list must always be maintained in a sorted order.
**/
void AddWord(WordPtr *wordList, char *word)
{
   /* Enter your code here */
}


/**
   This function prints the tray according to the following format:

   +---+---+---+---+
   | Y | A | T | R |
   +---+---+---+---+
   | P | H | N | E |
   +---+---+---+---+
   | X | C | E | Y |
   +---+---+---+---+
   | S | V | L | Q |
   +---+---+---+---+
**/
void PrintTray(Cell tray[][SIZE])
{
   /* Enter your code here */
}


/**
   Print the linked list, wordList, of words.
**/
void PrintList(WordPtr wordList)
{
   /* Enter your code here */
}


/**
   Function that checks the existence of a word on the tray.
   This function is case-insensitive.
   Function returns 1 if the word is found; 0 otherwise.

   Hint: One way is to invoke another function (probably recursive) to
         check the existence of the word beginning with a particular
         cell of the tray.
**/
int WordInTray(Cell tray[][SIZE], char *word)
{
   /* Enter your code here */
}


/**
   Function that performs a linear search on the linked list
   wordList and checks the existence of the word.
   This function is case-insensitive.
   Function returns 1 if the word is found; 0 otherwise.
**/
int WordInList(WordPtr wordList, char *word)
{
   /* Enter your code here */
}

Sample Output

helloKitty@sf3:~[123]$ gcc boggle.c
helloKitty@sf3:~[124]$ a.out
+---+---+---+---+
| S | Q | E | T |
+---+---+---+---+
| N | E | N | I |
+---+---+---+---+
| N | O | A | L |
+---+---+---+---+
| I | C | L | Y |
+---+---+---+---+

Enter word (any number to quit): la
Word must be at least 3 letters

Enter another word (any number to quit): lan
"lan" is not found in the dictionary

Enter another word (any number to quit): lane

--- Word(s) Found ---
1       lane
---------------------

+---+---+---+---+
| S | Q | E | T |
+---+---+---+---+
| N | E | N | I |
+---+---+---+---+
| N | O | A | L |
+---+---+---+---+
| I | C | L | Y |
+---+---+---+---+

Enter another word (any number to quit): nine
"nine" is not found on the tray

Enter another word (any number to quit): line

--- Word(s) Found ---
1       lane
2       line
---------------------

+---+---+---+---+
| S | Q | E | T |
+---+---+---+---+
| N | E | N | I |
+---+---+---+---+
| N | O | A | L |
+---+---+---+---+
| I | C | L | Y |
+---+---+---+---+

Enter another word (any number to quit): cane

--- Word(s) Found ---
1       cane
2       lane
3       line
---------------------

+---+---+---+---+
| S | Q | E | T |
+---+---+---+---+
| N | E | N | I |
+---+---+---+---+
| N | O | A | L |
+---+---+---+---+
| I | C | L | Y |
+---+---+---+---+

Enter another word (any number to quit): lane
"lane" has already been found

Enter another word (any number to quit): queen

--- Word(s) Found ---
1       cane
2       lane
3       line
4       queen
---------------------

+---+---+---+---+
| S | Q | E | T |
+---+---+---+---+
| N | E | N | I |
+---+---+---+---+
| N | O | A | L |
+---+---+---+---+
| I | C | L | Y |
+---+---+---+---+

Enter another word (any number to quit): inconsequential

--- Word(s) Found ---
1       cane
2       inconsequential
3       lane
4       line
5       queen
---------------------

+---+---+---+---+
| S | Q | E | T |
+---+---+---+---+
| N | E | N | I |
+---+---+---+---+
| N | O | A | L |
+---+---+---+---+
| I | C | L | Y |
+---+---+---+---+

Enter another word (any number to quit): inconsequentially
"inconsequentially" is not found in the dictionary

Enter another word (any number to quit): 123

Program Terminated...
helloKitty@sf3:~[125]$