views:

71

answers:

4

I am trying to read a text file in java, basically a set of questions. With 4 choices and 1 answer. The structure looks like this:

question

option a

option b

option c

option d

answer

I have no trouble reading it that way:

public class rar{
public static String[] q=new String[50];
public static String[] a=new String[50];
public static String[] b=new String[50];
public static String[] c=new String[50];
public static String[] d=new String[50];
public static char[] ans=new char[50];
public static Scanner sr= new Scanner(System.in);


public static void main(String args[]){
int score=0;
try {
             FileReader fr;
      fr = new FileReader (new File("F:\\questions.txt"));
      BufferedReader br = new BufferedReader (fr);
int ar=0;
      for(ar=0;ar<2;ar++){
      q[ar]=br.readLine();
      a[ar]=br.readLine();
      b[ar]=br.readLine();
      c[ar]=br.readLine();
      d[ar]=br.readLine();
    String tempo=br.readLine();
    ans[ar]=tempo.charAt(0);






        System.out.println(q[ar]);
        System.out.println(a[ar]);
        System.out.println(b[ar]);
        System.out.println(c[ar]);
        System.out.println(d[ar]);
        System.out.println("Answer: ");
        String strans=sr.nextLine();
char y=strans.charAt(0);
if(y==ans[ar]){
    System.out.println("check!");
score++;
System.out.println("Score:" + score);
}else{
System.out.println("Wrong!");
}

      }
      br.close();
    } catch (Exception e) { e.printStackTrace();}


}




}

The code above is predictable. The for loop just increments. And it displays the questions based on order. What I want to do is to be able to randomize through the text file, but still maintaining the same structure. (q, a, b, c, d, ans). But when I try to do this:

int ran= random(1,25);
   System.out.println(q[ran]);
        System.out.println(a[ran]);
        System.out.println(b[ran]);
        System.out.println(c[ran]);
        System.out.println(d[ran]);
        System.out.println("Answer: ");
        String strans=sr.nextLine();
char y=strans.charAt(0);
if(y==ans[ran]){
    System.out.println("check!");
score++;
System.out.println("Score:" + score);
}else{
System.out.println("Wrong!");
}

And this is the method that I use for randomizing:

public static int random(int min, int max){
    int xx;
    xx= (int) ( Math.random() * (max-min + 1))+ min;
    return xx;
    }

There's the possibility that I get a null. What can you recommend that I would do so that I get no null when trying to randomize the questions? Can you see anything else that is wrong with my program?

+4  A: 

I think a little structural changes will help a lot and make this much easier for you. Define new classes: Question and Answer. Let Question have the options and Answer inside of it. That's object composition.

Look into the Collection API. With a Collection of Questions, you can use the shuffle method to randomize them in one line. Let Java do the work for you.

So you might have:

Collection<Question> questions = new ArrayList<Question>();

questions.add(...);
questions.add(...);
questions.add(...);

questions.shuffle();

To embellish a little more about why you would want to do it this why... You want to separate your concerns the best you can. Questions, answers, and options are all different concerns. The user's response is a concern. The randomization of the questions is a concern. The response to the user's response is a concern.

Being a good software developer, you're going to want to compartmentalize all of these things. Java's construct for accomplishing this is the Class. You can develop your ideas relatively independently inside their own class. When you're satisfied with your Classes, all you have to do is connect them. Define their interfaces, how they talk to each other. I like to define the interfaces first, but when I started out, I found it a little easier to worry about that later.

Might seem like a lot of work, with all of these Classes and interfaces and what not. It'll take a fraction of the time to do it this way when you get good. And your reward is testability reusability.

Mike
Good answer, especially in giving the background reasoning behind it.
Andrzej Doyle
+1  A: 

Create a class to hold a question and read the file into an array of these objects.

Break the problem into three steps. The first step is to read in the data file and store all of the data in objects. The second step is to randomize the order of those objects. The final step is to print them out.

ArrayList questions = new ArrayList();
for(ar=0;ar<2;ar++){
  q=br.readLine();
  a=br.readLine();
  b=br.readLine();
  c=br.readLine();
  d=br.readLine();
  String tempo=br.readLine();
  ans=tempo.charAt(0);

  questions.add(new Question(q, a, b, c, d, ans));
}

Randomize the array like this:

Collections.shuffle(questions);

Then just loop through the questions and output them.

for (Question q: questions) {
  q.write();
  System.out.println(); // space between questions
}

Create a question class like this to hold your data:

public class Question {
  private String question;
  private String option1;
  private String option2;
  private String option3;
  private String option4;
  private String answer;

  public Question(String question, String option1, String option2, String option3,
                  String option4, String answer) {
    this.question = question;
    this.option1 = option1;
    this.option2 = option2;
    this.option3 = option3;
    this.option4 = option4;
    this.answer = answer;
  }

  public void write() {
    System.out.println(this.question);
    System.out.println(this.option1);
    System.out.println(this.option2);
    System.out.println(this.option3);
    System.out.println(this.option4);
    System.out.println("Answer: "+this.answer);
  }
}
Erick Robertson
+2  A: 

Other people (Mike, Erick) have already suggested better approaches to this problem by creating a new Question class, adding questions to a collection, and using the shuffle method to randomize them.

Regarding why you are "getting a null" in your code: As far as I can see in your example code you are only reading two questions from the file:

for (ar=0;ar<2;ar++) {
    [...]
}

This means that positions 0 and 1 in your arrays will have valid data, while positions 2 to 49 will contain null.

Later when you try to randomize questions you call your random method like this:

int ran = random(1,25);

This returs a value between 1 and 25, which you then use as an array index.

If this index happens to be '1' you'll be alright. For all other cases (2 to 25) you'll be accessing null values in your arrays, and getting exceptions when trying to play with these values.

Grodriguez
+1  A: 

You use all kind of magic numbers, numbers in your code that don't make much sense.

public static String[] q=new String[50]; //why make an array to hold 50 questions?

//... 

for(ar=0;ar<2;ar++){ //why read 2 questions?

//...

int ran= random(1,25); //why take one of 25 questions?
System.out.println(q[ran]);

These should all be the same number, right? If we have 25 questions, we should have room for 25, read 25 and use 25.

How to fix this:

1 Make a constant

public final static int NUMBER_OF_QUESTIONS = 25;

Then use that when making the array, reading the questions and when taking a random one:

public static String[] q=new String[NUMBER_OF_QUESTIONS];

for(ar=0;ar<NUMBER_OF_QUESTIONS;ar++){

int ran= random(1,NUMBER_OF_QUESTIONS);

2 Use q.length

public static String[] q=new String[NUMBER_OF_QUESTIONS];

for(ar=0;ar<q.length;ar++){

int ran= random(1,q.length);

3 Use a List / Collection

public static List<String> q=new List<String>();

for(ar=0;ar<q.size();ar++){

int ran= random(1,q.size());

Option 3 would be the best choice, this is java afterall. See Mike's answer for more detail in making this more Java.

Ishtar
Is this the proper way of assigning? q[ran]=br.readLine(); Because I do not get a random question. I followed option 1 and 2 of your answer.