gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

C/C++ > Shifting Arrays for High Scores Trouble.

#97114 - chatterbug89 - Tue Aug 08, 2006 1:38 am

I've been at this for a couple days and am sort of stumped. I have a system set up where the high scores are saved in a text file, and when read, the high scores are loaded into 2 arrays, AdventureScores and AdventureNames (there are actually 4...but, that doesn't really matter for my question). The scores are stored as text int he AdventureScores arrays, 6 digits for every score. So every 6 new digits, there is a new score. For the AdventureNames array, there are 3 letters to a name, so every 3 spaces, there is a new high score name.

Creating this file, reading it, etc. I have all working great. But, shifting the arrays to add new scores is causing me problems. One more thing before I show some code. 0 is the higest score. The higher the number, the lower the score place. At the momment, I have it working so that if you get a new higest score (a score greater than what is at 0), everything shifts down fine, clearing the lowest score, and making room for writing the new high score in the particlar place.

The following code is actually just part of a function of mine, but, I should have it so everything that concerns this question is included with it and enough to actually run it is included.

EDIT2: By the way, there are 10 high scores. That's why the names array is 30 (3 letters * 10 entries) and the score array is 60 ( 6 digits * 10 entries). ;-)

Code:

/*****Check if we have made a high score in adventure mode.  If so, save the new high scores******/
//This following code checks if we made a new high score and records the place.
//Cscores was converted to an array of intigers from AdventureScores.
//This code *should* be fine.
//This first conditional statement see's if our current score is higher than the lowest high score in a list of 10 high scores.
if ( score > Cscores[9] ){
   // Our score is bigger than our highest score, so we have a high score!
   if (score > Cscores[0] ){
      //We have a new TOP score!
      Cscores[0] = score;
      scoreplace = 0;
   }
   else{
      //Begin the loop to determine where we are.
      scoreplace = -1; // Initially we wont want to kill the loop.
      for ( i = 9; (i >= 0) && (scoreplace == -1); ++i ){
         if (score < Cscores[i]){
            //We have found a high score higher than our new high score, so our new high score must go below it.
            Cscores[i+1] = score;
            scoreplace = (i+1); // Kill the Loop & set the place we scored.
         }
      }
   }
   //Move all the scores down one level from the new high level place
   //This is the part where i'm having the problems.
   //First we begin a for loop that goes 3 times.  Since there are 3 spaces for a name, we have to do a shift tot he write three times.
   for (i = 0; i < 3; ++i){
      // If it isn't our first time, we need to copy the temp array to the orignal array, since we are shifting it again.
      if ( i != 0 ){
         for ( p = 0; p < 30; ++p)
            AdventureNames[p] = AdventureNamesTemp[p];
      }
      //This is suspose to determine where we should start shifting from....this part is where i'm unsure.
      actualscoreplace = scoreplace * 3;
      if (actualscoreplace == 0)
         actualscoreplace = 1;
      //Right now it is a loop which shifts everything to the right.
      // It doesn't matter what's in AdventureNamesTemp[0] (this varies depending ont he place, but if we had a higest top score it woudl be 0), since it will just be ovewritten
      //with the new high score later on.
      for ( q = actualscoreplace; q < 30; ++q)
         AdventureNamesTemp[q] = AdventureNames[q-1];
      // If a shift to the right diden't occur at the very beggining, we need to copy the old values to the unchangign parts of the arrays so they arn't filled with junk.
      for ( q = 0; q < actualscoreplace; ++q)
         AdventureNamesTemp[q] = AdventureNames[q];
   }
   //This part is identical to the first part, except it is for the scores, which are 6 spaces instead of 3.
   for (i = 0; i < 6; ++i){
   if ( i != 0 ){
      for ( p = 0; p < 60; ++p)
         AdventureScores[p] = AdventureScoresTemp[p];
   }
   actualscoreplace = scoreplace * 6;
   if (actualscoreplace == 0)
      actualscoreplace = 1;
   for ( q = 1; q < 60; ++q)
      AdventureScoresTemp[q] = AdventureScores[q-1];
   for ( q = 0; q < 1; ++q )
      AdventureScoresTemp[q] = AdventureScores[q];
   }
   //This stuff doesn't realy pertain to my question..you can safely ignore it.  But, you can look at it to kind of see what's happenign witht he data after it's parsed.
   convertscoresstring(AdventureScoresTemp, scoreplace); //Write out new score array.
   writeintials(AdventureNamesTemp, scoreplace); // Get the user intials and write it to the array.
   //Write the New High Scores to the High Scores File
   ResetHighScores(AdventureScoresTemp, ClassicScores, AdventureNamesTemp, ClassicNames);
}



