tags:

views:

2056

answers:

4

Hello Friend Were trying to use external file (txt or CSV) in order to create a file stream in C#. The data in the file is that of a quiz game made of :

1 short question 4 possibles answers 1 correct answer

The program should be able to tell the user whether he answered correctly or not.

I'm looking for an example code/algorithm/tutorial on how to use the data in the external file to create a simple quiz in C#. Also, any suggestions on how to construct the txt file (how do I remark an answer as the correct one?). Any suggestions or links? Thanks,

+2  A: 

A good place to start is with Microsoft's documentation on FileStream.

A quick google search will give you pretty much everything you need. Here's a tutorial on reading and writing files in C#. Google is your friend.

unforgiven3
Thanks, I've done with my google research.I'm looking for more specific help concerning quizes with file streams.
Sarit
You're not going to find much on "quizzes". You need to develop a design based on your requirement for your quiz project. FileStream is only a tool - there are several other ways you could design your project and get the same result, for example, XML serialization.
unforgiven3
My point is that there is a big difference between design and implementation - using FileStream is only how you implement your project. The design, you have to come up with that on your own.
unforgiven3
Unforgiven 2 - one of all time favourite songs. *sighs* ;-)
Cerebrus
Haha, same here, Cerebrus! :-)
unforgiven3
unforgiven3, I think the downvotes are coming from "google it" being the bulk of your answer. It sounds a bit arrogant. This looks like a "please do my homework"-type question, so I think it's fruitless to appeal to the virtues of selfthinkery.
bzlm
hey bzlm, that was pretty uncalled for - I'm not asking anyone to do my homework, I'm just asking for tips or ideas for a good head start.Unforgiven3 - I wasn't the one who downvoted you, I even thanked ou for you answer.
Sarit
+11  A: 

My recommendation would be to use an XML file if you must load your data from a file (as opposed to from a database).

Using a text file would require you to pretty clearly define structure for individual elements of the question. Using a CSV could work, but you'd have to define a way to escape commas within the question or answer itself. It might complicate matters.

So, to reiterate, IMHO, an XML is the best way to store such data. Here is a short sample demonstrating the possible structure you might use:

<?xml version="1.0" encoding="utf-8" ?>
<Test>
  <Problem id="1">
    <Question>Which language am I learning right now?</Question>
    <OptionA>VB 7.0</OptionA>
    <OptionB>J2EE</OptionB>
    <OptionC>French</OptionC>
    <OptionD>C#</OptionD>
    <Answer>OptionA</Answer>
  </Problem>
  <Problem id="2">
    <Question>What does XML stand for?</Question>
    <OptionA>eXtremely Muddy Language</OptionA>
    <OptionB>Xylophone, thy Music Lovely</OptionB>
    <OptionC>eXtensible Markup Language</OptionC>
    <OptionD>eXtra Murky Lungs</OptionD>
    <Answer>OptionC</Answer>
  </Problem>
</Test>

As far as loading an XML into memory is concerned, .NET provides many intrinsic ways to handle XML files and strings, many of which completely obfuscate having to interact with FileStreams directly. For instance, the XmlDocument.Load(myFileName.xml) method will do it for you internally in one line of code. Personally, though I prefer to use XmlReader and XPathNavigator.

Take a look at the members of the System.Xml namespace for more information.

Cerebrus
Thanks for this very helpful answer!
Sarit
My pleasure! When I was learning .NET, I made a couple of personal projects, one of which was a Quizzer. :-)
Cerebrus
Hi Cerberus, just to give me a good headstart - can you help with the basic code to print the question item into a label?
Sarit
This is a good answer, however, using the higher level constructs may not lead to learning what the assignment was meant to learn. Normally these types of assignments are meant to teach programming language constructs such as loops and if statements in addition to file structure.
margok you're right, but I'm doing my best to "dumb" it down for me.I'm not very familiar with constructs.
Sarit
+2  A: 

There's really no set way to do this, though I would agree that for a simple database of quiz questions, text files would probably be your best option (as opposed to XML or a proper database, though the former wouldn't be completely overkill).

Here's a little example of a text-based format for a set of quiz questions, and a method to read the questions into code. Edit: I've tried to make it as easy as possible to follow now (using simple constructions), with plenty of comments!

File Format

Example file contents.

Question text for 1st question...
Answer 1
Answer 2
!Answer 3 (correct answer)
Answer 4

Question text for 2nd question...
!Answer 1 (correct answer)
Answer 2
Answer 3
Answer 4

Code

This is just a simple structure for storing each question in code:

struct Question
{
    public string QuestionText; // Actual question text.
    public string[] Choices;    // Array of answers from which user can choose.
    public int Answer;          // Index of correct answer within Choices.
}

You can then read the questions from the file using the following code. There's nothing special going on here other than the object initializer (basically this just allows you to set variables/properties of an object at the same time as you create it).

// Create new list to store all questions.
var questions = new List<Question>();

