Prevent the else section execution when the if condition is executed

The below if condition triggers somehow the execution of the else section. I’d highly appreciate any input that could help me understand why this happens.

In my turnmanager.AskForCard, verify if the current player’s guess is correct, i.e. the if segment is for the case of a correct guess, i.e. the selectedPlayer has the SelectedCard. The else condition, considers a wrong guess. In general, the intention is to allow another guess to the currentPlayer if the guess is correct and end the turn otherwise.

The guess is executed by Turn UI objects that allow the currentPlayer to select a given card from a given player and ask for it via a click on the guess button which calls turnmanager.AskForCard.

In a case of wrong guess it works as expected. However, a correct guess triggers somehow another execution, “probably” that of the else/false segment. “probably” as the probability of a wrong guess is much higher than that of correct one. Accordingly, while it seems that the second ‘guess’ executes the else section, I cannot confirm if that is inherently so, or a probable cause of an arbitrary guess.

This ‘secondary’ guess isn’t a reflection of the currentPlayer’s action via the Turn UI objects, but rather an arbitrary call, executed in case of correct guess.

Here are the relevant snippets, in case you can consider them:

TurnManager:

private void HandlePlayerTurn(Player currentPlayer)
    {
        if (selectedCard == null && selectedPlayer == null)
        {
            EnableUIMakeGuess();
        }
        else
        {
            AskForCard(selectedCard, selectedPlayer);
        }
    }

    private void EnableUIMakeGuess()
    {
        Debug.Log("MakeGuess method is called");
    }

    private void AskForCard(Card selectedCard, Player selectedPlayer)
    {
        if (selectedPlayer != null && selectedCard != null)
        {
            if (selectedPlayer.HandCards.Contains(selectedCard))
            {
                Debug.Log("AskForCar guess is correct");
                TransferCard(selectedCard, currentPlayer);
                CheckForQuartets();

                // If the guess is correct and the player's hand isn't empty, allow another guess.
                if (!IsPlayerHandEmpty(currentPlayer))
                {
                    // Allow the player to make another guess without drawing a card or ending the turn.
                    HandlePlayerTurn(currentPlayer);
                }
                else if (deckCards.Count > 0)
                {
                    // If the player's hand is empty but the deck isn't, draw a card from the deck.
                    DrawCardFromDeck();
                    // After drawing a card, re-evaluate the hand.
                    if (!IsPlayerHandEmpty(currentPlayer))
                    {
                        // Allow the player to make another guess.
                        HandlePlayerTurn(currentPlayer);
                    }
                }
                // No need to check for the deck being empty here, as we've already handled that case.
            }
            else
            {
                // If the guess is wrong, draw a card from the deck and end the turn.
                DisplayMessage($"{selectedPlayer.playerName} does not have {selectedCard.cardName}.");
                DrawCardFromDeck();
                EndTurn(); // This is the correct place to call EndTurn for an incorrect guess.
            }
        }
    }

PlayerController:

public void OnEventGuessClickRenamed()
    {
        guessButton.interactable = false;

        int selectedPlayerIndex = playersDropdown.value;
        int selectedCardIndex = cardsDropdown.value;

        int selectedPlayerID = playerIDs[selectedPlayerIndex];
        int selectedCardID = cardIDs[selectedCardIndex];

        // Find the corresponding Card and Player objects based on IDs
        Card selectedCard = CardsPlayerCanAsk.Find(card => card.ID == selectedCardID);
        Player selectedPlayer = PlayerToAsk.Find(player => player.ID == selectedPlayerID);

        TurnManager turnManager = GameObject.Find("Managers").GetComponent<TurnManager>();
        if (turnManager != null)
        {
            turnManager.OnEventGuessClickRenamed(selectedCard, selectedPlayer);
        }
        else
        {
            Debug.LogError("TurnManager not found.");
        }

        // Re-enable the button after the method is called
        guessButton.interactable = true;

    }

You just have a bug somewhere.

Whenever you doubt the function of an if() statement, refactor your code to have a temporary variable, assign the former contents of the if statement to it, and use the variable, such that you can print it.

Turn all snippets of this form:

if (blah1 && blah2 && blah3)
{
  //...
}

into this:

bool temp = blah1 && blah2 && blah3;
Debug.Log( "temp = " + temp);
if (temp)
{
  //...
}

That has NEVER failed. In every single case it will reveal your incorrect value.

Time to start debugging! Here is how you can begin your exciting new debugging adventures:

You must find a way to get the information you need in order to reason about what the problem is.