I left out the variable declartions (remember, this is a part of a game i'm working on)...but, I added extra comments for this example than in the orginal so everyone knew what I was doing. Anyways, as I said before, it works if the new high score is higher than AdventureScores[0]...but, if it's lower or higher than any of the other scores....weird things happen. The whole score array is messed up, and, some other score arrays for a differnt mode of game play are affected when they are never intentially modified or called (somehow, something like array[20] is being edited where array only goes up to 10...so, it affects the next array declared after it).

Any help on how to get this working would be greatly appreciated. Also, feel free to use my ideas for score shifting :).

Finally, this was the preliminary code I made to test array shifting...and it works. The difffernce between this and the above, is each element is a differnt number/score..it shoudlen't be any differnt than above in the general aspect, but ...for soem reason it just wont work. In this example, place is the place of 0-9 in the array that you want to stick your new score in. Everything is shifted from the place to make room for a new varaible, dumping the variable at the end of the array.

Code:

#include <stdio.h>

main()
{
    int i;
    int place = 9;
    int teststring[10], transferstring[10];
    for ( i = 0; i < 10; ++i)
        teststring[i] = i;
    for ( i = 0; i < 10; ++i)
        printf("%d  ",teststring[i]);
    for (i = place+1; i < 10; ++i)
        transferstring[i] = teststring[i-1];
    for ( i = 0; i < place+1; ++i)
        transferstring[i] = teststring[i];
    transferstring[place] = 9;
    printf("\n");
    for ( i = 0; i < 10; ++i)
        printf("%d  ",transferstring[i]);
    while(1)
        ;
    return 0;
}


Anyways, thanks a lot :)[/code]

EDIT: By the way, I have a feeling i'm just doing somethign realy realy stupid :s The problem lies with taking the place variable and figuring out where to start shifting from.

#97136 - tepples - Tue Aug 08, 2006 4:24 am

The quick and dirty solution: Replace the worst score with the player's score, and then sort them by score afterward. It will help if you keep each score entry in a struct:
Code:
struct AdventureScoreEntry {
  int score;
  char name[3];
};

And why are you storing scores as digits anyway? You can save 4 bytes by storing a score in a machine word.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#97143 - chatterbug89 - Tue Aug 08, 2006 5:09 am

Hmm, I could try that.

Quote:
And why are you storing scores as digits anyway? You can save 4 bytes by storing a score in a machine word.


For my save games, values such as the ammount of lives and level (which are pretty small numbers) I'll save as a single char variable into a text file. ex: 1 char woudl be the lives, another the level, etc.(EDIT: and I don't mean as ASCII text..but, a numercial number). But, I can't fit the size of the scores inside of a single char. Could you explain further?

Also, I probaly should use some structs. It would make things a little cleaner/easier :)

Tommrow i'll probally look at it a little more and try to get it working how it works now (It seems like i'm missing something so small :S...it's bugging me i guess). Otherwise, I guess i'll just resort to useing structs that contain the score and intials, write the new data to the structure that would get pushed off of the top 10 list, sort it, then write it to the file. Thanks for the tips.

#97145 - tepples - Tue Aug 08, 2006 5:23 am

Instead of storing the score in SRAM in decimal digits, store it in binary with 8 bits per char:
Code:
void pokeBinary32(unsigned char *dst, int n) {
  dst[0] = n;
  dst[1] = n >> 8;
  dst[2] = n >> 16;
  dst[3] = n >> 24;
}

unsigned int peekBinary32(const unsigned char *src) {
  return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
}

I'd suggest implementing the sort yourself, based on the directions from wikipedia:Insertion sort. Once you implement a proper insertion sort, you will know how to simplify it for the special case where all but the last element are sorted.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#97231 - chatterbug89 - Tue Aug 08, 2006 8:01 pm

Yes! I did it with my own logic. The equation for getting the poitn to start in the array for shifting was

Code:

actualscoreplace = ((scoreplace + 1) * 3) - 2;


for the intials and

Code:

actualscoreplace = ((scoreplace + 1) * 6) - 5;


for the scores.

I spent some time and carefully worked out test situations on paper and came up with the equation....I should ahve took the time and carefully did it the way I did in the first place...I guess I just got stressed because it woudlen't work.

Also....the part of the program which determines the score place....had a mistake.... And I would have never noticed it if i wasn't so sure that my equation was correct. my for loop starts at 9 and goes to 0...yet i had ++i instead of --i. That exaplains why other arrays were getting messed up.

Anyways, i'm realy glad I got it working with my logic :) I kind of got a realy high sense of accomplishment that I did it all by myself with my own logic :-P And that I diden't give up ^^. However, later on, I think I may implent your ideas, tepples...since, it would be a tad cleaner and more practical. Plus, it'd be good practice for me either way. (I need to get bitwise operators down some more also).

Thanks a lot for your help Tepples.

EDIT: Actualy, it's not compeltely done. I still need to decide how to handle duplicate high scores. I'm still sort of decicing how to handle it, so...i'll probaly work on that later today. :)

