Go Back  Xtreme Visual Basic Talk > Visual Basic .NET (2002/2003/2005/2008, including Express editions) > .NET Game Programming > High score in game?


Reply
 
Thread Tools Display Modes
  #1  
Old 04-17-2012, 06:51 AM
qweqwe256 qweqwe256 is offline
Newcomer
 
Join Date: Apr 2012
Posts: 7
Default High score in game?


I made a game with a score. Now i want to save that score in a .txt so it can be displayed later. I want to save the top 5 scores by introducing them in a text box from a form1 and them display them in a form2.

So when the game is over a form pops up asking you to insert your name. This is the form:

-------------

Imports System.Windows.Forms.Form
Imports System.IO


Public Class Highscore

Private Sub bt_Ok_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_OK.Click
Dim i As Integer
Dim aryText(5) As String
Dim objWriter As New System.IO.StreamWriter("scor.txt")

aryText(1) = 0
aryText(2) = 0
aryText(3) = 0
aryText(4) = 0
aryText(5) = 0

For i = 1 To 5
If Tetris.Tetris.LblScoreValue.Text > aryText(1) Then

aryText(1) = Tetris.Tetris.LblScoreValue.Text
objWriter.WriteLine(TextBox_Player.Text & " " & aryText(1))

ElseIf Tetris.Tetris.LblScoreValue.Text > aryText(2) Then

aryText(2) = Tetris.Tetris.LblScoreValue.Text
objWriter.WriteLine(TextBox_Player.Text & " " & aryText(2))

ElseIf Tetris.Tetris.LblScoreValue.Text > aryText(3) Then

aryText(3) = Tetris.Tetris.LblScoreValue.Text
objWriter.WriteLine(TextBox_Player.Text & " " & aryText(3))

ElseIf Tetris.Tetris.LblScoreValue.Text > aryText(4) Then

aryText(4) = Tetris.Tetris.LblScoreValue.Text
objWriter.WriteLine(TextBox_Player.Text & " " & aryText(4))

ElseIf Tetris.Tetris.LblScoreValue.Text > aryText(5) Then
aryText(5) = Tetris.Tetris.LblScoreValue.Text
objWriter.WriteLine(TextBox_Player.Text & " " & aryText(5))

End If
Next
objWriter.Close()
Me.Close()
End Sub

------------

Tetris.Tetris.LblScoreValue is the score value made string in a label in the main class.
If score is bigger than arytext(1) =0 , replace 0 with the score and add the name inserted in the textbox.

If i do this, all the 5 names become what i inserted in the textbox along with the same score. I know it's because i put arytext(1) =0, so i need a way to look inside the txt, check each line to see if it's at least bigger that last place arryText(5) and replace it with the new score.
I would also like to increment each line position. For example if place #1 was replaced move all the scores down with one position.

Can somebody please help?? I'm familiar with programming but I'm new to vb.net and maybe I've complicated things too much.
Reply With Quote
  #2  
Old 04-17-2012, 06:55 AM
qweqwe256 qweqwe256 is offline
Newcomer
 
Join Date: Apr 2012
Posts: 7
Default

If i made 200 pts in my game and it's over , after i introduce my name in that form that pops out, for ex "Alex", this is what scor.txt looks like:

Alex 200
Alex 200
Alex 200
Alex 200
Alex 200

If I play again and make 100 points, with name Mark this is the new scor.txt

Mark 100
Mark 100
Mark 100
Mark 100
Mark 100
Reply With Quote
  #3  
Old 04-17-2012, 08:46 AM
AtmaWeapon's Avatar
AtmaWeapon AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

One way to diagnose a problem is to substitute known values for variables when you read the code. This can shed a lot of light on what's going on. Here's what I mean.

Let's give the following start values:
LblScoreValue.Text = "300"
TextBox_Player.Text = "Rose"

The rest are assigned via code. So we'll take this line:
Code:
aryText(1) = Tetris.Tetris.LblScoreValue.Text
...and consider it like this instead:
Code:
aryText(1) = "300"
Consider these two cases:
Code:
If Tetris.Tetris.LblScoreValue.Text > aryText(1) Then
    aryText(1) = Tetris.Tetris.LblScoreValue.Text
    objWriter.WriteLine(TextBox_Player.Text & " " & aryText(1))
