Typing Tutor Help...?

thugster69

Active member
Joined
Jun 17, 2010
Messages
35
Programming Experience
Beginner
Hey guys!

I'm planning to create a Typing Tutor application which will provide texts that should be imitated by a user and then scored through its WPM.. I wonder how will I compare the values entered by the user to a defined text pattern?

Thanks in advance!
 

Solitaire

Well-known member
Joined
Jun 28, 2004
Messages
465
Location
New York
Programming Experience
10+
Here is an idea: Place the original text into one textbox. Start timing and have the user duplicate the text in a second textbox. When done, you can check the characters one by one between the original and duplicate text to get a count of the number of mistakes.

However, this requires the same number of characters in both texts. In case the user skipped a character or entered an extra one, this won't work and you will need a lot more complicated code to compensate for the difference.

Anyway, this may get you started:

VB.NET:
        Dim original, duplicate As String, n1, n2, typo As Integer, ch1, ch2 As Char
        original = TextBox1.Text
        duplicate = TextBox2.Text
        n1 = original.Length
        n2 = duplicate.Length
        If n1 = n2 Then
            For x As Integer = 0 To n1 - 1
                ch1 = original.Chars(x)
                ch2 = duplicate.Chars(x)
                If ch1 <> ch2 Then typo += 1
            Next
            MessageBox.Show("There were " & typo & " mistakes.")
        End If
 

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,439
Location
Norway
Programming Experience
10+
Since it's a words per minute score I'd just validate per word match, either word is right or it's not. This example splits word by space only, punctuation is considered part of the word (punctuation is important, right?). Anyway it is easy to exclude by entering them in the split array if you think not. This function takes user input string, the solution string and the time elapsed typing, and returns the calculated WPM number.
VB.NET:
Function WordsPerMinute(ByVal input As String, ByVal solution As String, ByVal time As TimeSpan) As Integer
    Dim inputwords = input.Split(" ".ToCharArray)
    Dim solutionwords = solution.Split(" ".ToCharArray)
    Dim min As Integer = Math.Min(inputwords.Length, solutionwords.Length) - 1
    Dim count As Integer
    For i As Integer = 0 To min
        If inputwords(i) = solutionwords(i) Then
            count += 1
        End If
    Next
    Return CInt(count / time.TotalMinutes)
End Function
To complete the application, need something to measure elapsed time:
VB.NET:
Private watch As Stopwatch
a Start button, when clicked:
VB.NET:
watch = Stopwatch.StartNew
a Stop button, when clicked:
VB.NET:
Me.Result.Text = String.Format("You typed at a rate of {0} words per minute.", WordsPerMinute(Me.Input.Text, Me.Solution.Text, Me.watch.Elapsed))
So there's a Input control that is probably a TextBox, and a Solution control perhaps a Label, and a Result control that is maybe also a Label.
 

thugster69

Active member
Joined
Jun 17, 2010
Messages
35
Programming Experience
Beginner
@Solitaire,

Thanks for the idea! It's been good in introducing me in this app..

@JohnH

I just read your reply, and haven't digested it all in my mind, but I'll go through it now.

Is the Stopwatch a built in function? and also, what do this line mean?

VB.NET:
Me.Result.Text = String.Format("You typed at a rate of {0} words per minute.", WordsPerMinute(Me.Input.Text, Me.Solution.Text, Me.watch.Elapsed))


Thank you guys! I'm also looking forward in hearing some other approaches in this topic! Thanks!
 

thugster69

Active member
Joined
Jun 17, 2010
Messages
35
Programming Experience
Beginner
Function WordsPerMinute(ByVal input As String, ByVal solution As String, ByVal time As TimeSpan) As Integer
Dim inputwords = input.Split(" ".ToCharArray)
Dim solutionwords = input.Split(" ".ToCharArray)

Isnt it that the third line should be solution.split(" ".ToCharArray) ?

And also, where does those 2 of the byVal statements point? Does the input points to my textbox component and solution to my label component?
 

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,439
Location
Norway
Programming Experience
10+
Isnt it that the third line should be solution.split(" ".ToCharArray) ?
Correct, copied the code line and forgot to update it, I fixed the previous code post.
And also, where does those 2 of the byVal statements point?
Those are function parameters, when you call the function you provide these strings, such as the example I provided for the Stop button. Procedure Parameters and Arguments
 