EDIT2: There was one other change I made by the way for anyone interested. The loop that wrote the origanl values tot he unchanging spots in the array, was moved out of the main for loop that shifted everything to the right. Also, at the begginign of the main for loop, I put a for loop that copied the intial arrayt o be shifted to a temporary array. The loop at the end that rewrites the variables in the array that were unchaning, gets its data from that temporary array. ;-)

#97246 - tepples - Tue Aug 08, 2006 9:08 pm

chatterbug89 wrote:
I still need to decide how to handle duplicate high scores. I'm still sort of decicing how to handle it, so...i'll probaly work on that later today. :)

A new score equal to an existing score should go below the old score unless the scores are perfect scores (e.g. 100% perfect steps in DDR), in which case the latest perfect score should go on top. In addition, each set of initials should be allowed only once on a given table; otherwise, you're just seeing who plays the game more often, not who are the best players.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#97274 - chatterbug89 - Tue Aug 08, 2006 11:23 pm

Quote:
In addition, each set of initials should be allowed only once on a given table; otherwise, you're just seeing who plays the game more often, not who are the best players.


I sort of disagree with that. Especialy in this case, where maybe the user wont share his or her game with other people. In that case, he's goign to want to see all of his or her high scores.

If one user gets 100 points, the the same user gets 50 points...
player1 - 100
Player1 - 50.

If we removed the lower one...then, player two only has to get 1 point to get that same spot, when he or she would orginally have to get over 50.

Plus...I dont' think i've ever seen a high score system where only one certain set of intials could appear on a particlar high score table. maybe there's something i'm missing in your statement.

EDIT: Oh! i think i get what you mean. If the same user, got the same score again, then, it shoudlen't be added...since as you said, it'd just be shwoing who plays more. ^^

#97276 - tepples - Tue Aug 08, 2006 11:41 pm

chatterbug89 wrote:
Quote:
In addition, each set of initials should be allowed only once on a given table; otherwise, you're just seeing who plays the game more often, not who are the best players.

I sort of disagree with that. Especialy in this case, where maybe the user wont share his or her game with other people. In that case, he's goign to want to see all of his or her high scores.

I was thinking more of the situation in an arcade machine, an Internet ranking, or a game that is shared among children in a household or college students in neighboring dorm rooms. Why would you want someone to hog the top 5 with 99.5, 99.4, 99.3, 99.2, 99.1?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#97282 - chatterbug89 - Wed Aug 09, 2006 12:02 am

Using fractiosn is kind of eagerating it, isn't it? :-P

But, I guess you do have some point, if there was something like this.
1. ABC - 105
2. ABC - 104
3. ABC - 103
4. ABC - 102

But, then if there is something like this
1. ABC - 105
2. ABC - 50

If the two entries dident' exist, getting on the high score list becomes easier. Also, taking your suggestion about how to move things. In our first example, if a differnt player got 104, they would gain either the new 2 or 3rd place, pushing everything else down. It woudlen't realy be hogging anything. Also, what's the differnce if, lets say, 4 people got 4 differnt scores like that.
1. ABC - 105
2. DEF - 104
3. GHI - 103
4. JKL - 102
...Plus....the user coudl always just change his intials to get past the restrictions to "hog" the high score.

#97284 - tepples - Wed Aug 09, 2006 12:31 am

chatterbug89 wrote:
Using fractiosn is kind of eagerating it, isn't it? :-P

In The Groove keeps a score for each song from zero to 5 times the number of steps in the song and displays it as a percentage. In machines played by a lot of expert players, you see a lot of almost perfect scores, with timing off by a hair on a handful of steps.

Quote:
If the two entries dident' exist, getting on the high score list becomes easier.

Getting on a high score list is an incentive to put quarters in and play the game. (Everything I say about "quarters" also applies to pay MMO games, even though they're usually flat rate per month.)

Quote:
Also, taking your suggestion about how to move things. In our first example, if a differnt player got 104, they would gain either the new 2 or 3rd place, pushing everything else down.

But then you have multiple people putting multiple sets of quarters in.

Quote:
Also, what's the differnce if, lets say, 4 people got 4 differnt scores like that.
1. ABC - 105
2. DEF - 104
3. GHI - 103
4. JKL - 102

Then you have four different people's high scores, and usually it means that a lot of quarters have been spent on playing that game.

Quote:
...Plus....the user coudl always just change his intials to get past the restrictions to "hog" the high score.

But then if you make a new set of initials, you lose your custom game settings. And do people regularly change their initials to get multiple lines on nintendowifi.com's world rankings for Tetris DS?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#97286 - chatterbug89 - Wed Aug 09, 2006 12:57 am

Heh, you make some good points. I guess you win :-P For a game that is goign to be in a comercial/arcade/online enviroment, I would agree with you now. But, for a personal game on a handheld, it's probally not such a great idea due to what I mentioned. For a personal game, it'll probaly be shared only with a few friends tryign to compete for new high scores and or only played by one person.