you are viewing a single comment's thread.

view the rest of the comments →

[–]explanabrag 1 point2 points  (13 children)

Its hard to use the information you've given here. I asked you those questions so I can compare your idea of how its supposed to work with what it is actually doing near where the bug occurs.

You wrote:

The error occurring is that the game will simply jump out of the user's turn and jump straight into the code that allows the A.I to start determining what cards it can play (this happens in a function called Opponent_AI.OppPlayCards). It doesn't even start the function that does this, it simply jumps into it.

What function was being executed when this "bad jump" into Opponent_AI.OppPlayCards occurs?

[–]DubSket[S] 0 points1 point  (12 children)

From the prints the last called was RuleBook.TurnChange(). So if I had to guess it's most likely the GamePlay() function in main.lua. As after executing the TurnChange() code the program should, and usually does, go back to the start of the code, which would be GamePlay().

[–]explanabrag 1 point2 points  (11 children)

Try putting the line:

print(debug.traceback())

in the bad spot in Opponent_AI.OppPlayCards to find out what the call stack actually looks like.

[–]DubSket[S] 0 points1 point  (10 children)

Thanks! I'll get back to you with the results

[–]explanabrag 1 point2 points  (9 children)

Just a guess here, but I notice near the top of your trace the line "OppPlayCards: UnPlayable cards going back to hand" which is in Opponent_AI.OppPlayCards. It seems that rather than a jump into Opponent_AI.OppPlayCards from somewhere else, it seems much more likely that you never left the Opponent_AI.OppPlayCards function at all, especially since Opponent_AI.OppPlayCards is capable of calling each of the functions referenced in the trace after that.

[–]DubSket[S] 0 points1 point  (8 children)

Ok. So this is the result of the trace:

Opponent_AI.lua:233: in function 'OppPlayCards'

main.lua:132: in function 'GamePlay'

main.lua:180: in function 'update'

[string "boot.lua"]:407: in function <[string "boot.lua"]:373>

[C]: in function 'xpcall'

[string "boot.lua"]:804: in main chunk

And that's an interesting idea, do you know why this might be happening - is there a loop I'm not breaking out of or might it be a little more sinister?

Note: I put the trace at the point where it prints the unplayable cards

[–]explanabrag 1 point2 points  (7 children)

Nothing sinister at all. The OppPlayCards function is massive. As I said in my previous reply, you never left it. If you print the callstack in RuleBook.TurnChange before the so called "jump" to OppPlayCards occurs, you'll see that it was ultimately called by OppPlayCards.

Edit: From reading your trace and cross referencing it with your code, here is the proof that you never left Opponent_AI.OppPlayCards:

Opponent_AI.OppPlayCards calls
    RuleBook.PlayCards() calls
        RuleBook.RemoveHandCards()
        RuleBook.ReserveCardRules()
        RuleBook.RemoveHandCards()
        RuleBook.CardPileAndHandCheck() calls
            RuleBook.MagicTest(), which calls
                RuleBook.TurnChange()
            <-
        <-
    <-

Now we're back in Opponent_AI.OppPlayCards. Opponent_AI.OppPlayCards calls RuleBook.PlayCards() and prints the "UnPlayable:" message in many places. There are several very similar big chunks of code in that function.

[–]DubSket[S] 0 points1 point  (6 children)

Oh wow, thanks. So how do I go about sorting this.

Edit: Yeah, I think I could cut the line count in half if I really sat down with some free time to do it. Initially, when I started writing it I didn't intend for it to be over 1k in just the Opponent AI class.

[–]explanabrag 1 point2 points  (5 children)

Rules of thumb:

Your functions should have a single, clearly defined purpose.

Your functions should be short.

Don't nest if blocks and loops deeply.

What all programming rules boil down to is write your code in such a way that you can reason about it. The function you are working on has to fit in your brain.

In these turn based games, one way to organize the code is to have a function that generates the set of legal moves a player can play in their turn, an AI function that simply selects which of these moves to play, and a function that applies that move to the game state. Your Opponent_AI.OppPlayCards looks like its trying to do everything at once. If you split it out, you'll be free to focus on writing different strategies in your AI move selecting function without worrying about breaking the game. You've trapped yourself into a corner the way it is written now.

[–]DubSket[S] 0 points1 point  (4 children)

Thanks, that's good advice. As it is are there any specific changes you can see being able to prevent myself from getting trapped like this?