thugster69

Active member
Joined
Jun 17, 2010
Messages
35
Programming Experience
Beginner
Those are function parameters, when you call the function you provide these strings, such as the example I provided for the Stop button. Procedure Parameters and Arguments

I see, now I have an additional knowledge about functions.. Now I'm wondering if I can output to several labels the Time Elapsed, Correct Input and Mistakes using the WordsPerMinute function.. Is it possible to RETURN several values with one function? Or do I have to create another one?

Thanks for answering all of my queries.. Seems like your the only one interested in answering my question! Cheers Mate!
 

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,439
Location
Norway
Programming Experience
10+
WordsPerMinute function does not provide the elapsed time, that is one of the arguments that you input to it, so you already have that value and can use it also for other purposes.
A function does only have a single return value, but that value can be any type of object, for example a class instance with 100 properties is still a single object.
Through the arguments passed to methods values can also be passed back to caller, this is true for reference types through the default ByVal parameters, and for value types through ByRef parameters.
 

thugster69

Active member
Joined
Jun 17, 2010
Messages
35
Programming Experience
Beginner
Now I see.. I showed the program to my classmate and he was quite impressed with the logic you put it.. I really appreciate your help on me on getting myself started on my app..

If I may ask one last question, how can I make the solution words BOLD when the input word is correct?

Thanks again! I feel very welcome in this forum because of you!
 

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,439
Location
Norway
Programming Experience
10+
Use a RichTextBox control, that supports mixed font styles. You can keep track of text index as you loop and use the Select method to select the word, then apply hilighting with one of the Selection... properties, like SelectionFont. The index is the length of each word + 1 space between each word.
 

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,439
Location
Norway
Programming Experience
10+
Let's restructure the code slightly. Let the function validate and hilight the words and return the correct word count and total word count. To return these two result values as a single object a Structure can be defined, for example like this:
VB.NET:
Private Structure Result
    Public Property TotalCount As Integer
    Public Property CorrectCount As Integer

    Public Sub New(ByVal correctCount As Integer, ByVal totalCount As Integer)
        Me.CorrectCount = correctCount
        Me.TotalCount = totalCount
    End Sub

    Public Function WPM(ByVal time As TimeSpan) As Integer
        Return CInt(CorrectCount / time.TotalMinutes)
    End Function
End Structure
I use .Net 4 and have autodeclared properties, but you get the idea. Also, WPM is conveniently included as a function here.

The previous WPM function only has some small changes to allow it to hilight the Solution control directly (that now is a RichTextBox), and return an instance of the Result structure, so now I called it ValidateHilightWords instead:
VB.NET:
Private Function ValidateHilightWords(ByVal input As String, ByVal solution As RichTextBox) As Result
    Dim inputwords = input.Split(" ".ToCharArray)
    Dim solutionwords = solution.Text.Split(" ".ToCharArray)
    Dim min As Integer = Math.Min(inputwords.Length, solutionwords.Length) - 1
    Dim count, index As Integer
    For i As Integer = 0 To min
        If inputwords(i) = solutionwords(i) Then
            Dim wordlength = solutionwords(i).Length
            solution.Select(index, wordlength)
            solution.SelectionFont = New Font(solution.Font, solution.Font.Style Or FontStyle.Bold)
            index += wordlength + 1
            count += 1
        End If
    Next
    Return New Result(count, solutionwords.Length)
End Function
Now in Stop button you can do this instead:
VB.NET:
Dim time = watch.Elapsed
Dim res = ValidateHilightWords(Me.Input.Text, Me.Solution)
Dim msg = "You typed at a rate of {0} words per minute. You had {1} correct words out of {2}."
Me.Result.Text = String.Format(msg, res.WPM(time), res.CorrectCount, res.TotalCount)
The Solution RichTextBox should have Readonly set to True and ShortcutsEnabled set to False to prevent users just copying the solution text.
 

thugster69

Active member
Joined
Jun 17, 2010
Messages
35
Programming Experience
Beginner
@ JohnH

Whew, its been days since I've been in the site.. Been very busy academically.. Thanks for the guidance! Ill be reading it now and reply ASAP I finish coding and trying it! Thanks for the help!
 
Top Bottom