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

Solver. C

Uploaded by

danmanfunk
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

Solver. C

Uploaded by

danmanfunk
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
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