/* ///////////////////////////////////////// */ /* ///////// Includes and Defines ////////// */ /* ///////////////////////////////////////// */ #include #include #include #include #include #include #include #include #include /* ///////////////////////////////////// */ /* ///////// Global Variables ////////// */ /* ///////////////////////////////////// */ /* Room variables */ char* room_filenames[] = { "room_1.txt", "room_2.txt", "room_3.txt", "room_4.txt", "room_5.txt", "room_6.txt", "room_7.txt" }; char* rooms_directory_base = "perrenc.rooms."; char rooms_directory_full[255]; char *potential_room_names[10] = { "Dearborn", "Graf", "Rogers", "Covell", "Batcheller", "Kidder", "Valley Library", "Memorial Union", "Gilbert", "Weniger" }; unsigned int min_connections = 3; unsigned int max_connections = 6; char* current_room_filename; char path_taken[255][15]; unsigned int num_steps = 0; /* File access variables */ FILE *file_pointer_main; FILE *file_pointer_time; /* Threading variables */ pthread_t time_thread_ID; bool time_written = false; char* time_file_name = "currentTime.txt"; pthread_mutex_t time_mutex; /* State Handling Variables */ bool game_over = false; bool delete_folder_and_files = true; /* State Variables */ bool valid_input = false; bool first_print = true; /* //////////////////////////////////////// */ /* ///////// Function Prototypes ////////// */ /* //////////////////////////////////////// */ /* Initialization functions */ void program_init(void); void generate_rooms(void); /* User Input and Printing Functions */ void print_current_room_and_prompt(void); void get_user_input_and_process(void); void print_game_over(void); /* Room Specific Functions*/ void create_room(char *room_filename, char *room_name, char* room_type); void add_connection_to_room(char *room_filename, char *room_name_to_add); unsigned int get_number_of_connections_from_room(char *room_filename); bool is_room_used(char* room_name); bool is_end_room(char* room_filename); void get_room_name(char* room_filename, char* room_name_buffer); int get_room_index_from_name(char* room_name); int get_used_indexes(char* room_filename, int* output_list); /* Threading Functions */ void print_time(void); /* Threading Functions */ void* get_time(void *arguments); /* Helper Functions */ FILE *open_file_local_folder(char *file_name, char *mode); int delete_file_local_folder(char *file_name); /* ///////////////////////// */ /* ///////// Main ////////// */ /* ///////////////////////// */ int main(int argc, char** argv) { program_init(); generate_rooms(); while(!game_over){ print_current_room_and_prompt(); while(!valid_input){ get_user_input_and_process(); } valid_input = false; } print_game_over(); return (EXIT_SUCCESS); } /* ///////////////////////////////////////////// */ /* ///////// Initialization Functions ////////// */ /* ///////////////////////////////////////////// */ void program_init(void){ char pid_buffer[20]; memset(pid_buffer, '\0', 20); /* Initialize our mutex */ assert(pthread_mutex_init(&time_mutex, NULL) == 0); /* Make the rooms directory string we'll be using */ memset(rooms_directory_full, '\0', 255); sprintf(pid_buffer, "%d", getpid()); strcat(rooms_directory_full, rooms_directory_base); strcat(rooms_directory_full, pid_buffer); /* Create the directory now that we have the string */ mkdir(rooms_directory_full, 0770); /* Select the start room as the start point */ current_room_filename = room_filenames[0]; } void generate_rooms(void){ time_t t; bool start_used = false; bool end_used = false; char num_rooms = sizeof(room_filenames) / sizeof(room_filenames[0]); srand((unsigned) time(&t)); /* Generate base rooms with room name and room type */ int i; for(i = 0 ; i < num_rooms ; i++){ /* Get a random room name */ int random_num_name = rand() % 10; char* current_room_name = potential_room_names[random_num_name]; /* If that name is already used, generate a unique one */ while(is_room_used(current_room_name)){ random_num_name = rand() % 10; current_room_name = potential_room_names[random_num_name]; } /* Make the start room if it hasn't been made yet */ if(!start_used){ create_room(room_filenames[i], current_room_name, "START_ROOM"); start_used = true; /* Make the end room if it hasn't been made yet */ }else if(!end_used){ create_room(room_filenames[i], current_room_name, "END_ROOM"); end_used = true; /* Make the middle rooms, if the start and ends rooms are made */ }else{ create_room(room_filenames[i], current_room_name, "MID_ROOM"); } } /* Generate the room connections for each room */ for(i = 0 ; i < num_rooms ; i++){ char buffer[255]; int used_rooms[6]; /* Initialize used rooms array with invalid numbers */ int l; for(l = 0 ; l < 6 ; l++){ used_rooms[l] = -1; } /* Get random number between min and max connections */ int num_connections = (rand() % 4) + min_connections - \ get_number_of_connections_from_room(room_filenames[i]); /* Generate the connections for an individual room */ int j; for(j = 0 ; j < num_connections ; j++){ int room_to_add; bool unused_found = false; /* Generate connections, making sure they're not itself or other rooms that have already been used */ while(!unused_found){ room_to_add = rand() % 7; /* Skip if room is itself */ if(room_to_add == i){ continue; } /* Make sure that we're not adding a room that's already a connection */ bool already_exists = false; get_used_indexes(room_filenames[i], used_rooms); int k; for(k = 0 ; k < 6 ; k++){ if(used_rooms[k] == room_to_add){ already_exists = true; break; } } /* Make sure the connecting room can handle the reverse connection */ if(get_number_of_connections_from_room(\ room_filenames[room_to_add]) == max_connections){ already_exists = true; } /* If all is good, set flag to exit loop */ if(!already_exists){ unused_found = true; } } /* Once a connection has been deemed valid, add forward and backwards connections */ memset(buffer, '\0', 255); get_room_name(room_filenames[room_to_add], buffer); add_connection_to_room(room_filenames[i], buffer); memset(buffer, '\0', 255); get_room_name(room_filenames[i], buffer); add_connection_to_room(room_filenames[room_to_add], buffer); } } } /* //////////////////////////////////////////////// */ /* ///////// User Input and Printing Functions //// */ /* //////////////////////////////////////////////// */ void print_current_room_and_prompt(void){ char current_line[255]; char print_buffer[255]; char* tokenized; memset(current_line, '\0', 255); memset(print_buffer, '\0', 255); file_pointer_main = open_file_local_folder(current_room_filename, "r"); /* Print location header */ if(first_print){ printf("CURRENT LOCATION: "); first_print = false; }else{ printf("\nCURRENT LOCATION: "); } /* Strip out and print current room name */ fgets(current_line, 255, file_pointer_main); tokenized = strtok(current_line, ":"); tokenized = strtok(NULL, " \n"); bool first_entry = true; while(tokenized != NULL){ if(first_entry){ first_entry = false; }else{ printf(" "); } printf("%s", tokenized); tokenized = strtok(NULL, " \n"); } /* Print possible connections header */ printf("\nPOSSIBLE CONNECTIONS: "); /* Loop through connections and print names with separators */ bool printing_connections = true; bool printed_first_connection = false; while(printing_connections){ fgets(current_line, 255, file_pointer_main); tokenized = strtok(current_line, " "); if(strcmp(tokenized, "CONNECTION") != 0){ printing_connections = false; break; } if(printed_first_connection){ printf(", "); }else{ printed_first_connection = true; } tokenized = strtok(NULL, ":"); tokenized = strtok(NULL, " \n"); bool first_entry = true; while(tokenized != NULL){ if(first_entry){ first_entry = false; }else{ printf(" "); } printf("%s", tokenized); tokenized = strtok(NULL, " \n"); } } printf("."); fclose(file_pointer_main); } void get_user_input_and_process(void){ char buffer[255]; memset(buffer, '\0', 255); /* Print where to header */ printf("\nWHERE TO? >"); /* Read in newline terminated string from user, and strip out the newline*/ fgets(buffer, 255, stdin); buffer[strlen(buffer)-1] = '\0'; /* Check input to determine if valid and what it should do*/ int room_index = get_room_index_from_name(buffer); if(room_index != -1){ /* Room change is valid, change room and log */ strcpy(path_taken[num_steps], buffer); num_steps++; current_room_filename = room_filenames[room_index]; valid_input = true; }else if(strcmp(buffer, "time") == 0){ /* Request was to print time, do so */ print_time(); }else{ /* Bad input was entered, print input error message */ printf("\nHUH? I DON'T UNDERSTAND THAT ROOM. TRY AGAIN.\n"); valid_input = true; } /* Set game over flag to the result of whether we're in the end room */ game_over = is_end_room(current_room_filename); } void print_game_over(void){ /* Print game over header */ printf("\nYOU HAVE FOUND THE END ROOM. CONGRATULATIONS!"); printf("\nYOU TOOK %u STEPS. YOUR PATH TO VICTORY WAS:", num_steps); /* Print path taken to game over*/ int i; for(i = 0 ; i < num_steps ; i++){ printf("\n%s", path_taken[i]); } printf("\n"); } /* ////////////////////////////////////// */ /* ///////// Room Specific Functions //// */ /* ////////////////////////////////////// */ void create_room(char *room_filename, char *room_name, char* room_type){ file_pointer_main = open_file_local_folder(room_filename, "w"); assert(file_pointer_main != NULL); /* Print line for the room name */ fputs("ROOM NAME: ", file_pointer_main); fputs(room_name, file_pointer_main); fputs("\n", file_pointer_main); /* Print line for the room type */ fputs("ROOM TYPE: ", file_pointer_main); fputs(room_type, file_pointer_main); fclose(file_pointer_main); } void add_connection_to_room(char *room_filename, char *room_name_to_add){ char output_string_buffer[255]; char room_type_save_buffer[255]; unsigned int newline_count = 0; unsigned int line_to_insert_at = 0; long insertion_position = 0; memset(output_string_buffer, '\0', 255); memset(room_type_save_buffer, '\0', 255); /* Determine where the new connection line will sit */ line_to_insert_at = get_number_of_connections_from_room(room_filename); /* Add one to skip room name line */ line_to_insert_at++; file_pointer_main = open_file_local_folder(room_filename, "r+"); /* Count out way to where we insert the new connection */ while(newline_count != line_to_insert_at){ if(fgetc(file_pointer_main) == '\n'){ newline_count++; } } /* Save insertion position and make backup of line that will be wiped out */ insertion_position = ftell(file_pointer_main); fgets(room_type_save_buffer, 255, file_pointer_main); fseek(file_pointer_main, insertion_position, SEEK_SET); /* Save new connection line and add the saved one after it */ sprintf(output_string_buffer, "CONNECTION %u: %s\n", line_to_insert_at, \ room_name_to_add); fputs(output_string_buffer, file_pointer_main); fputs(room_type_save_buffer, file_pointer_main); fclose(file_pointer_main); } unsigned int get_number_of_connections_from_room(char *room_filename){ char current_line[255]; char* tokenized; unsigned int number_of_rooms = 0; memset(current_line, '\0', 255); file_pointer_main = open_file_local_folder(room_filename, "r"); /* Loop through the lines and count the number of connections we have */ while(fgets(current_line, 255, file_pointer_main) != NULL){ tokenized = strtok(current_line, " "); if(strcmp("CONNECTION", tokenized) == 0){ number_of_rooms++; } } fclose(file_pointer_main); return number_of_rooms; } bool is_room_used(char* room_name){ char num_rooms = sizeof(room_filenames) / sizeof(room_filenames[0]); char room_name_buffer[255]; /* Loop through all files and strcmp to see if it's been used already */ int i; for(i = 0 ; i < num_rooms ; i++){ memset(room_name_buffer, '\0', 255); get_room_name(room_filenames[i], room_name_buffer); /* printf("Comparing %s to %s\n", room_name, room_name_buffer); */ if(strcmp(room_name_buffer, room_name) == 0){ return true; } } return false; } bool is_end_room(char* room_filename){ char current_line[255]; char* tokenized; memset(current_line, '\0', 255); file_pointer_main = open_file_local_folder(room_filename, "r"); /* Run through file until room type, check if room is end room*/ while(fgets(current_line, 255, file_pointer_main) != NULL){ tokenized = strtok(current_line, ":"); if(strcmp("ROOM TYPE", tokenized) == 0){ tokenized = strtok(NULL, " \n"); if(strcmp(tokenized, "END_ROOM") == 0){ fclose(file_pointer_main); return true; } } } fclose(file_pointer_main); return false; } void get_room_name(char* room_filename, char* room_name_buffer){ char current_line[255]; char* tokenized; memset(current_line, '\0', 255); file_pointer_main = open_file_local_folder(room_filename, "r"); /* Return immediately if file does not yet exist */ if(file_pointer_main == NULL){ strcpy(room_name_buffer, "___NOT_A_ROOM_NAME____"); return; } /* Run through file and get room name with special handling for spaces */ while(fgets(current_line, 255, file_pointer_main) != NULL){ /*strcpy(current_line_backup, current_line);*/ tokenized = strtok(current_line, ":"); bool first_entry = true; if(strcmp("ROOM NAME", tokenized) == 0){ tokenized = strtok(NULL, " \n"); while(tokenized != NULL){ if(first_entry){ first_entry = false; }else{ strcat(room_name_buffer, " "); } strcat(room_name_buffer, tokenized); tokenized = strtok(NULL, " \n"); } break; } } fclose(file_pointer_main); } int get_room_index_from_name(char* room_name){ char num_rooms = sizeof(room_filenames) / sizeof(room_filenames[0]); char room_name_buffer[255]; /* Loop through files until the room name is found, return index*/ int i; for(i = 0 ; i < num_rooms ; i++){ memset(room_name_buffer, '\0', 255); get_room_name(room_filenames[i], room_name_buffer); if(strcmp(room_name_buffer, room_name) == 0){ return i; } } return -1; } int get_used_indexes(char* room_filename, int* output_list){ char current_line[255]; char used_names[6][15]; char* tokenized; int return_index = 0; memset(current_line, '\0', 255); file_pointer_main = open_file_local_folder(room_filename, "r"); /* Loop through and get names of all connections in file */ while(fgets(current_line, 255, file_pointer_main) != NULL){ tokenized = strtok(current_line, " "); if(strcmp("CONNECTION", tokenized) == 0){ tokenized = strtok(NULL, ":"); tokenized = strtok(NULL, " \n"); bool first_entry = true; while(tokenized != NULL){ if(first_entry){ first_entry = false; }else{ strcat(used_names[return_index], " "); } strcat(used_names[return_index], tokenized); tokenized = strtok(NULL, " \n"); } return_index++; } } fclose(file_pointer_main); /* Get indices from names, and return */ int i; for(i = 0 ; i < return_index ; i++){ output_list[i] = get_room_index_from_name(used_names[i]); } return return_index; } /* /////////////////////////////////// */ /* ///////// Time Functions ////////// */ /* /////////////////////////////////// */ void print_time(void){ /* Make and run the thread. Join to block until the other thread is done. */ assert(pthread_create(&time_thread_ID, NULL, get_time, NULL) == 0); assert(pthread_join(time_thread_ID, NULL) == 0); /* Lock and get a copy of whether time was written. Set original to false. */ pthread_mutex_lock(&time_mutex); bool time_was_written = time_written; time_written = false; pthread_mutex_unlock(&time_mutex); /* Make sure that the time was written, otherwise massive error... */ assert(time_was_written); /* Open file with time information and print it. */ file_pointer_main = open_file_local_folder(time_file_name, "r"); assert(file_pointer_main != NULL); printf("\n"); char c = fgetc(file_pointer_main); while(c != EOF){ printf("%c", c); c = fgetc(file_pointer_main); } printf("\n"); fclose(file_pointer_main); /* Delete this temporary file */ delete_file_local_folder(time_file_name); } /* //////////////////////////////////////// */ /* ///////// Threading Functions ////////// */ /* //////////////////////////////////////// */ void* get_time(void *arguments){ time_t current_time_raw; struct tm *time_as_struct; char buffer_size = 50; char buffer[buffer_size]; memset(buffer, '\0', buffer_size); /* Get current time */ time(¤t_time_raw); time_as_struct = localtime(¤t_time_raw); /* Format per specification */ strftime(buffer, buffer_size, "%-l:%M%P, %A, %B %-e, %Y", time_as_struct); /* Write formatted time to file */ file_pointer_time = open_file_local_folder(time_file_name, "w"); fprintf(file_pointer_time, "%s", buffer); fclose(file_pointer_time); /* Lock, update, and unlock mutex variable */ pthread_mutex_lock(&time_mutex); time_written = true; pthread_mutex_unlock(&time_mutex); return NULL; } /* ///////////////////////////////////// */ /* ///////// Helper Functions ////////// */ /* ///////////////////////////////////// */ FILE *open_file_local_folder(char *file_name, char *mode){ /* Makes common concatenation of file with full path easier */ char full_path[255]; memset(full_path, '\0', 255); strcat(full_path, rooms_directory_full); strcat(full_path, "/"); strcat(full_path, file_name); return fopen(full_path, mode); } int delete_file_local_folder(char *file_name){ /* Easy delete that handles concatenation for time file */ char full_path[255]; memset(full_path, '\0', 255); strcat(full_path, rooms_directory_full); strcat(full_path, "/"); strcat(full_path, file_name); return remove(full_path); }