Once you understand what the problem is, you may begin to reason about a solution to the problem.

What is often happening in these cases is one of the following:

  • the code you think is executing is not actually executing at all
  • the code is executing far EARLIER or LATER than you think
  • the code is executing far LESS OFTEN than you think
  • the code is executing far MORE OFTEN than you think
  • the code is executing on another GameObject than you think it is
  • you’re getting an error or warning and you haven’t noticed it in the console window

To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

Doing this should help you answer these types of questions:

  • is this code even running? which parts are running? how often does it run? what order does it run in?
  • what are the names of the GameObjects or Components involved?
  • what are the values of the variables involved? Are they initialized? Are the values reasonable?
  • are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

Knowing this information will help you reason about the behavior you are seeing.

You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as Debug.Log("Problem!",this);

If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

You could also just display various important quantities in UI Text elements to watch them change as you play the game.

Visit Google for how to see console output from builds. If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer for iOS: https://discussions.unity.com/t/700551 or this answer for Android: https://discussions.unity.com/t/699654

If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

If your problem is with OnCollision-type functions, print the name of what is passed in!

Here’s an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

https://discussions.unity.com/t/839300/3

“When in doubt, print it out!™” - Kurt Dekker (and many others)

Note: the print() function is an alias for Debug.Log() provided by the MonoBehaviour class.

Thanks @Kurt-Dekker . I struggle to observe however, how it can address my needs. I applied bool as you suggested which provided me with the exact values, as I expected already via other logs… but this is exactly what I struggle with, my if/else statement seems to be correct, while probably it isn’t. I just don’t know where to look at, i.e. why does this happen, what is the problem I need to solve?

If the condition you are checking is not correct, the answer is you need to check a different condition.

It may be helpful to draw out a simple flowchart or logic diagram to help you think about the problem, even a few circles and lines on paper:

“decide if correct” → yes, no
“decide if card is matching” → yes, no

and what you expect the code to do.

If your Debug.Log statements are showing the values for only your if condition, then there is no way that it can run the else statements. That is just fundamentally impossible.

It looks to me like your logic is just wrong with how you are handling the player turn.
1 - You use the guess button method which sets the selectedCard and selectedPlayer variables.
2 - The guess button method calls the HandlePlayerTurn method.
3 - The HandlePlayerTurn method checks if the selectedCard and selectedPlayer are null and calls MakeGuess (this appears to not be any problem). If the selectedCard and selectedPlayer are not null (which they should not be as they are set from the guess button method) then the AskForCard method is called passing in the selectedCard and selectedPlayer values.
The following parts are based on a correct guess:
5 - The selectedPlayer and selectedCard are not null, so it then checks if the player has that card.
6 - The player DOES have that card, so it is transferred out of their hand, and the check for quartets is done.
6a - If the player still has cards then the HandlePlayerTurn method is called again.
6b - If the deck still has cards, then draw one for the player and then check that the player has cards (this is a redundant check as they can only draw a card if the deck still has cards and they have just been made to draw a card). And then call the HandlePlayerTurn method again.
7 - the HandlePlayerTurn method checks if the selectedCard and selectedPlayer are null (which they still are not) so the AskForCard method is run again (go back to 3 above).

Your issues appear to be at 6a and 6b where you call the HandlePlayerTurn method again. Because it is still in the same frame/tick/turn and nothing has changed or nulled the selectedCard and selectedPlayer it will be checking for exactly the same card that it had just correctly guessed in the previous loop and as that card has already been removed from the players hand, then it will fail the if statement (item 6 in my breakdown above) and therefore will skip to the else and say that the player does not have that card in their hand and will draw a card and end the turn.

You should probably not be calling HandlePlayerTurn after a correct guess, because it is still going to be using the same card that they had previously guessed. Shouldn’t this be going off to a different method to allow the current player to guess a different card? After all, what is the point of guessing the same card if you have just taken it from the player - I’m assuming that there is only 1 of each type of card, although even with duplicates what is the likelihood that the selected player actually has multiple of the same card in their hand?

Thanks @BABIA_GameStudio & @Kurt-Dekker for your highly appreciated time and input. It helped to dissolve my stagnation and even more than that to solve it. The issue was exactly as @BABIA_GameStudio : suggestedSelectedPlayer && SelectedCard passed again in HandlePlayerTurn. I reset these values and it solved the issue. It functions, which is always happier. It highlighted some other issues with my game logic, which I had to solve, to verify it actually works. Thus, the belated reply.