0% found this document useful (0 votes)
3 views

Solver. C

Uploaded by

danmanfunk
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

Solver. C

Uploaded by

danmanfunk
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 9

#include <stdio.

h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <getopt.h>
#include <ctype.h> // Added for handling case-insensitive options
#include "hashset.h" // Header file for hash set functions #include
"bst.h" // Header file for binary search tree functions

#define MEM_LIMIT (64 * 1024 * 1024) // 64MB

// Structure to represent a node in the binary search tree


typedef struct tnode {
char word[15]; // Maximum word length is 14, so 15 with null
terminator
struct tnode *left, *right; // Pointers to left and right child nodes
} tnode;

// Structure to represent the hash set


typedef struct hashset {
unsigned long size; // Number of entries in the hash set
tnode **table; // Array of linked lists (for handling collisions)
} hashset;

hashset set; // Global hash set to store the dictionary


tnode *root = NULL; // Root of the binary search tree
pthread_mutex_t bst_lock = PTHREAD_MUTEX_INITIALIZER; // Mutex for
thread-safe access to the binary search tree
int puzzle_size = 0, buf_cells = 0, min_len = 0, max_len = 0, sorted = 0,
buf_dimension; // Global variables to store puzzle parameters
char *filename = NULL; // Input file path
FILE *dictionary_file; // File pointer for the dictionary file
char ***buffer; // 3D buffer to store sub-puzzles

// Hash function for strings (using the djb2 algorithm)


unsigned long hash(char *str) {
unsigned long hash = 5381;
int c;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}

// Function to insert a word into the binary search tree


void bst_insert(tnode **node, char *word) {
if (*node == NULL) {
*node = (tnode *)malloc(sizeof(tnode));
strcpy((*node)->word, word);
(*node)->left = (*node)->right = NULL;
} else {
int cmp = strcmp(word, (*node)->word);
if (cmp < 0)
bst_insert(&((*node)->left), word);
else if (cmp > 0)
bst_insert(&((*node)->right), word);
}
}

// Function to perform in-order traversal of the binary search tree


void inorder_print(tnode *node) {
if (node) {
inorder_print(node->left);
printf("%s\n", node->word);
inorder_print(node->right);
}
}

// Function to initialize the hash set


hashset set_init() {
hashset set;
set.size = 0;
set.table = (tnode **)calloc(65536, sizeof(tnode *));
return set;
}

// Function to search for a word in the hash set


int search(hashset *set, char *word) {
unsigned long hash_val = hash(word) % 65536;
tnode *entry = set->table[hash_val];
while (entry != NULL) {
if (strcmp(word, entry->word) == 0)
return 1;
entry = entry->right;
}
return 0;
}

// Function to insert a word into the hash set


void insert(hashset *set, char *word) {
unsigned long hash_val = hash(word) % 65536;
tnode *entry = (tnode *)malloc(sizeof(tnode));
strcpy(entry->word, word);
entry->right = set->table[hash_val];
set->table[hash_val] = entry;
set->size++;
}

// Function to print an error message and exit the program


void error(char *msg, int code) {
fprintf(stderr, "%s\n", msg);
exit(code);
}

// Function executed by consumer threads to solve the sub-puzzle


void *solve(void *arg) {
char **sub_puzzle = (char **)arg;
int subpuzzle_rows = buf_dimension, subpuzzle_cols = buf_dimension;

// Find the actual dimensions of the sub-puzzle


for (int i = 0; i < buf_dimension; i++) {
if (sub_puzzle[i] == NULL) {
subpuzzle_rows = i;
break;
}
}
for (int i = 0; i < subpuzzle_rows; i++) {
int len = strlen(sub_puzzle[i]);
if (len < subpuzzle_cols)
subpuzzle_cols = len;
}

// Search for words in the sub-puzzle


char word[max_len + 1];
for (int len = min_len; len <= max_len; len++) {
// Check horizontal words
for (int row = 0; row < subpuzzle_rows; row++) {
for (int col = 0; col <= subpuzzle_cols - len; col++) {
strncpy(word, sub_puzzle[row] + col, len);
word[len] = '\0';
if (search(&set, word)) {
if (sorted) {
pthread_mutex_lock(&bst_lock); // Lock the mutex
for thread-safe access
bst_insert(&root, word); // Insert the word into
the binary search tree
pthread_mutex_unlock(&bst_lock); // Unlock the
mutex
} else {
printf("%s\n", word); // Print the word to the
console
}
}
}
}

// Check vertical words


for (int col = 0; col < subpuzzle_cols; col++) {
for (int row = 0; row <= subpuzzle_rows - len; row++) {
for (int i = 0; i < len; i++)
word[i] = sub_puzzle[row + i][col];
word[len] = '\0';
if (search(&set, word)) {
if (sorted) {
pthread_mutex_lock(&bst_lock);
bst_insert(&root, word);
pthread_mutex_unlock(&bst_lock);
} else {
printf("%s\n", word);
}
}
}
}

// Check diagonal words (slope +1)


for (int row = 0; row <= subpuzzle_rows - len; row++) {
for (int col = 0; col <= subpuzzle_cols - len; col++) {
for (int i = 0; i < len; i++)
word[i] = sub_puzzle[row + i][col + i];
word[len] = '\0';
if (search(&set, word)) {
if (sorted) {
pthread_mutex_lock(&bst_lock);
bst_insert(&root, word);
pthread_mutex_unlock(&bst_lock);
} else {
printf("%s\n", word);
}
}
}
}

// Check diagonal words (slope -1)


for (int row = 0; row <= subpuzzle_rows - len; row++) {
for (int col = len - 1; col < subpuzzle_cols; col++) {
for (int i = 0; i < len; i++)
word[i] = sub_puzzle[row + i][col - i];
word[len] = '\0';
if (search(&set, word)) {
if (sorted) {
pthread_mutex_lock(&bst_lock);
bst_insert(&root, word);
pthread_mutex_unlock(&bst_lock);
} else {
printf("%s\n", word);
}
}
}
}
}

free(arg); // Free the memory allocated for the sub-puzzle buffer


pthread_exit(NULL); // Exit the consumer thread
}