ElseIf Tetris.Tetris.LblScoreValue.Text > aryText(2) Then
    aryText(2) = Tetris.Tetris.LblScoreValue.Text
    objWriter.WriteLine(TextBox_Player.Text & " " & aryText(2))
Code:
If "300" > "0" Then
    aryText(1) = "300"
    objWriter.WriteLine("Rose" & " " & "300")
ElseIf "300" > "0" Then
    aryText(2) = "300"
    objWriter.WriteLine("Rose" & " " & "300")
This brings up multiple problems, but the most pressing is you don't change which name you're writing. That's why you get the same name each time. Here's some suggestions.

Normally high score logic looks like this:
Code:
1. Read the list of names and scores from the file.
2. Add the current name and score to the appropriate place in the list.
3. Trim the list.
4. Write the list to a file.
Each of those pieces is an interesting discussion in and of itself.

1. Read the list of names and scores.
You're not reading the old high scores file right now; there's not much point to writing it if you don't read it later. You've currently only got an array of scores; that means you'll lose the old names.

2. Add the current name and score to the appropriate place.
If you think through your current logic, you'll replace /every/ score, because if the score is the highest it's automatically greater than all the lower scores. That's why my step 2 involves finding the right place. A simple way to do it if you've got a list that supports insertion:
Code:
1. For each element in the list:
    1.1. If score > currentScore Then
        1.1.1. Insert the score before this position
        1.1.2. Stop searching
2. If no replacement occurred:
    2.1. Add the score to the end of the list
3. Trim the List and 4. Write the list to the file
These can be combined. If you want 5 items, only write 5 items to the file. If the last score was lower than any high scores, it'll get dropped.

Give it another shot with these hints in mind and see if you have more success.
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #4  
Old 04-17-2012, 08:49 AM
passel's Avatar
passel passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 7,911
Default

{edit}: I see AtmaWeapon slipped in. I tried to check to make sure I didn't post if someone else was going to (I saw PlausiblyDamp skipped). I've got to run so can't read Atma's till later, but I'm sure it is good and this post is probably redundant, and less helpful {/edit}

Since you are going to have five scores, when you start your game, you should check to see if you have a scores file.
If you do, then read the five sets of data into your score array.
If you don't, now would be a good time to create a file with five dummy low score values and set your high score array data to that.

