Difference between revisions of "Maximum high score"

From TheAlmightyGuru
Jump to: navigation, search
(Why Not Prevent All Buffer Overruns?)
(Custom Integers)
 
Line 57: Line 57:
 
|}
 
|}
  
The custom integer is setup just like a decimal numbers, so, if the player has a 9 in the "Score 6" place holder, and gets one more point, the value will overflow into the place holder to the left. Thus, the "Score 5" place holder will become a 1 and the "Score 6" place holder will be reset to 0.
+
The custom integer is setup just like a decimal number, so, if the player has a 9 in the "Score 6" place holder, and gets one more point, the value will overflow into the place holder to the left. Thus, the "Score 5" place holder will become a 1 and the "Score 6" place holder will be reset to 0.
  
 
Now, suppose a skilled player racks up a massive score and has obtained a score of 999,999, making the memory look like this:
 
Now, suppose a skilled player racks up a massive score and has obtained a score of 999,999, making the memory look like this:

Latest revision as of 19:21, 17 March 2024

Achieving the maximum score in Adventures of Dino Riki.

A maximum high score is the largest possible score a player can achieve in a video game. Computers can't store infinitely large numbers, so, all games which maintain a score will eventually top out. What happens when this occurs depends on how the game was programmed. Common results when the score reaches its maximum include: it stops increasing, it rolls back to zero, or the game glitches.

Buffers

When a game uses a score, the programmer must designate a section in the computer's memory where the score will be stored. This area is called a "memory buffer." In order for the player to know their score, the designer must also designate an area on the screen where the score will be displayed, which is a "screen buffer."

Technically speaking, a memory buffer can be any size within the available memory of the hardware, but, the larger it is, the less memory the developer has for the rest of the game. Likewise, a screen buffer could be the entire width of the screen, but that would leave less room on the screen for the rest of the game. These limitations usually result in the buffers being only as large as they need to be. While the memory and screen buffers do not have to be the same size, to help optimize space, their length is usually tied to one another. Thus, if the screen buffer only allows for six digits of score, the memory buffer will probably only allow six digits of score as well.

As the player progresses through the game and their score grows, it begins to fill up the buffer. If the score continues to grow beyond the constraints of one of the buffers, a "buffer overrun" will occur which may cause the program to glitch. An overrun in the screen buffer will usually just result in a cosmetic glitch; the score may be drawn outside of its designated area, or a number may be displayed as a letter or other graphic instead. An overrun in the memory buffer, however, may result in the game crashing or some other serious error.

Preventing a Buffer Overrun

After enterprising gamers began causing buffer overruns in the score of early video games, developers began adding code to prevent them from occurring. There are two primary methods for managing this: stop counting or roll back to zero.

For the stop counting method, the designer chooses a maximum high score within the confines of the buffer and prevents the score from ever going above that. For example, they may choose 999,999 points. Once the player reaches 999,999, they can never increase the score higher than that. Usually the game simply throws away all subsequent points, but some games execute a planned game over. This method is easy to program and implement, but it's not very satisfying to the player who wants to continue to break their record. When expert players find it too easy to reach the maximum high score, they sometimes begin challenging themselves by seeing how quickly they can reach the maximum high score.

For the roll back to zero method, the programmer also chooses a maximum high score within the confines of the buffer, but, instead of stopping the score from increasing, they roll it beck to zero and keep counting from there. This method is also easy to program and implement, but it has the benefit of allowing the player to continue playing with the score being maintained by the game. The only drawback is the player must be aware of how many times they've elapsed the score when they finally succumb to a game over.

For games which roll back to zero, the math may differ depending on how it's programmed. Usually, the overflow is carried over, so, if the maximum score is 999,999, the current score is 999,900, and the player earns 500 points, the score will be rolled to 400. An alternate way to handle this is to simply reset the score to zero when a point gain would make it surpass its maximum, and the player would lose their 400 point overflow. However, for technical reasons, it's less likely a game will be programmed this way.

Why Not Prevent All Buffer Overruns?

Most of the time, when a game doesn't trap a buffer overrun, it's because the programmer never thought a player would be good enough to rack up a high score large enough to overrun the buffer. However, there are practical reasons for not protecting against a buffer overrun, for example, they slow down the game, and they take up space.

It's not just the score that can overrun its buffer, every number the game has to keep track of can overrun its buffer too. Consider a game where the stage is represented by a number which continuously increases as the player progresses. It will also overrun its buffer unless it's protected. What about an RPG where each character's experience, gold pieces, and stats increase throughout the game? All of those numbers use buffers as well, which means they can overrun.