// Open file containing quiz questions using StreamReader, which allows you to read text from files easily.
using (var quizFileReader = new System.IO.StreamReader("questions.txt"))
{
    string line;
    Question question;

    // Loop through the lines of the file until there are no more (the ReadLine function return null at this point).
    // Note that the ReadLine called here only reads question texts (first line of a question), while other calls to ReadLine read the choices.
    while ((line = quizFileReader.ReadLine()) != null)
    {
        // Skip this loop if the line is empty.
        if (line.Length == 0)
            continue;

        // Create a new question object.
        // The "object initializer" construct is used here by including { } after the constructor to set variables.
        question = new Question()
        {
            // Set the question text to the line just read.
            QuestionText = line,
            // Set the choices to an array containing the next 4 lines read from the file.
            Choices = new string[]
            { 
                quizFileReader.ReadLine(), 
                quizFileReader.ReadLine(),
                quizFileReader.ReadLine(),
                quizFileReader.ReadLine()
            }
        };

        // Initially set the correct answer to -1, which means that no choice marked as correct has yet been found.
        question.Answer = -1;

        // Check each choice to see if it begins with the '!' char (marked as correct).
        for(int i = 0; i < 4; i++)
        {
            if (question.Choices[i].StartsWith("!"))
            {
                // Current choice is marked as correct. Therefore remove the '!' from the start of the text and store the index of this choice as the correct answer.
                question.Choices[i] = question.Choices[i].Substring(1);
                question.Answer = i;
                break; // Stop looking through the choices.
            }
        }

        // Check if none of the choices was marked as correct. If this is the case, we throw an exception and then stop processing.
        // Note: this is only basic error handling (not very robust) which you may want to later improve.
        if (question.Answer == -1)
        {
            throw new InvalidOperationException(
                "No correct answer was specified for the following question.\r\n\r\n" + question.QuestionText);
        }

        // Finally, add the question to the complete list of questions.
        questions.Add(question);
    }
}

Of course, this code is rather quick and basic (certainly needs some better error handling), but it should at least illustrate a simple method you might want to use. I do think text files would be a nice way to implement a simple system such as this because of their human readability (XML would be a bit too verbose in this situation, IMO), and additionally they're about as easy to parse as XML files. Hope this gets you started anyway...

Noldorin
Thanks Noldrin, but knowledge-wise what I'm looking for is a little simpler. I'm learning right now and I'm not familiar with lists, for example.
Sarit
Oh, fair enough then. Lists are fairly simple objects actually, and are probably worth learning soon whatever level you are at. I admit, the LINQ can seem a bit daunting to a newcomer however... if you like, I can rewrite the code to use simpler constructs.
Noldorin
That would be great! Since I'm a beginner, I would love to get as much help as possible.
Sarit
No problem. I've just edited my post so that the code should now be using largely quite common features of C#. It also has an absurd number of comments now! Still, if there is any part you don't understand, feel free to ask, though I hope it's all clear now.
Noldorin
Thanks Noldorin! I've been reading about lists, I'll definitley give this version a try :)
Sarit
+1  A: 

any suggestions on how to construct the txt file (how do I remark an answer as the correct one?)

Perhaps the easiest is with a simple text file format - where you have questions and answers on each line (no blank lines). The # sign signifies the correct answer.

Format of the file -

Question
#answer
answer
answer
answer  

An example file -

What is 1 + 1?
#2
9
3
7
Who is buried in Grant's tomb?
Ed
John
#Grant
Tim 

I'm looking for an example code/algorithm/tutorial on how to use the data in the external file to create a simple quiz in C#.

Here's some code that uses the example file to create a quiz.


        static void Main(string[] args)
        {
            int correct = 0;
            using (StreamReader sr = new StreamReader("C:\\quiz.txt"))
            {
                while (!sr.EndOfStream)
                {
                    Console.Clear();
                    for (int i = 0; i < 5; i++)
                    {
                        String line = sr.ReadLine();
                        if (i > 0)
                        {                            
                            if (line.Substring(0, 1) == "#") correct = i;
                            Console.WriteLine("{0}: {1}", i, line);
                        }
                        else
                        {
                            Console.WriteLine(line);
                        }
                    }                                       

                    for (; ; )
                    {
                        Console.Write("Select Answer: ");
                        ConsoleKeyInfo cki = Console.ReadKey();
                        if (cki.KeyChar.ToString() == correct.ToString())
                        {
                            Console.WriteLine(" - Correct!");
                            Console.WriteLine("Press any key for next question...");
                            Console.ReadKey();
                            break;
                        }
                        else
                        {
                            Console.WriteLine(" - Try again!");
                        }
                    }
                }
            }
        }
Thanks margok! I really appreciate the detailed answer, I'll definitely try this.I'm just not sure about the meaning of this line: Console.WriteLine("{0}: {1}", i, line);?
Sarit
In the string written to the display, it substitutes the value of 'i' for {0} and the value of 'line' for {1}, etc... It's a method of formatting the output string.
Hi margok, for some reason this condition: if ((line.Substring(0, 1)) == "#"), generates an error message: System.NullReferenceException: Object reference not set to an instance of an object.Any idea why?
Sarit
Probably because sr.ReadLine() returned null. Ensure you don't have any blank lines in your text file. There should be no blank lines between questions/answers and no blank lines at the start/end. A good exercise would be to step through the code and watch the variables to see what is happening.
Another good exercise would be to add a check for null using an if statement and handle the condition appropriately. (Although one could argue that a properly constructed quiz/text file would not give such a condition to begin with.)
There could be other reasons, like if you have questions with more or less than 4 answers you would need to change the 5 in the for loop to reflect that. The best is to set a break point on the "using statement" and step through the code in the Visual Studio IDE, examining variables as you go.
That will give you an idea as to what the code is really doing.