Hi,
I really need some help with this project. I'm currently a beginning C student working on a wheel of fortune program. For this program a random phrase must be chosen from a text file; the same phrase cannot also be used again during the game (there are three rounds). I've started to work on this, but I'm really stuck. I think I need to have a loop with fgets instead but other than that I'm clueless Please help me. Thanks. The test text file had 43 lines that why rand is with 43

int initialize_array(char phrase[], char puzzle[], char clue[]){
	FILE* phraseFile; /*input file*/
	char temp[100]; /*temporary array*/
	int line; /*line from which word and clue are chosen*/
	size_t i=0; /*counter for loop*/
	int len; /*length of line from file*/


	line=rand()%43; /*randomization of line*/
	
	phraseFile = fopen("clues.txt", "r"); /*opens file*/
	            
	if (!phraseFile) {
		fprintf(stderr, "Oops - file not opened !\n"); /*if there is error in opening file program is exited*/
		exit(1);
		}

		while(line--){
			fgets(temp, 100, phraseFile); /*gets line and stores in temp*/
		}
		
	len=strlen(temp);
	if(temp[len-1]=='\n')
		temp[len-1]=0; /*places the null terminating character after word*/
		
		/*separates clues from word*/
	strcpy(clue,strtok(temp, "%"));
	char tmp[WORD_LENGTH];
	strcpy(tmp,strtok(NULL,"%"));
	strcpy(phrase, tmp + 1);
	strcpy(puzzle,phrase);


		/*strcpy(puzzle,phrase);*/
	
		while(i<strlen(puzzle)){
			if(isalpha(puzzle[i])){
				puzzle[i] = '*'; /*hides word*/
				}
				++i;
			}
	fclose(phraseFile);	/*closes file*/	
	return i;
}

Recommended Answers

All 11 Replies

The hard part is working out how to get a random line from the file when you don't know how many lines there are. One way is to read the file once and count the lines, then use that count to pick a random number. A cooler way is a survivor method. Read lines and use a random test to pick between two lines. The one you picked is the survivor. When you get to the end of the file, the survivor will be randomly picked from all of the lines:

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

char *getLine(FILE *fp, char line[], size_t limit);
void getRandomLine(const char *filename, char line[], size_t limit);

int main()
{
  char line[1024];
  int i;

  srand((unsigned)time(NULL));

  /* Get 10 random lines from the file */
  for (i = 0; i < 10; ++i) {
    getRandomLine("test.txt", line, sizeof line);
    printf("%s\n", line);
  }
}

char *getLine(FILE *fp, char line[], size_t limit)
{
  char *result = fgets(line, limit, fp);

  if (result != NULL) {
    /* Strip the newline character */
    char *nl = strchr(line, '\n');

    if (nl != NULL)
      *nl = '\0';
  }

  return result;
}

void getRandomLine(const char *filename, char line[], size_t limit)
{
  FILE *fp = fopen(filename, "r");

  if (fp != NULL) {
    /* Get the first line as the first survivor */
    if (getLine(fp, line, limit) != NULL) {
      char *temp = (char*)malloc(limit);

      /* Survivor method starting with the first 2 lines */
      while (getLine(fp, temp, limit) != NULL) {
        if (rand() % 2 == 0)
          strcpy(line, temp);
      }

      /* Clean up resources */
      free(temp);
      fclose(fp);
    }
  }
}

It gets kind of inefficient if you ask for a lot of random lines though. The best solution is to keep the whole file in memory and just use random indexes if it's small enough. :)

I was thinking of doing it the first way described. Here is what I've done so far, but it isn't working. Someone please help!

