/* CITS1210 Project 1 Names: Tom Martin, Harrison Sweeney Student numbers: ########, 20367988 Date: <Submission Date> */#include <stdio.h>#include <stdlib.h>#include <stdbool.h>#include <string.h>#include <ctype.h>/****************************************************************//* Constants and structure definitions *//* The maximum size of the wordsquare */#define MAXSIZE 50/* Structure to hold information about the wordsquare */typedef struct { /* The letters making up the wordsquare */ char grid[MAXSIZE][MAXSIZE]; /* The number of rows in the wordsquare */ int nRows; /* The number of columns in the wordsquare */ int nCols; } WORDSQUARE;/* The number of different search directions */#define NSEARCHDIRECTIONS 8/* Enumeration for the possible search directions */typedef enum {UP, DIAGUPRIGHT, RIGHT, DIAGDOWNRIGHT, DOWN, DIAGDOWNLEFT, LEFT, DIAGUPLEFT} DIRECTION;/* Structure to hold information about the location of a search position */typedef struct { /* The row number, starting from 0 */ int row; /* The column number, starting from 0 */ int col; } LOCATION;/* Structure to hold information about movement amounts in a single step of the searching process */typedef struct { /* The amount to move in the row-direction: either -1, 0, or 1 depending on the direction of the search */ int deltaRow; /* The amount to move in the column-direction: either -1, 0, or 1 depending on the direction of the search */ int deltaColumn; } MOVEAMOUNT;/* The search direction character denoting all search directions */#define ALLDIRECTIONSCHAR '5'/* Structure to hold information about the search directions to use in searching for a word in the wordsquare */typedef struct { int nDirections; DIRECTION dirs[NSEARCHDIRECTIONS]; } SEARCHDIRECTIONS;/****************************************************************//* Global variable definitions *//* You should not need to add to this list *//* The wordsquare puzzle global variable */WORDSQUARE ws;/****************************************************************//* Functions *//* isValidGridEntry(c) returns true iff c is a valid character that can appear in a grid-file. */static bool isValidGridEntry(char c){ return islower(c);}/* trimLine(line) removes any trailing new-line or carriage-return characters from the end of line. */static void trimLine(char line[]){ int i = 0; while(line[i] != '\0') { if(line[i] == '\r' || line[i] == '\n') { line[i] = '\0'; break; } i = i+1; }}/* readGrid(filename) reads the contents of the file named filename as a grid-file, "filling" the grid global variable with information read from the file. The function terminates the program if the file is not a valid grid-file or if the corresponding wordsquare would be too large to store in the ws global variable. */static void readGrid(char filename[]){}/* isValidLocation(loc) returns true iff loc represents a location within the wordsquare. */static bool isValidLocation(LOCATION loc){ if (loc.row < ws.nRows && loc.col < ws.nCols) { return true; } return false;}/* getValue(loc) returns the character occupying location loc in the wordsquare. The function terminates the program if the location is not valid (i.e. outside the bounds of the wordsquare). */static char getValue(LOCATION loc){ if (!isValidLocation(loc)) { fprintf(stderr, "Error: Invalid location supplied to getValue\n"); exit(EXIT_FAILURE); } return ws.grid[loc.row][loc.col];}/* display(void) displays the contents of the wordsquare. */static void display(void){ // This may not work, was just a guess.... printf("%dx%d\n", ws.nRows, ws.nCols); int i = 0; while (i < ws.nRows) { int j = 0; while (j < ws.nCols) { printf("%c\n", ws.grid[i][j]); i++; } } printf("\n");}/* move(dir) returns a MOVEAMOUNT structure that indicates how much to vary an iteration through the rows and columns of the wordsquare for a single step of the searching process when searching in the dir direction. e.g. move(UP)={-1,0}; move(RIGHT)={0,1}; move(DIAGUPLEFT)={-1,-1} */static MOVEAMOUNT move(DIRECTION dir){ //Dunno bout the default value at the bottom....also he mightn't like this formatting.. MOVEAMOUNT mv; if (dir == UP) { mv.deltaRow = -1; mv.deltaColumn = 0; } else if (dir == RIGHT) { mv.deltaRow = 0; mv.deltaColumn = 1; } else if (dir == DOWN) { mv.deltaRow = 1; mv.deltaColumn = 0; } else if (dir == LEFT) { mv.deltaRow = 0; mv.deltaColumn = -1; } else if (dir == DIAGUPLEFT) { mv.deltaRow = -1; mv.deltaColumn = -1; } else if (dir == DIAGUPRIGHT) { mv.deltaRow = -1; mv.deltaColumn = 1; } else if (dir == DIAGDOWNRIGHT) { mv.deltaRow = 1; mv.deltaColumn = 1; } else if (dir == DIAGDOWNLEFT) { mv.deltaRow = 1; mv.deltaColumn = -1; } else { mv.deltaRow = 0; mv.deltaColumn = 0; } return mv;}/* isMatch(c, loc) returns true iff c matches the (potentially highlighted) character occupying location loc in the wordsquare. The function terminates the program if the location is not valid (i.e. outside the bounds of the wordsquare). */static bool isMatch(char c, LOCATION loc){ if (!isValidLocation(loc)) { fprintf(stderr, "Error: Invalid location supplied to isMatch\n"); exit(EXIT_FAILURE); } if (ws.grid[loc.row][loc.col] == c) { return true; } return false;}/* searchForm(word, loc, dir) returns true iff word appears in the wordsquare starting at location loc in the dir direction. */static bool searchFrom(char word[], LOCATION loc, DIRECTION dir){ MOVEAMOUNT mv = move(dir); int matched = 0; int i = 0; while (word[i] != '\0') { if (ws.grid[loc.row + mv.deltaRow*i][loc.col + mv.deltaColumn*i] == word[i]) { matched++; } } if (matched == strlen(word)) { return true; } return false;}/* setValue(loc, value) sets location loc in the wordsquare to value. The function terminates the program if the location is not valid (i.e. outside the bounds of the wordsquare). */static void setValue(LOCATION loc, char value){ if (!isValidLocation(loc)) { fprintf(stderr, "Error: Invalid location supplied to setValue\n"); exit(EXIT_FAILURE); } ws.grid[loc.row][loc.col] = value;}/* highlightLetter(c) returns the highlighted version of c. */static char highlightLetter(char c){ // What a useless function.. return toupper(c);}/* foundWord(word, loc, dir) highlights word in the wordsquare. This function assumes word has already been found in the wordsquare starting at position loc in the dir direction. */static void foundWord(char word[], LOCATION loc, DIRECTION dir){ //Kindof messy but the best way I could think of doing it... MOVEAMOUNT mv = move(dir); LOCATION current = loc; int i = 0; while (word[i] != '\0') { ws.grid[current.row][current.col] = highlightLetter(ws.grid[current.row][current.col]); current.row += mv.deltaRow; current.col += mv.deltaColumn; }}/* search(word, sds) returns the number of times word appears in the wordsquare when searching in the search directions specified by sds */static int search(char word[], SEARCHDIRECTIONS sds){}/* isValidWordChar(c) returns true iff c is a valid character that can appear in the word part of a line of a words-file. */static bool isValidWordChar(char c){ //Surely this can't be this simple... if (islower(c)) { return true; } return false;}/* isValidSearchDirectionChar(c) returns true iff c is a valid character that can appear in the search directions string of a line of a words-file. */static bool isValidSearchDirectionChar(char c){ if (isdigit(c) && c != '0') { return true; } return false;}/* isValidChar(c) returns true iff c is a valid character that can appear in a words-file. */static bool isValidChar(char c){ if (islower(c)) { return true; } return false;}/* splitLine(line, fstwrd, sndwrd) splits line into its two component words: fstwrd and sndwrd. This function assumes line contains two words separated by a contiguous sequence of whitespace characters. */static void splitLine(char line[], char fstwrd[], char sndwrd[]){ int i = 0; while (line[i] != ' ') { fstwrd[i] = line[i]; i++; } while (line[i] == ' ') { i++; } while (line[i] != ' ' && line[i] != '\0') { sndwrd[i] = line[i]; i++; }}/* directionToSearchChar(dir) returns the words-file search direction character corresponding to the dir direction. */static char directionToSearchChar(DIRECTION dir){ if (dir == UP) return '8'; else if (dir == RIGHT) return '6'; else if (dir == DOWN) return '2'; else if (dir == LEFT) return '4'; else if (dir == DIAGUPLEFT) return '7'; else if (dir == DIAGUPRIGHT) return '9'; else if (dir == DIAGDOWNRIGHT) return '3'; else if (dir == DIAGDOWNLEFT) return '1'; else return ALLDIRECTIONSCHAR;}/* makeDirections(dirs) returns the SEARCHDIRECTIONS structure corresponding to the dirs search directions string taken from a words-file. The directions listed in the SEARCHDIRECTIONS structure are the minimal set from dirs (i.e. duplicate entries from dirs are removed) and are listed in the order specified by the DIRECTION enumeration. */static SEARCHDIRECTIONS makeDirections(char dirs[]){}/* processWords(filename) reads the contents of the file named filename as a words-file, searching for each word in turn in the wordsquare using the specified search directions for that word. The function reports whether each word was found or not and also the total number of words-file entries located in the wordsquare. The function terminates the program if the file is not a valid words-file. */static void processWords(char filename[]){}/* isHighlighted(loc) returns true iff the character occupying location loc in the wordsquare is highlighted. The function terminates the program if the location is not valid (i.e. outside the bounds of the wordsquare). */static bool isHighlighted(LOCATION loc){ if (!isValidLocation(loc)) { fprintf(stderr, "Error: Invalid location supplied to setValue\n"); exit(EXIT_FAILURE); } if (isupper(ws.grid[loc.row][loc.col])) { return true; } return false;}/* determineUnusedCharacters(str) sets str to be the nul-byte terminated string corresponding to the unused (non-highlighted) characters of the wordsquare, listed in left-to-right top-to-bottom order. */static void determineUnusedCharacters(char str[]){ int count = 0; int i = 0; while (i < ws.nRows) { int j = 0; while (j < ws.nCols) { LOCATION loc = {i,j}; if (!isHighlighted(loc)) { str[count] = getValue(loc); count++; } } } str[count] = '\0';}/* subset() returns true iff str1 is a subset of str2. The string str1 is considered a subset of the string str2 iff each character of str1 appears the same number of times or more in str2. */static bool subset(char str1[], char str2[]){ char temp[BUFSIZ]; int matched = 0; int str1l = strlen(str1); int str2l = strlen(str2); int i = 0; strcpy(temp, str1); while (i < str2l) { int j=0; while (j < str1l) { if (str2[i] == temp[j]) { temp[j] = '*'; matched++; break; } j++; } i++; } if (matched == str1l) { return true; } return false;}/* searchDictionary(filename, pattern) read the contents of the file named filename as a dictionary-file, reporting the longest word in the file that is a subset of pattern. */static void searchDictionary(char filename[], char pattern[]){ FILE *fp; char line[BUFSIZ]; char biggest[BUFSIZ]; int biggestMatched = 0; fp = fopen(filename, "r"); if(fp == NULL) { fprintf(stderr, "Cannot open file '%s'\n", filename); exit(EXIT_FAILURE); } while (fgets(line, sizeof line, fp) != NULL) { trimLine(line); if (subset(line, pattern) && strlen(line) > biggestMatched) { strcpy(biggest, line); biggestMatched = strlen(line); } } printf("Largest match in '%s' for\n '%s': %s\n", filename, pattern, biggest);}/****************************************************************//* The main program */int main(int argc, char *argv[]){ /* Exit with an error if the the number of arguments (including the name of the executable) is not 4 */ if(argc != 4) { fprintf(stderr, "Usage: %s <grid-file> <words-file> <dictionary-file>\n", argv[0]); exit(EXIT_FAILURE); } else { /* Read the grid from file */ readGrid(argv[1]); printf("Read wordsquare from '%s'. The initial wordsquare is:\n", argv[1]); /* Display the contents of the wordsquare */ display(); printf("\nProcessing words from file '%s':\n", argv[2]); /* Search for words, highlighting matches in the wordsquare */ processWords(argv[2]); printf("\nFinished task. The final wordsquare is:\n"); /* Redisplay the contents of the wordsquare */ display(); char unused[MAXSIZE*MAXSIZE+1]; /* Find the unused characters in the wordsquare */ determineUnusedCharacters(unused); printf("\nUnused characters in the wordsquare: %s.\n", unused); /* Search the dictionary for the longest word using the unused characters of the wordsquare */ searchDictionary(argv[3], unused); /* Finished successfully! */ exit(EXIT_SUCCESS); } return 0;}