Today I managed to fit in some design, some coding, AND some bug fixing (by way of a bit of a redesign). This was not nearly as frustrating as the bug the other day and although in the end not a lot of visible progress was made, things are a lot more streamlined and ready to go now. Functionality-wise, we can now properly check to see if a given player should have a turn and immediately skip them if they have no moves available.
The idea is that everywhere that we would set the state directly to PLAYER_TURN or COMPUTER_TURN, we instead switch to CHECK_VALID_PLAY_PLAYER or CHECK_VALID_PLAY_COMPUTER. The handling for these states then just has to check and see if the appropriate player has a turn to make. If they do, it can switch directly to their TURN state; if they don’t, we check the opposite player to see if they have a turn and switch to their TURN state if they can make a play. In case no player can make a play, this switches to the state that indicates that the final ball drop should be happening.
I had already implemented the functionality for checking for a valid play previously in anticipation of this, but it didn’t quite work out as planned. The method itself was sound; it would check in the data structure that holds the still-playable balls for each player (an array for each) to see if they had a move, so that you could check to see if a move was available even if those balls were not currently visible.
The failing in this logic is that the way I implemented the mechanism to swap the visible balls. It would first save the existing balls from the maze back into the source array they came from and then replace the maze contents with the balls from the opposite array. This causes a problem if you don’t swap the visible balls immediately after a turn is over, before trying to swap to the other player.
For example, if the computer takes a turn, it tries to swap to us but we have no play, it then checks to see if the computer has another play to make and always thinks that it does because until the ball swap happens, the ball they just played is still in the array.
This could be fixed by always swapping the array after a turn is over, but it seemed like a better way would be that the method that pushes a ball out of the top row could just check to see if that ball exists in either of the two arrays and if so, remove it. This keeps those values always in sync. Then the code for swapping just becomes a restore of a ball array to the maze contents and hiding the other balls, which is a lot simpler for everything.
I haven’t altered the existing code to trigger the last ball drop when no player has a turn yet, since I ran out of development time for the night. I spent the remaining time modifying the state engine so that it tracks how many engine ticks it has been in the current state. This allows us to stay in a state for only a set number of ticks before switching away without having to do our own timing (for example, to display a “no move; skipping turn”) image, plus it also allows for other simple timing like slowing down the player while he’s walking to make his move.
Things are coming together pretty fast now. I need to rework some of the initial test code so that things like removing the gray bricks or removing all of the balls are states instead of being tracked by booleans. This will make everything more modular and clear to read plus also remove some crufty code and boolean tracking values.