To completely eliminate buffer overruns, every single time any number is changed in a game, the program must perform a check to verify that the new number will not be outside the boundaries of its buffer. If a game really did perform all these checks, it would slow down to a crawl. And, even though modern computers are thousands of times faster, modern games have thousands of times more variables to deal with, so this is a problem even today. Because of this, programmers have to try to determine which numbers can realistically overrun their buffers during ordinary game play and only protect against those.

However, each protection needs to be programmed, and this brings up the second problem, all this code takes up space. A clever programmer will be able to reuse much of their buffer overrun protection code, but, in the early days of video games, even a small amount of code took away a significant percentage of the available space. This resulted in a trade off for the designers: do they want to include a new feature in their game, or, do they want to protect against a buffer overrun that can only occur when an especially skilled player plays for hours without dying? Usually the new features win out.

Examples of Buffer Overruns

The result of a buffer overrun is dependent upon whether it's a screen or memory buffer overrun, how the buffer is setup, and what is located around the buffer in memory.

Screen Buffer Overruns

Screen buffer overruns usually only cause cosmetic problems.

Built-in Integer Overruns

Every CPU that has ever been used as a video game platform has a built-in integer for storing numbers, and they come with their own memory buffer. Since they're optimized for the system, most of the numbers stored in games use these built-in integers for their memory buffers. The size of the integer and its buffer increases along with the bit-size at an exponential rate. An 8-bit integer experiences a buffer overrun above 255, a 16-bit integer above 65,535, a 32-bit integer above 4,294,967,295, and a 64-bit integer above 18,446,744,073,709,551,615.

Since 64-bit integers have such a large buffer, it's unlikely that a memory buffer overrun will occur during normal game play (unless the game awards an insane number of points for things). However, even today, just because a CPU supports larger integers, that doesn't mean the programmer is forced to used them. They may still choose to use a smaller integer to save space.

When a memory buffer overrun occurs in a built-in integer, the typical response of the CPU is to roll the integer back to zero with the overflow carried over. So, if an 8-bit integer is currently at 254, and the game adds 5 to it, the new value will be 3. Internally, the CPU will set something called a "carry register" which will allow the programmer to know that an overflow took place, and write code to process it as needed.

Although such an overflow won't directly crash the program, sometimes wrapping the number back to zero may create unexpected consequences. For example, if the player's lives are stored in an 8-bit integer, and they have 255 lives, then get a 1-up, the CPU will roll the value back to zero. And, when a player has zero lives, they get a game over!

Custom Integers

8-bit CPUs only support 8-bit integers with a max value of 255, but many 8-bit games display numbers greater than 255 by using custom integers. See 255 in video games for how this happens. There are many ways in which custom integers can be implemented, but most of them overflow in a similar manner, a nearby are of memory is corrupted. Below I help illustrate how this happens. Imagine a game where the score is expected to be no more than six digits in size, and each digit is stored in a single byte in memory. When the game first starts, the score is zero, so all the memory addresses will be set to zero like so:

Score 1 Score 2 Score 3 Score 4 Score 5 Score 6
0 0 0 0 0 0

The custom integer is setup just like a decimal number, so, if the player has a 9 in the "Score 6" place holder, and gets one more point, the value will overflow into the place holder to the left. Thus, the "Score 5" place holder will become a 1 and the "Score 6" place holder will be reset to 0.

Now, suppose a skilled player racks up a massive score and has obtained a score of 999,999, making the memory look like this:

Score 1 Score 2 Score 3 Score 4 Score 5 Score 6
9 9 9 9 9 9

The buffer is full, but player earns one more point, and there isn't any code to prevent the buffer from overrunning, so the normal logic goes into work. Score 6 is a 9, so it overflows into Score 5, but it's a 9, so it overflows into Score 4, and so on. This continues until it gets to Score 1, which is also a 9, and it overflows into the next area of memory as seen below:

Other Score 1 Score 2 Score 3 Score 4 Score 5 Score 6
1 0 0 0 0 0 0

Now, what happens is all dependent upon what is stored in that Other place in memory. If it is unused, then all that will happen is the score will appear to roll back to zero. However, if that memory stores something important to the game, whatever value was there will now be overwritten with the number 1. If, for example, the player's lives were stored in that area of memory, the player could be doing very well, with a score of 999,999 and 35 lives.

Lives Score 1 Score 2 Score 3 Score 4 Score 5 Score 6
35 9 9 9 9 9 9

However, the moment they get another point, they will overrun the buffer, and their 35 lives will be overwritten with the 1 from the score, causing them to immediately lose 34 lives!

Lives Score 1 Score 2 Score 3 Score 4 Score 5 Score 6
1 0 0 0 0 0 0

Links