int initialize_array(char phrase[], char puzzle[], char clue[]){
	FILE* phraseFile; /*input file*/
	char temp[100]; /*temporary array*/
	char line[100]; /*line from which word and clue are chosen*/
	size_t i=0; /*counter for loop*/
	int len; /*length of line from file*/
	int count;
	int x=0;

	
	phraseFile = fopen("clues.txt", "r"); /*opens file*/
	            
	if (!phraseFile) {
		fprintf(stderr, "Oops - file not opened !\n"); /*if there is error in opening file program is exited*/
		exit(1);
		}

		count=0;
		while(fgets(temp, 100, phraseFile)!=NULL){
			++count;
		}
	
	x=rand()%count+1;

	len=strlen(temp);
	if(temp[len-1]=='\n')
		temp[len-1]=0; /*places the null terminating character after word*/
		
		/*separates clues from word*/
	strcpy(clue,strtok(temp, "%"));
	char tmp[WORD_LENGTH];
	strcpy(tmp,strtok(NULL,"%"));
	strcpy(phrase, tmp + 1);
	strcpy(puzzle,phrase);


		/*strcpy(puzzle,phrase);*/
	
		while(i<strlen(puzzle)){
			if(isalpha(puzzle[i])){
				puzzle[i] = '*'; /*hides word*/
				}
				++i;
			}
	fclose(phraseFile);	/*closes file*/	
	return i;
}

You count the lines, but you don't go back and get the random line. Your function will always pick the last line in the file. This is what you want:

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

int main()
{
  FILE *fp = fopen("test.txt", "r");
  char line[1024];
  int count = 0;
  int r;

  srand((unsigned)time(NULL));

  while (fgets(line, sizeof line, fp) != NULL)
    ++count;

  r = rand() % count;

  // Start over
  rewind(fp);

  // Only read r lines
  while (--r >= 0)
    fgets(line, sizeof line, fp);

  puts(line);

  return 0;
}

well, for one thing:

size_t i=0; /*counter for loop*/
	int len; /*length of line from file*/

you've got your types switched. not really going to make a difference (size_t is typically #defined as a long int) but still...

if this basic stuff is wrong, i wonder how much more typos and cut-and-paste errors are lurking.

Is there anyway to do this without using rewind? We haven't learned this yet.

sure. instead of using "rewind", merely close the file, then reopen it exactly as you did the first time.

either way you start at the beginning of the file. rewind is just a nicer way to do it.

PS: dont be afraid to try new functions. especially if they're part of standard ANSI C libraries. rewind is part of the <stdio.h> library.

it's not some sort of secret 33rd level Grand Poobah Royal Order of Ancient Waterbuffalo thing.

Is there anyway to do this without using rewind? We haven't learned this yet.

Just close and open the file again.

its like deja vu or something.

Well, use any function that does the job.

besides, rewind() is nothing but

fseek (/* file pointer*/fp ,0L, SEEK_SET ) ;

Hi did what was suggested with the fopen/fclose. Could someone now help to me prevent the same line in a text file from being used twice? Thanks

int initialize_array(char phrase[], char puzzle[], char clue[]){
	FILE* phraseFile; /*input file*/
	char temp[100]; /*temporary array*/
	int line; /*line from which word and clue are chosen*/
	int i=0; /*counter for loop*/
	int len; /*length of line from file*/
	int count=0;
		
	phraseFile = fopen("clues.txt", "r"); /*opens file*/
	            
	if (!phraseFile) {
		fprintf(stderr, "Oops - file not opened !\n"); /*if there is error in opening file program is exited*/
		exit(1);
		}
 		
		while(fgets(temp,100,phraseFile)!=0){
			++count;
		}
		
		fclose(phraseFile);
		fopen("clues.txt", "r");
		line= rand()%count;
		
		while(line--){
			fgets(temp, 100, phraseFile); /*gets line and stores in temp*/
		}

	len=strlen(temp);
	if(temp[len-1]=='\n')
		temp[len-1]=0; /*places the null terminating character after word*/
		
		/*separates clues from word*/
		strcpy(clue,strtok(temp, "%"));
		/*
		strcpy(phrase,strtok(NULL,"%"));*/
char tmp[WORD_LENGTH];
	strcpy(tmp,strtok(NULL,"%"));
	strcpy(phrase, tmp + 1);
	strcpy(puzzle,phrase);
 
 
		/*strcpy(puzzle,phrase);*/
	
		while(i<strlen(puzzle)){
			if(isalpha(puzzle[i])){
				puzzle[i] = '*'; /*hides word*/
				}
				++i;
			}
	fclose(phraseFile);	/*closes file*/	
	return i;
}

in "main", declare an integer array of size equal to or greater than the number of possible lines, initializing all elements to zero on startup.


each time you go to use a line, check to see that the array element at that line index is still zero. if not, choose a different line.


once you use a line from the file, set the value of the array element at that line's index number to one.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.