void print_buffer(char **sub_puzzle, int subpuzzle_rows, int


subpuzzle_cols) {
printf("%d by %d\n", subpuzzle_rows, subpuzzle_cols);
for (int i = 0; i < subpuzzle_rows; i++)
for (int j = 0; j < subpuzzle_cols; j++)
printf("%c%s", sub_puzzle[i][j], j == subpuzzle_cols - 1 ?
"\n" : "");
}

int main(int argc, char **argv) {


if (argc < 11)
error("Fatal Error. Usage: solve -dict dict.txt -input
puzzle1mb.txt -size 1000 -nbuffer 64 -len 4:7 [-s]", 1);

int i = 1;
while (i < argc) {
if (argv[i][0] != '-')
error("Fatal Error. Invalid CLA", 2);
else if (!strcmp(argv[i], "-size")) {
puzzle_size = atoi(argv[++i]);
if (puzzle_size < 15 || puzzle_size > 46340)
error("Fatal Error. Illegal value passed after -size", 3);
} else if (!strcmp(argv[i], "-nbuffer")) {
buf_cells = atoi(argv[++i]);
if (buf_cells != 1 && buf_cells != 4 && buf_cells != 16 &&
buf_cells != 64)
error("Fatal Error. Illegal value passed after -nbuffer",
4);
buf_dimension = (int)sqrt(MEM_LIMIT / buf_cells); // Compute
the dimension of each sub-puzzle buffer
} else if (!strcmp(argv[i], "-input")) {
filename = strdup(argv[++i]);
int fd = open(filename, O_RDONLY, 0); // Open the input file
if (fd < 0)
error("Fatal Error. Illegal value passed after -input",
5);
// Rest of the file reading code...
close(fd); // Close the input file
} else if (!strcmp(argv[i], "-dict")) {
dictionary_file = fopen(argv[++i], "r"); // Open the
dictionary file
if (!dictionary_file)
error("Fatal Error. Illegal value passed after -dict", 6);
} else if (!strcmp(argv[i], "-len")) {
char *min_max = strdup(argv[++i]);
char *max_str = strrchr(min_max, ':');
if (!max_str || max_str == min_max)
error("Fatal Error. Illegal value passed after -len", 7);
max_len = atoi(max_str + 1); // Extract the maximum word
length
*max_str = '\0';
min_len = atoi(min_max); // Extract the minimum word length
free(min_max);
if (min_len < 3 || max_len > 14 || min_len > max_len)
error("Fatal Error. Illegal value passed after -len", 7);
} else if (!strcmp(argv[i], "-s"))
sorted = 1; // Set the flag to sort the output
else
error("Fatal Error. Usage: solve -dict dict.txt -input
puzzle1mb.txt -size 1000 -nbuffer 64 -len 4:7 [-s]", 1);
i++;
}

// Read and move all words from dictionary_file to a new hash table
(hashset)
set = set_init(); // Initialize the hash set
char word[256];
while (fscanf(dictionary_file, "%s", word) == 1) {
insert(&set, word); // Insert each word from the dictionary into
the hash set
}
fclose(dictionary_file); // Close the dictionary file

// Allocate 64MB of buffer in the heap


buffer = (char ***)malloc(buf_cells * sizeof(char **)); // Allocate
memory for the 3D buffer
for (i = 0; i < buf_cells; i++) {
buffer[i] = (char **)malloc(buf_dimension * sizeof(char *)); //
Allocate memory for each sub-puzzle buffer
for (j = 0; j < buf_dimension; j++)
buffer[i][j] = (char *)malloc(buf_dimension); // Allocate
memory for each row of the sub-puzzle
}

int buf_index = 0;
pthread_t t_id[buf_cells]; // Array to store thread IDs of consumer
threads
for (i = 0; i < buf_cells; i++)
t_id[i] = NULL; // Initialize all thread IDs to NULL

// Code for reading the input file and filling the buffer cells...

for (i = 0; i < buf_cells; i++)


if (t_id[i])
pthread_join(t_id[i], NULL); // Wait for all consumer threads
to finish

if (sorted) {
// Print the binary search tree using in-order traversal...
inorder_print(root); // Print the words in alphabetical order
printf("\n");
}

// Free the allocated memory for the buffer and the hash set
for (i = 0; i < buf_cells; i++) {
for (j = 0; j < buf_dimension; j++)
free(buffer[i][j]);
free(buffer[i]);
}
free(buffer);
for (i = 0; i < 65536; i++) {
tnode *entry = set.table[i];
while (entry != NULL) {
tnode *temp = entry;
entry = entry->right;
free(temp);
}
}
free(set.table);

return 0;
}

You might also like