![]() |
|
![]() |
|
|
Thread Tools | Display Modes |
|
|
|
|
#1 |
|
Programmer
Join Date: Feb 2006
Location: Ohio
Posts: 93
Rep Power: 3
![]() |
Viscious Game Bug
Hello, folks. I need help.
The following is a function that determines the winner of a single battle in the game I'm creating, and then updates the field and stats appropriately. The "DetermineBattleOutcome" call is what actually determines the winner. My debug output shows that this ALWAYS returns the correct value. The "outcome" variable which stores this result is checked against the SUCCESS and FAILURE codes (values 1.00 and 0.01, respectively,) in an IF statement following the "Determine..." call. PROBLEM IS: When I lose a battle on purpose, and the value of outcome is CORRECTLY set to MWEIGHT_FAILURE (0.01), the afore-mentioned IF statement DOES NOT evaluate "outcome == MWEIGHT_FAILURE" to true............. It's late... and I hope I'm just missing something obvious, but this is truly perplexing. If the debug code is too confusing, please let me know and I'll remove it. void DoBattle (UINT attacker, UINT pos)
{
#ifdef GAME_PLAY_DEBUG_BATTLE
Debug_CleanUp();
char sztemp[256] = "\0";
sprintf(sztemp, "BATTLE: a=%d p=%d", attacker, pos);
Debug_CompyOut(sztemp);
Delay(BATTLE_DEBUG_DELAY);
#endif
if (attacker != COMPUTER && attacker != PLAYER) return;
if (pos >= FIELD_SIZE) return;
UINT defender = (attacker == COMPUTER) ? PLAYER: COMPUTER;
float outcome = DetermineBattleOutcome(g_Field[attacker][pos], g_Field[defender][pos]);
#ifdef GAME_PLAY_DEBUG_BATTLE
sprintf(sztemp, "BATTLE: outcome=%f", outcome);
Debug_CompyOut(sztemp);
Delay(BATTLE_DEBUG_DELAY);
#endif
if (outcome == MWEIGHT_INVALID)
return;
BYTE suit, value, state, color;
// if someone won the battle
if (outcome == MWEIGHT_FAILURE || outcome == MWEIGHT_SUCCESS) {
// set the winner and loser
UINT winner = (outcome == MWEIGHT_SUCCESS) ? attacker: defender;
UINT loser = (outcome == MWEIGHT_SUCCESS) ? defender: attacker;
#ifdef GAME_PLAY_DEBUG_BATTLE
sprintf(sztemp, "BATTLE: w=%d l=%d", winner, loser);
Debug_CompyOut(sztemp);
Delay(BATTLE_DEBUG_DELAY);
#endif
// get the value of the lost card
ParseCardValue(g_Field[loser][pos], NULL, &value, NULL, NULL);
// update the winer's states
g_Scores[winner]->nTotalCaptured++;
if (value > CARDROW_TENS) {
g_Scores[winner]->nFacesCaptured++;
}
// and remove the lost card from the field
g_Field[loser][pos] = 0;
} else {
#ifdef GAME_PLAY_DEBUG_BATTLE
sprintf(sztemp, "BATTLE: NO WINNER! %f %f", outcome, MWEIGHT_FAILURE);
Debug_CompyOut(sztemp);
Delay(BATTLE_DEBUG_DELAY);
#endif
}
}
// end DoBattle
__________________
Neeley.org |
|
|
|
|
|
#2 |
|
Programmer
Join Date: Feb 2006
Location: Ohio
Posts: 93
Rep Power: 3
![]() |
Fixed
Sorry for answering my own post :o I finally figured out that I had to (float) my variables:
// if someone won the battle
if ( (float)outcome == (float)MWEIGHT_FAILURE
|| (float)outcome == (float)MWEIGHT_SUCCESS
) {
// set the winner and loser
__________________
Neeley.org |
|
|
|
|
|
#3 |
|
Resident Grouch
![]() ![]() ![]() ![]() ![]() ![]() Join Date: Jun 2005
Posts: 6,453
Rep Power: 10
![]() |
How did you define MWEIGHT_FAILURE and MWEIGHT_SUCCESS? You don't show that.
It's also error prone to compare floats directly. Floats gain their range at the expense of precision. You should generally define an error value such that if the difference between two floats is within that range, they're considered equal.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code. Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers |
|
|
|
|
|
#4 | ||
|
Programmer
Join Date: Feb 2006
Location: Ohio
Posts: 93
Rep Power: 3
![]() |
Quote:
#define MWEIGHT_FAILURE 0.01 #define MWEIGHT_SUCCESS 1.00 Quote:
That's not a good thing for what I'm doing.I'm using floats as the return value from the DetermineBattleOutcome function because the result acts as the root weight in the AI for determining which move is the best. If FAILURE is returned for instance, the weight starts as low as possible (0.01, in this case), while still being a valid move. When the AI gets this value, it then adds the float value that represents the importance of the card to this root weight. E.g. a 3 card would be weighted 0.15 because of it's low importance, while a Queen would be 0.90, etc. The AI part is working great, since it adds the floats up and takes their average, then justs looks for the highest. The battle handling function that I posted does not need float values, but uses them for sake of convenience. Do you think it would be best for me to return integer values for this part, instead of the floats? The code is so uncluttered now, I don't really want to gunk it up by doing that. But if it's a high probability that I'm going to run into problems with it the way it is now, I'll be happy to change it.
__________________
Neeley.org |
||
|
|
|
|
|
#5 |
|
Professional Programmer
|
I had similar problem once, and all I did was create a new method that returned BOOL, and did a comparison on 2 floats to see if they are "equal". (if abs(f1-f2) < SOME_CONSANT)
Didn't clutter things up too much :/
__________________
http://www.kevinherron.com/ |
|
|
|
|
|
#6 |
|
Resident Grouch
![]() ![]() ![]() ![]() ![]() ![]() Join Date: Jun 2005
Posts: 6,453
Rep Power: 10
![]() |
Assuming you're on a typical 32-bit system, there are only 2^32 values available for all the floats in the approximate range 10^-38 to 10^38. As you can see, there would be a huge number of actual values missing.
The value that andro is using (SOME_CONSTANT) is often called Epsilon. I often define my own epsilon, according to what I think I need. Your system may define a constant, such as FLT_EPSILON, that is the smallest number which, when added to 1.0, will not result in 1.0. In the case of MS' C++, this value is 1.192092896e–07F. As an example, if you divide 1.0 by 100.0, you will get 0.01. You will get that same result if you divide 1.0 by 100.00001. Your mileage may vary slightly depending on your machine's floating point implementation, but you get my drift. Very small changes in your weights will introduce error.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code. Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers |
|
|
|
|
|
#7 |
|
Programmer
Join Date: Feb 2006
Location: Ohio
Posts: 93
Rep Power: 3
![]() |
Thank you, DaWei. That's a bit over my head
but I'll keep it in mind as I go. Hopefully the way that it is coded now will not present any major problems, as the game will be relatively simple.And thank you for the suggestion Andro. I'll keep that in mind, also.
__________________
Neeley.org |
|
|
|
![]() |
| Bookmarks |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
| Display Modes | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| An aspiring game programmer needs your advice | Emperor | Community Introductions | 5 | Feb 10th, 2007 5:36 PM |
| Trying to setup an anti-cheat system for a game friend and I are creating | Dr.Backtick` | C++ | 14 | Feb 15th, 2006 11:12 PM |
| Java programmers, game developers, artists, be ware! RPG game team is recruiting! | atcomputers.us | Paid Job Offers | 7 | Sep 25th, 2005 7:25 PM |
| Programmers Needed! Online Game | troy_eisert | C++ | 2 | Jan 29th, 2005 12:51 PM |