I'm really struggling in loading a high score table.
I can create a blank hi-score table and save it to disk with no problems. When I try to load the data, the program runs ok and the name is displayed ok, but the score is loaded as some high number. I'm getting confused so any help would be gratefully received.
int blank_hiscores(void)
{
// Save a new blank hi-score table
//
ofstream myfile ("hiscores.txt");
for (int n=10; n>0;n--)
{
myfile << "xxxxxx"; //name
myfile << "\n";
myfile << n; //score
myfile << "\n";
}
myfile.close();
textprintf_ex(screen, font, 10, 50, makecol(255, 255, 255),-1, "New Hi-score table created");
rest(1000);
clear_bitmap(screen);
}
int load_hiscores(void)
{
string dummy;
int dummy1;
// Load Hi-score table
//
ifstream myfile ("hiscores.txt");
for (int n=0; n<10;n++)
{
getline (myfile,dummy);
hi_scores[n].name=dummy;
textprintf_ex(screen, font, 60, 30+(n*10), makecol(255, 255, 255),-1, "%s", hi_scores[n].name.c_str());
getline (myfile,dummy);
hi_scores[n].score=dummy1;
textprintf_ex(screen, font, 200, 30+(n*10), makecol(255, 255, 255),-1, "%i", hi_scores[n].score);
}
myfile.close();
textprintf_ex(screen, font, 10, 300, makecol(255, 255, 255),-1, "Hi-Score table loaded");
rest(2000);
clear_bitmap(screen);
}
You do realize you never actually set dummy1 to anything, right?
You do realize you never actually set dummy1 to anything, right?
Since he's asking us why he's outputting garbage he probably doesn't. It's an honest mistake with identifiers dummy and dummy1.
getline (myfile,dummy);
hi_scores[n].score=dummy1;
In other words, you mistakenly loaded the score into the string object instead of the integer.
I haven't done C/C++, file I/O, nor Allegro programming in a while so I couldn't say if that's the only problem...
Also, use [code]mycodehere[/code] tags and use descriptive variable identifiers. dummy and dummy1 are worse than a and b.
For other BBCode syntax on Allegro.cc, check out the Help section (the Help button on the Post Reply toolbar).
I use this code for my games that need a high score table, it can load and save and sort names, its doesn't deal with getting names from user, and showing the high-score table, it just manages the table itself. Even if the code isn't much use, it will stick you on the right track.
http://www.timorg.net/high_score.zip
If you need an example of use, I will whack something together.
-Tim
I wrote a small "game template" for allegro games some time ago. It also contains high score routines. You might want to take a look at it to get some ideas.
Please note that the main() routine is basically a showcase of the functions.
Many thanks for the code.
Thats a clever trick of using enums for named constants.
Since he's asking us why he's outputting garbage he probably doesn't.
It's a rhetorical device, you dimwit.
Thats a clever trick of using enums for named constants.
It's pretty standard for C++. It allows you to put constants in a namespace.
> Thats a clever trick of using enums for named constants.
It's pretty standard for C++. It allows you to put constants in a namespace.
It's also pretty standard for C
It was / is pretty standard for C before even C++ exists
Hmm, interesting. Why doesn't the grabber emit that sort of header then?
Heh, because grabber is a secret build from allegro big 5 ;-)
Sometimes using the preprocessor can be the better option. Esp. if you use some of the more powerful features of the pp.
Another point is that using the PP is IMO the better solution for the grabber headers. You're not working with actual constants. You are actually accessing an index. You just prefer to give that index a speaking name. So the mapping is value -> name.
In the case above the mapping is vice versa. I have name and map it to a value.
enum { HI_COLOR = -3, TRUE_COLOR, INDEXED_COLOR };
I'm not sure I understand the point of using enums instead of the preprocessor. It would help if I understood namespaces... And if you're not defining a namespace, spellcaster, wouldn't it be better to use the preprocessor?
It's a rhetorical device, you dimwit.
X_G.PostCount+=2;
And if you're not defining a namespace, spellcaster, wouldn't it be better to use the preprocessor?
It's never better to use the preprocessor.
enum { NamedConstant = 2 }; void foo() { int NamedConstant = 3; NamedConstant = 4; }
Obviously, this is an obvious example, since no one would create a variable named NamedConstant. However, this is totally valid code that compiles. But, had you used the preprocessor, you get this error message:
test.cpp: In function 'void foo()': test.cpp:4: error: expected unqualified-id before numeric constant test.cpp:5: error: invalid lvalue in assignment
Quite cryptic.
For a more likely example, try this on for size:
This sort of thing happens all the time.
Name collision is just a fact of programming though. I don't think that's a valid flaw in #define'ing constants. I was told that by #define'ing your global constants you save memory (even though it wouldn't be much).
Besides, considering how quickly the problem was detected in those threads returned by the search I would say that it's relatively easy to track down. You also probably don't want a local variable named the same as your constant to avoid logical errors (perhaps breaking somebody else's code) so I would still lean towards the preprocessor when possible.
It's also easy to come up with a naming convention to separate preprocessor definitions from other entities.
/* * For example, and this is not to be taken as real code... */ #define NAMED_CONSTANT 4 class NamedConstant { private: int mintNamedConstant; };
Anybody else have an opinion?
Name collision is just a fact of programming though.
Sure, if you code like that. Using constants inside specific scopes completely eliminates the collision. You can select either constant:
#include <iostream> using namespace std; enum { Bitmap = 3 }; int main(int argc, char* argv[]) { int Bitmap; Bitmap = ::Bitmap; cout << "Bitmap constant is " << ::Bitmap << endl; cout << "Bitmap variable is " << Bitmap << endl; return 0; }
I was told that by #define'ing your global constants you save memory (even though it wouldn't be much).
Well, that's wrong, as the compiler will inline the constants anyways.
[append]
In addition, even if creating an enumeration caused any extra space to be allocated in the executable (which it doesn't), it would have to be enough data to cause the program to spill over into the next allocation chunk, otherwise it's insignificant. Allocation chunks are typically (or always, on a Pentium, IIRC) 4kb.
[/append]
The problem is that you're using the preprocessor to do things the compiler should be doing. It's like running a sed script on your code before you compile it. The sed script doesn't know whether or not you mean the variable or the constant, it just does string replacement. The compiler can accomplish the same task, but more intelligently.
Libraries that use the preprocessor have to prefix all of their symbols to avoid collision. Instead of doing that, use namespaces. Compare:
// GfxLib.h #define MODE_SOLID 0x01
That uses the preprocessor to represent a flag passed to a function that draws shapes in a graphics library.
// ColDetek.h #define MODE_SOLID 0x03
That uses the preprocessor to represent a flag passed to a function in a physics library. Now one can't use both libraries in the same file. To fix the problem, both libraries need to be made compliant.
// GfxLib.h #define GFXLIB_MODE_SOLID 0x01
// ColDetek.h #define COLDETEK_MODE_SOLID 0x03
Now to use them we have to use GFXLIB_MODE_SOLID or COLDETEK_MODE_SOLID. How annoying. Instead, use enumerations and namespaces:
// GfxLib.h namespace GfxLib { enum { MODE_SOLID = 1 }; }
// ColDetek.h namespace ColDetek { enum { MODE_SOLID = 3 }; }
Now, when you want to use ColDetek's constants, use ColDetek::MODE_SOLID. How does that help? using statements!
void foo() { using namespace ColDetek; ColDetekFunction(data, MODE_SOLID); // Lots of other calls to ColDetek's functions // But we can still use GfxLib in this function GfxLib::DrawPoly(points, GfxLib::MODE_SOLID); }
Namespace collisions are not a product of programming, they are a product of poor programming.
Thanks. That's all very interesting.
Well, that's wrong, as the compiler will inline the constants anyways.
What do you mean by inline the constants? And if there's no difference in memory usage between using the preprocessor instruction (#define) versus an enum or const definition then why do large commercial games #define constants?
// But we can still use GfxLib in this function
However, wouldn't using the prefix make it more clear which namespace each constant belongs to?
void foo() { ColDetekFunction(data, ColDetek::MODE_SOLID); // Lots of other calls to ColDetek's functions GfxLib::DrawPoly(points, GfxLib::MODE_SOLID); }
I'm curious how the std namespace is defined if it contains entities from different header files... Or am I misunderstanding the structure of the std namespace? Does anybody know where it's defined?
Namespaces don't have to be declared all at once. This code is valid:
namespace foo { enum { constant }; } namespace foo { void func(); }
Also, is there a way to switch between namespaces in the same scope (for example, use one, stop using it, use another one)?
No, because you can't "stop" using a namespace.
However, wouldn't using the prefix make it more clear which namespace each constant belongs to?
Well, yeah, but it can also make it more convoluted. It gets to a point where you know you are passing ColDetek::MODE_SOLID to ColDetek::ColDetekFunction.
[edit]
Changed example to be clearer.
Namespaces don't have to be declared all at once.
No, because you can't "stop" using a namespace.
Good to know. Thanks!
I deleted the question in his quote convinced that it was a stupid qustion... Apparently it wasn't... :-/
Well, yeah, but it can also make it more convoluted. It gets to a point where you know you are passing ColDetek::MODE_SOLID to ColDetek::ColDetekFunction.
True...
I'm not sure I understand the point of using enums instead of the preprocessor. It would help if I understood namespaces... And if you're not defining a namespace, spellcaster, wouldn't it be better to use the preprocessor?
Define "better". Main reason I use enums is that the enum is known to the compiler, so it'll appear in compile errors, during debug sessions, etc.
Besides that, it's mainly a question of style and lazyness. If I have a couple of constants with increasing numbers, using an enum is simply less typing.
And adding a new constant in the middle is way less work.
I also think that the enum version is slightly more readable.
You can also do something like this:
enum { MODE_1 = 0 MODE_2, MODE_3, MODE_GUARD }; int countModes = MODE_GUARD - MODE_1; // or for (int a=MODE_1; a < MODE_GUARD; ++a) { }
That's nothing fancy. It's just practical and provides a bit of comfort. Oh, have I mentioned that it saves a couple of keystrokes as well? This will not make a big difference, but if you start using it, and you need to insert that extra constant in the middle, you'll just smile, do it and smile even broader.
Guess that's why I'm using it. I like that warm feeling
What do you mean by inline the constants?
const int NamedConstant = 3; enum { NamedConstant = 3 };
Both of those create constant values. When you compile the program, the compiler doesn't actually add that value to the code as a variable. Instead, wherever you use the variable, the compiler places the literal value there directly.
And if there's no difference in memory usage between using the preprocessor instruction (#define) versus an enum or const definition then why do large commercial games #define constants?
In C there isn't much advantage to using the enums since you can't select the scoping you want anyways (in other words the function scope will always override the named constant and you can't change that behavior), and #defines are easier to type, I suppose (there might be an argument for "easier to read" also). The tradition probably carried over into C++, before people popularly realized the concrete benefits of enumerations.
In C++, this is also quite nice:
enum WHATEVER { ENUM1, ENUM2, ENUM3 } void doSomething(WHATEVER w) { ... }
typedef enum WHATEVER { ENUM1, ENUM2, ENUM3 } WHATEVER; void doSomething(WHATEVER w) { ... }
Works in C, too.
Another thing I like about enums:
1 | enum eFoo { |
2 | VAL1, |
3 | VAL2, |
4 | VAL3 |
5 | }; |
6 | |
7 | void someFunc(eFoo foo) |
8 | { |
9 | switch(foo) |
10 | { |
11 | case VAL1: |
12 | ... |
13 | break; |
14 | case VAL2: |
15 | ... |
16 | break; |
17 | } |
18 | } |
will generate a warning in GCC that 'VAL3' isn't handled in the switch statement.
KittyCat: that's pretty interesting !