Now, when someone finishes the game, you compare their score to the lowest on the list.
If it is not greater, then they don't go on the list, so you don't have to have them input anything.
If it is greater than the lowest score, then replace the lowest score with their score.
Then loop through the four "higher" score positions, and compare the trailing score against that score, and if the trailing score is greater, than swap the entries (i.e. you've written a score in the 5th slot, so starting at the 4th slot, if the 5th score is greater than the 4th, swap the 4th and 5th).
You continue with the next (is 3rd > 4th) and when the answer is no, the scores are sorted.
You would normally just do this in a simple loop, looping backwards until the preceeding score is > than the succeeding score and then exit the loop at that point.
Now, you can write those highscore values out to your save file.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Reply With Quote
  #5  
Old 04-17-2012, 09:17 AM
DrPunk's Avatar
DrPunk DrPunk is offline
Senior Contributor

* Expert *
 
Join Date: Apr 2003
Location: Never where I want to be
Posts: 1,403
Default

The array's a bit of an issue because of the player name associated with the score.

For that reason it'd be worth creating a highscore class and using IComparible on your class so that the array can be sorted by score. It's not as daunting as it sounds...
Code:
Public Class HighScore
    Implements IComparable(Of HighScore)

    ' public variables because I can't be bothered typing out the properties
    Public PlayerName as String
    Public PlayerScore as Integer

    Public Sub New(byval name as string, byval score as integer)
        Me.Playername = name
        me.PlayerScore = score
    End Sub

    Public Function CompareTo(ByVal other As highscore) As Integer Implements System.IComparable(Of highscore).CompareTo
        return Me.PlayerScore.CompareTo(other.PlayerScore)
    End Function

    Public Overrides Function ToString() As String
        Return me.playerName & ": " & me.playerScore.ToString
    end sub
End Class
An array of HighScores can now act like an array of integers when calling Array.Sort to get the scores in order.
__________________
There are no computers in heaven!
Reply With Quote
  #6  
Old 04-17-2012, 11:27 AM
qweqwe256 qweqwe256 is offline
Newcomer
 
Join Date: Apr 2012
Posts: 7
Default

Quote:
Originally Posted by AtmaWeapon View Post
One way to diagnose a problem is to substitute known values for variables when you read the code. This can shed a lot of light on what's going on. Here's what I mean.

Let's give the following start values:
LblScoreValue.Text = "300"
TextBox_Player.Text = "Rose"

The rest are assigned via code. So we'll take this line:
Code:
aryText(1) = Tetris.Tetris.LblScoreValue.Text
...and consider it like this instead:
Code:
aryText(1) = "300"
Consider these two cases:
Code:
If Tetris.Tetris.LblScoreValue.Text > aryText(1) Then
    aryText(1) = Tetris.Tetris.LblScoreValue.Text
    objWriter.WriteLine(TextBox_Player.Text & " " & aryText(1))
ElseIf Tetris.Tetris.LblScoreValue.Text > aryText(2) Then
    aryText(2) = Tetris.Tetris.LblScoreValue.Text
    objWriter.WriteLine(TextBox_Player.Text & " " & aryText(2))
Code:
If "300" > "0" Then
    aryText(1) = "300"
    objWriter.WriteLine("Rose" & " " & "300")
ElseIf "300" > "0" Then
    aryText(2) = "300"
    objWriter.WriteLine("Rose" & " " & "300")
This brings up multiple problems, but the most pressing is you don't change which name you're writing. That's why you get the same name each time. Here's some suggestions.

Normally high score logic looks like this:
Code:
1. Read the list of names and scores from the file.
2. Add the current name and score to the appropriate place in the list.
3. Trim the list.
4. Write the list to a file.
Each of those pieces is an interesting discussion in and of itself.

1. Read the list of names and scores.
You're not reading the old high scores file right now; there's not much point to writing it if you don't read it later. You've currently only got an array of scores; that means you'll lose the old names.

2. Add the current name and score to the appropriate place.
If you think through your current logic, you'll replace /every/ score, because if the score is the highest it's automatically greater than all the lower scores. That's why my step 2 involves finding the right place. A simple way to do it if you've got a list that supports insertion:
Code:
1. For each element in the list:
    1.1. If score > currentScore Then
        1.1.1. Insert the score before this position
        1.1.2. Stop searching
2. If no replacement occurred:
    2.1. Add the score to the end of the list
3. Trim the List and 4. Write the list to the file
These can be combined. If you want 5 items, only write 5 items to the file. If the last score was lower than any high scores, it'll get dropped.

Give it another shot with these hints in mind and see if you have more success.

Thx for the advices so far.

I'm gonna implement that feature that the form should pop out only if the score is bigger than array 5 later after i sort the writing/reading problem first.


So i have a couple of questions?

1.In the logic of my code if I switch and start from the bottom of the code I get the same thing because if LblScoreValue.Text>aryText(1) but smaller than aryText(2) it's ok. but if LblScoreValue.Text>aryText(2), it's gonna change both aryText(1) and (2) and if it's the biggest it's gonna replace all of them again, so it's gonna be the same result. 5 times the same thing

2.how do i read the names and scores in the file. using Console.ReadLine() or StreamReader. I can't get the sintax right for both of them

So it's like this the score at game over must read the file to see if it's bigger than #5, if it is replace aryText(5) with the new value, but if it's bigger than aryText(4), how to replace first aryText(4) with aryText(5) and then get the new value, so that it seems like the position has dropped one spot.

3. for your :
Quote:
For each element in the list:
1.1. If score > currentScore Then
1.1.1. Insert the score before this position
1.1.2. Stop searching
Stop searching should be like a break in C. So what's the equiv in vb.net. End Loop ?

I'm ataching a diagram of what i'm looking to achieve maybe it will make things clearer.

I must certainly be complicating my like too much, there must be an easier way.
Attached Images
File Type: jpg scorelogic.jpg (214.4 KB, 6 views)
Reply With Quote
  #7  
Old 04-17-2012, 03:09 PM
qweqwe256 qweqwe256 is offline
Newcomer
 
Join Date: Apr 2012
Posts: 7
Default Am i going in the right direction ?

Ok , so I rewrote the code a bit differently, I made a different string for every player name, i'm not using the same on for every player. Also I'm trying to read first the file and then rewrite it. The problem is that if i try first to read it before writing it for the first time, is says the file doesnt not exists. And I try to write the file first and then read it , it gives me an error like "The process cannot access the file 'C:\....\bin\Debug\scor.txt' because it is being used by another process." So i'm thinking streamreader is in conflict with streamwriter. This is the code:

Code:
 Private Sub bt_Ok_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_OK.Click      
        Dim FILE_NAME As String = "scor.txt"
        Dim Scor(5) As String
        Dim Nume(5) As String
        Dim i As Integer

        For i = 1 To 5

            Dim objreader As New System.IO.StreamReader(FILE_NAME)

            Do While objreader.Peek() >= 0
                Console.WriteLine(objreader.ReadLine())
            Loop
            objreader.Close()

            Dim objWriter As New System.IO.StreamWriter(FILE_NAME)

            If Tetris.Tetris.LblScoreValue.Text > Scor(1) Then
                TextBox_Player.Text = Nume(1)
                Tetris.Tetris.LblScoreValue.Text = Scor(1)
                objWriter.WriteLine(Nume(1) & " " & Scor(1))
                objWriter.Close()

            ElseIf Tetris.Tetris.LblScoreValue.Text > Scor(2) Then
                TextBox_Player.Text = Nume(2)
                Tetris.Tetris.LblScoreValue.Text = Scor(2)
                objWriter.WriteLine(Nume(2) & " " & Scor(2))
                objWriter.Close()

            ElseIf Tetris.Tetris.LblScoreValue.Text > Scor(3) Then
                TextBox_Player.Text = Nume(3)
                Tetris.Tetris.LblScoreValue.Text = Scor(3)
                objWriter.WriteLine(Nume(3) & " " & Scor(3))
                objWriter.Close()

            ElseIf Tetris.Tetris.LblScoreValue.Text > Scor(4) Then
                TextBox_Player.Text = Nume(4)
                Tetris.Tetris.LblScoreValue.Text = Scor(4)
                objWriter.WriteLine(Nume(4) & " " & Scor(4))
                objWriter.Close()

            ElseIf Tetris.Tetris.LblScoreValue.Text > Scor(5) Then
                TextBox_Player.Text = Nume(5)
                Tetris.Tetris.LblScoreValue.Text = Scor(5)
                objWriter.WriteLine(Nume(5) & " " & Scor(5))
                objWriter.Close()

            End If
        Next
        Me.Close()
    End Sub
End Class

Last edited by passel; 04-17-2012 at 04:46 PM. Reason: Added [code] tags
Reply With Quote
  #8  
Old 04-18-2012, 06:43 AM
DrPunk's Avatar
DrPunk DrPunk is offline
Senior Contributor

* Expert *
 
Join Date: Apr 2003
Location: Never where I want to be
Posts: 1,403
Default

You don't need to read and write the file 5 times, which is what your loop will be doing.

It would be far easier to have an array of highscores that when your program starts it reads the current highscores into the array. When someone finishes their game it checks if it's a highscore against the array and if it is it removes the lowest score from the array (if the array contains the maximum number of high scores) and puts the new score into the array and then writes the array out to the file.

That breaks it down into seperate methods to write, where each method has a particular task (this uses the HighScore class I detailed above)...
Code:
Private Sub ReadHighScores(byval filePath as string) as HighScore()
    ' Read the file and return an array of highscores
End Sub

Private Sub WriteHighScores(byval filePath as string, byval highscores() as HighScore)
    ' Write the array to the file
End Sub

Private Function IsHighScore(byval newScore as integer, byval highScores() as HighScore) as Boolean
    ' Check the array to see if newScore is higher than any of the existing highscores
    ' and return true if it is
End Function

Private Sub AddNewHighScore(byval newScore as HighScore, byval highScores() as HighScore)
    ' Remove the lowest score from the array if array is at MaxHighScores and add the new score
End Sub
Then, when the game has finished it goes along the lines of...
Code:
' The array containing the highscores.
' In the form load then this is set to the return of ReadHighScores
Dim MyHighScores() as HighScore

Private Sub bt_Ok_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_OK.Click 

    dim userName as string
    dim h as highscore

    If IsHighScore(cint(Tetris.Tetris.LblScoreValue.Text), MyHighScores) Then
    
        ' Get a name for them.
        userName = InputBox("Enter name:", "You got a high score")

        h = new HighScore(username, cint(Tetris.Tetris.LblScoreValue.Text))

        AddNewHighScore(h, MyHighScores)

        WriteHighScores([A file to save them to], MyHighScores)
    end if
End Sub
It's readable as to what it's doing, each seperate process is fairly easy to write because it only has to achieve a particular task (and it's easy enough to test that it achieves its task) and it's possible to change the logic of a particular step without screwing up anything else.
__________________
There are no computers in heaven!

Last edited by DrPunk; 04-18-2012 at 07:49 AM.
Reply With Quote
  #9  
Old 04-18-2012, 10:50 AM
qweqwe256 qweqwe256 is offline
Newcomer
 
Join Date: Apr 2012
Posts: 7
Default

I'm sorry, I don't understand your methods. I just wanted to understand why my method wasn't working. Not make a whole different logic to the game. I have 3 forms : the main gameform one where the inputform pops put at the end of the game, then i got inputform that needs to check the information in the file.txt and make the necesary changements if it's a highscore and then i got a thirf form Highscoreform that must display the top 5 scores.
I just wanted to modify my code a bit so that it would work, not make a whole new one, because i'm new at vb and I juggling with so many subs and forms is too much for me.


In the gameform i Have,

If GameOver=true Then

'................

If score > highscore.array(5)
Show inputform
End if
'................

In the input form

I have to see if the gameform.score is bigger than 4,3,2,1 ' where does it stop,( so there must be a read function somewhere), after that write the new code over the line which is smaller than it, and decrement the rest of the scores by one line.

in the higscoreform

replace each labelanames and labelscores in the form with the names and the scores that match those names from the file.txt
Reply With Quote
  #10  
Old 04-18-2012, 11:00 AM
DrPunk's Avatar
DrPunk DrPunk is offline
Senior Contributor

* Expert *
 
Join Date: Apr 2003
Location: Never where I want to be
Posts: 1,403
Default

Quote:
Not make a whole different logic to the game.
Working logic as opposed to not working logic. It's not different. It does what you want it to do.

You're struggling to understand why what you've written doesn't do what you want it to. That suggests it's badly written. I've tried to show you how you could write it so that it's easier to work out what it's doing.

You've taken something that didn't work, you didn't know why it didn't work, then changed it to try and make it work and still don't understand why it doesn't work. On top of that you then want someone else to work out what it's doing in order to tell you why it's not doing what it should be doing.

Maybe someone else would like to do that. I don't. Sorry. But I can see it's reading and writing the file 5 times and it shouldn't be doing that, along with your original code that never worked. It would just be better if it was written well.
__________________
There are no computers in heaven!
Reply With Quote
  #11  
Old 04-18-2012, 11:19 AM
qweqwe256 qweqwe256 is offline
Newcomer
 
Join Date: Apr 2012
Posts: 7
Default point taken

I understand your point of view. You're right.

Can you be more specific with your sub then, so i can finally finish this thing?
More clearly, how do i write 5 lines, how to i read and compare those 5 lines with the new score. how do i rewrite it. I know it sound needy, but i've been searching forums and tutorials for the last 4 days and I only got like general methods that i couldn't apply here or other useless stuff.


Code:
Private Sub ReadHighScores(byval filePath as string) as HighScore()
    ' Read the file and return an array of highscores
End Sub

Private Sub WriteHighScores(byval filePath as string, byval highscores() as HighScore)
    ' Write the array to the file
End Sub

Private Function IsHighScore(byval newScore as integer, byval highScores() as HighScore) as Boolean
    ' Check the array to see if newScore is higher than any of the existing highscores
    ' and return true if it is
End Function

Private Sub AddNewHighScore(byval newScore as HighScore, byval highScores() as HighScore)
    ' Remove the lowest score from the array if array is at MaxHighScores and add the new score
End Sub
Reply With Quote
  #12  
Old 04-18-2012, 11:30 AM
DrPunk's Avatar
DrPunk DrPunk is offline
Senior Contributor

* Expert *
 
Join Date: Apr 2003
Location: Never where I want to be
Posts: 1,403
Default

Quote:
Originally Posted by qweqwe256 View Post
I'm sorry, I don't understand your methods.
I should maybe at least answer this.

The method names are pretty self explanatory.

The ReadHighScores one's probably the hardest but the others shouldn't take much effort.

For example...
Code:
Private Function IsHighScore(byval newScore as integer, byval highScores() as HighScore) As Boolean
   
    dim h as HighScore
    dim isHigh as boolean = False

    ' How many high scores are recorded?
    if highScores.Length < MAXHIGHSCORES then ' MAXHIGHSCORES is 5 for you, but it's worth making it 
                                                    ' a constant so you can easily change it and refer to it elsewhere

        ' There is space for new high scores so it must be a high score
        isHigh = True

    Else

        ' There are high scores. Look at each high score, order doesn't matter
        For each h in highScores

            ' Is the new score higher than this existing high score?
            if newScore > h.PlayerScore then

                ' It is! This score is a new high score
                isHigh = True

                ' No need to check any more scores
                exit for

            end if
        Next
    end if

    return isHigh
End Function
Again, it's easy to see what it's doing. Or more importantly if it's not doing what it should be doing, why it isn't.

No doubt the other 3 will be in this thread by the end of the week.

Edit :- I would like to add, that the main point of this is that one of the tasks that you need to complete is working out if a score is a high score or not. How you go about working out it's a high score is your own business. I imagine everyone here would have a different way of doing it. But anyone tackling this problem would have to overcome working out that a new score is a high score. So, stick that calculation into a function. It's the same for the other tasks. They've got to be done. How everyone does them will be different. And they're worth putting in their own methods.
__________________
There are no computers in heaven!

Last edited by DrPunk; 04-18-2012 at 11:45 AM.
Reply With Quote
  #13  
Old 04-18-2012, 11:54 AM
DrPunk's Avatar
DrPunk DrPunk is offline
Senior Contributor

* Expert *
 
Join Date: Apr 2003
Location: Never where I want to be
Posts: 1,403
Default

I'm reluctant to type out all the code.

Rather than always having 5 high scores I've based all this on having no high scores to maxhighscores.

Writing the high scores, you already know about the StreamWriter to use and the IsHighScore that I wrote shows how to loop over every score. The HighScore class has a .ToString function to use to write the properties to the file.

Amending the high scores array, like with the IsHighScore function should first check the length of the array and if there's less than maxhighscores it can just dump it into the highscore array (Redim preserve the array to .GetUpperBound(0) + 1 of the array). If the array is "full" then you want to sort it (using Array.Sort that the IComparable interface of the HighScore class will let you use) then replace the last item (maxhighscores - 1) with the new high score. Obviously it won't be in order any more but it will have replaced the lowest score with the new score.

Reading the high scores, you can read it line by line and split the line by ":" which seperates the username and score in to seperate elements of .ToString. Then use those to create highscore classes and put them into an array. Reading should check if the file exists and create an empty highscores array if there is no file (as far as an empty array goes, you could check if HighScores is nothing in certain places in the code like when the IsHighScores function checks the length of the array an array of nothing would cause an error and so a Is Nothing check should maybe be in there, or you could Redim an array with -1. See -> http://msdn.microsoft.com/en-us/libr...(v=vs.80).aspx for more information on empty arrays).
__________________
There are no computers in heaven!

Last edited by DrPunk; 04-18-2012 at 12:04 PM.
Reply With Quote
  #14  
Old 04-19-2012, 07:07 AM
DrPunk's Avatar
DrPunk DrPunk is offline
Senior Contributor

* Expert *
 
Join Date: Apr 2003
Location: Never where I want to be
Posts: 1,403
Default

I've done the code for the other routines. I've tried it and it appears to be working OK. It uses 2 Buttons (Button1 and Button2) and a NumericUpDown control (NumericUpDown1). Button1 does the high score stuff on the value of NumericUpDown1. Button2 puts the scores into a messagebox on the screen using a new DisplayScores method I've added.

Code:
Public Class Form1

    Private Const MAXHIGHSCORES = 5
    Private Const SCOREFILE = "C:\Temp\Scores.txt"

    Dim MyHighScores() As HighScore
    
    Private Function ReadHighScores(ByVal filePath As String) As HighScore()
        ' Read the file and return an array of highscores
        Dim sr As IO.StreamReader
        Dim line As String
        Dim params() As String

        Dim highScores() As HighScore
        Dim h As HighScore

        ' Initialise the array as empty. If there's no file there will be no scores
        ReDim highScores(-1)

        ' Check that the file exists
        If IO.File.Exists(filePath) Then
            Try

                sr = New IO.StreamReader(filePath)

                ' read each line of the file creating highscores as we go along
                While Not sr.EndOfStream
                    line = sr.ReadLine

                    ' Check that there's something in the line. Writeline of WriteHighScores
                    ' will leave a blank line at the end
                    If line.Length > 0 Then
                        ' Split the line into its name and score parameters
                        params = line.Split(":")

                        ' Use those to create a highscore
                        h = New HighScore(params(0), CInt(params(1)))

                        ' Increase the size of the array by one and add the high score
                        ReDim Preserve highScores(highScores.GetUpperBound(0) + 1)
                        highScores(highScores.GetUpperBound(0)) = h
                    End If
                End While

            Catch ex As Exception
                Throw
            Finally
                sr.Close()
                sr.Dispose()
            End Try

        End If

        Return highScores
    End Function

    Private Sub WriteHighScores(ByVal filePath As String, ByVal highscores() As HighScore)
        ' Write the array to the file
        Dim sw As IO.StreamWriter
        Dim h As HighScore

        ' Are there any high scores recorded
        If highscores.Length > 0 Then

            Try
                ' Overwrite an existing high score file
                sw = New IO.StreamWriter(filePath, False)

                ' Work through each high score and add it to the file
                For Each h In highscores
                    sw.WriteLine(h.ToString)
                Next
            Catch ex As Exception
                Throw
            Finally
                sw.Close()
                sw.Dispose()
            End Try
            
        End If
    End Sub

    Private Function IsHighScore(ByVal newScore As Integer, ByVal highScores() As HighScore) As Boolean

        Dim h As HighScore
        Dim isHigh As Boolean = False

        ' How many high scores are recorded?
        If highScores.Length < MAXHIGHSCORES Then ' MAXHIGHSCORES is 5 for you, but it's worth making it 
            ' a constant so you can easily change it and refer to it elsewhere

            ' There is space for new high scores so it must be a high score
            isHigh = True

        Else

            ' There are high scores. Look at each high score, order doesn't matter
            For Each h In highScores

                ' Is the new score higher than this existing high score?
                If newScore > h.PlayerScore Then

                    ' It is! This score is a new high score
                    isHigh = True

                    ' No need to check any more scores
                    Exit For

                End If
            Next
        End If

        Return isHigh
    End Function

    Private Function AddNewHighScore(ByVal newScore As HighScore, ByVal highScores() As HighScore) As HighScore()
        ' Remove the lowest score from the array if array is at MaxHighScores and add the new score

        ' Check to see how many scores are recorded
        If highScores.Length < MAXHIGHSCORES Then
            ' Less than the maximum means increase the size of the array
            ReDim Preserve highScores(highScores.GetUpperBound(0) + 1)
        Else
            ' At the maximum means we want to replace the lowest score so get the array in
            ' order
            Array.Sort(highScores)
            Array.Reverse(highScores)
        End If

        ' Record the score at the last element. Either empty or the lowest scores
        highScores(highScores.GetUpperBound(0)) = newScore

        Return highScores
    End Function

    Private Sub DisplayScores(ByVal highScores() As HighScore)
        Dim h As HighScore
        Dim scores As String = ""

        Array.Sort(highScores)
        Array.Reverse(highScores)

        For Each h In highScores
            scores &= h.ToString & vbCrLf
        Next

        MessageBox.Show(scores)
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' When the form loads, read the high scores
        MyHighScores = ReadHighScores(SCOREFILE)
    End Sub

    Private Sub bt_Ok_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim userName As String
        Dim h As HighScore

        If IsHighScore(NumericUpDown1.Value, MyHighScores) Then

            ' Get a name for them.
            userName = InputBox("Enter name:", "You got a high score")

            h = New HighScore(userName, NumericUpDown1.Value)

            MyHighScores = AddNewHighScore(h, MyHighScores)

            WriteHighScores(SCOREFILE, MyHighScores)
        End If
    End Sub
   
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        DisplayScores(MyHighScores)
    End Sub

    
End Class
A couple of things have changed since I tried getting this to work.

My passing on the Array by value to AddNewHighScore was wrong, so AddNewHighScore is now a function and returns the array with the new score in it.

I could've got around the AddNewHighScore problem by having it access MyHighScores instead of passing the array (or could've ByRef'd), but it's quite nice to have methods working on stuff you can pass to it if you can so that it doesn't rely on external stuff if you wanted to use the method elsewhere (like passing SCOREFILE instead of using it in the methods). Ideally for that reason the whole workings of high scores that's in Button1.Click should really be in it's own method and passing the high score to it rather than using a control's value. But hey ho, there's always room for improvement.

The order that the array gets sorted into is Ascending when it really should be descending. Therefore I've gone for reversing the array after sorting it. Not a great technique if the array is large (but it's 5 here so it's hardly cpu breaking). The alternative would be to go and change the CompareTo in the HighScore class so that it compared the numbers the other way round, but I thought I'd go with the simpler option that works with the class I've already posted instead of having to change that class too.

I didn't do much in the way of error handling so that should really be addressed.

As the code stands, it will happily cope with increasing the MAXHIGHSCORES number but will go a bit screwy on decreasing it less than the current number of high scores. It should also be noted that scores of 0 are high scores.

Usernames with a ":" in them will cause the reading of high scores to error.
__________________
There are no computers in heaven!

Last edited by DrPunk; 04-19-2012 at 07:31 AM.
Reply With Quote
  #15  
Old 04-20-2012, 09:43 AM
qweqwe256 qweqwe256 is offline
Newcomer
 
Join Date: Apr 2012
Posts: 7
Default

Code:
Public Class Form1

    Private Const MAXHIGHSCORES = 5
    Private Const SCOREFILE = "C:\Temp\Scores.txt"

    Dim MyHighScores() As HighScore
Related to my game , what is form1, and in
Code:
   Dim MyHighScores() As HighScore
. Who is HighScore. It's asking me to declare it.
Reply With Quote
  #16  
Old 04-20-2012, 10:04 AM
DrPunk's Avatar
DrPunk DrPunk is offline
Senior Contributor

* Expert *
 
Join Date: Apr 2003
Location: Never where I want to be
Posts: 1,403
Default

Quote:
Originally Posted by DrPunk View Post
The array's a bit of an issue because of the player name associated with the score.

For that reason it'd be worth creating a highscore class and using IComparible on your class so that the array can be sorted by score. It's not as daunting as it sounds...
Code:
Public Class HighScore
    Implements IComparable(Of HighScore)

    ' public variables because I can't be bothered typing out the properties
    Public PlayerName as String
    Public PlayerScore as Integer

    Public Sub New(byval name as string, byval score as integer)
        Me.Playername = name
        me.PlayerScore = score
    End Sub

    Public Function CompareTo(ByVal other As highscore) As Integer Implements System.IComparable(Of highscore).CompareTo
        return Me.PlayerScore.CompareTo(other.PlayerScore)
    End Function

    Public Overrides Function ToString() As String
        Return me.playerName & ": " & me.playerScore.ToString
    end sub
End Class
An array of HighScores can now act like an array of integers when calling Array.Sort to get the scores in order.
This class that I created earlier in this thread is the HighScore class. The program uses an array of these.

As far as Form1 goes, that's the form of the application.

Create a new project, that will create Form1. When you open the code file for Form1, all the is there until you start adding code is...
Code:
Public Class Form1

End Class
If you want to post the code into an existing form then just copy the bits between the Public Class and End Class parts of the class.

Same with the HighScore class. In the project menu, choose Add Class. It'll ask you for a name, call it HighScore. It'll open the file and you'll just have...
Code:
Public Class HighScore

End Class
... so you can select everything between those parts of the class in this post to copy and paste in between the Public Class and End Class.

If that all makes sense.
__________________
There are no computers in heaven!
Reply With Quote
Reply

Tags
file, highscore, read, save, table


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
 
 
-->