Programming Forums

Programming Forums (http://www.programmingforums.org/forumindex.php)
-   C++ (http://www.programmingforums.org/forum15.html)
-   -   Viscious Game Bug (http://www.programmingforums.org/showthread.php?t=13902)

dr.p Sep 3rd, 2007 4:21 AM

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


dr.p Sep 3rd, 2007 4:50 AM

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

I'm using MS Visual C++ 2005 Express for this. Is it normal for most compilers to default a comparison between a float variable and a float value to an integer comparison?

DaWei Sep 3rd, 2007 8:14 AM

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.

dr.p Sep 3rd, 2007 2:58 PM

Quote:

Originally Posted by DaWei (Post 133225)
How did you define MWEIGHT_FAILURE and MWEIGHT_SUCCESS? You don't show that.

Like so:
:

#define MWEIGHT_FAILURE 0.01
#define MWEIGHT_SUCCESS 1.00



Quote:

Originally Posted by DaWei (Post 133225)
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.

:( 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.

andro Sep 3rd, 2007 3:00 PM

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 :/

DaWei Sep 3rd, 2007 3:32 PM

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.

dr.p Sep 3rd, 2007 8:52 PM

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.


All times are GMT -5. The time now is 8:13 PM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC