Week 3 – Fixing Bugs
March 24, 2023
Welcome to my third Senior Project, where I will go over my progress fixing the bugs I found last week. I hope to have the game completely finished by the end of next week, so I can move on to having people test the game in order to answer my main research question: how changing the difficulty level with AI can make the game more or less enjoyable.
The Game Should End When A Player Has No Legal Moves Available.
I said in last week’s blog that this bug was the “only one I could completely fix.” And at the time I was correct; the game works fine when two people play against each other. But I already have a simple AI model written, and when I turn it on, the entire program breaks.
To understand why, I’ll go back to how I fixed this in the first place. I have a class, play.py, in which most of the gameplay occurs. This class has a Board attribute, found in the board.py class. My initial method to check for a winner was in board.py, as the board class contained information about the number of pieces remaining. Since redRemaining and blackRemaining were both stored locally in board.py, I decided that this would be the best place to put the method.
My Solution
As I mentioned earlier, play.py is the method that handles actual gameplay, including which player’s turn it is. However, board.py has no way to access this, so I needed to move the method to play.py. I then went ahead and checked for a winner using the play.py method, rather than accessing the board to use its method. Since the AI algorithm uses the state of the board as well as the getWinner() method, I need to rewrite the algorithm in order to use play.py and access its Board attribute as well as play.py’s getWinner(), rather than directly using board.py and it’s getWinner(). Not a difficult change, but I do need to be careful to not accidentally make things worse.
King Pieces Should Be Able To Go Forward And Backward, Even On The Same Turn.
In checkers, a king piece is able to go forwards and backwards. Additionally, a piece that captures another is able to make a second jump to capture multiple pieces if possible. Combining these two rules, a king piece is able to go both forward and backwards on the same turn when making captures. In my game, the first part worked, with kings able to go both directions, but capturing in this way did not. In this example, black is moving up on the screen, and red is moving down. Since the black piece is a king, it should be able to move in both directions, and capture both of the red pieces in the middle row. However, the game doesn’t let the player make this double jump, as moving both directions in the same turn isn’t working. If it worked correctly, another blue circle should appear in the top right corner to mark that being another valid move.
My Solution
Trying to fix this involved reading over my code over and over and trying out any solution I could think of. My first thought was to add another direction check for king pieces. My code starts with the piece’s current location, and checks moves to the left and right, in the direction it is able to move. Since black moves upwards, it checks in that direction, and since red moves down, it checks down for red. Kings can move in both directions, so it checks both times. After that, if a piece was captured, it checks to the left and right of that new location in order to determine if a double jump can be made. Since the method uses a starting row, ending row, and a direction, however, kings would only get checked in the same direction. If I checked up and right, the next move would be up and left or up and right, but never down. I added another two lines to check king pieces in the opposite direction as well, left and right.
This didn’t fix the issue, though, as the only thing I was updating was the direction being looked at. After reading my code a lot more, I realized that the start and stop rows were never updated. For example, if the rows I needed to check were 4, 5, and 6, my code would start at 4, add the direction (1 for down and -1 for up), check row 5, add the direction, and then check row 6. By not changing my start and stop rows, I would end up checking row 4, adding the opposite direction (so -1 in this case), and getting to row 3. Since this is outside the range to check, the loop would end without ever doing anything. To fix this, I just changed the ending row to what it would be if the direction had been the opposite.
After this, I finally saw some change. While the problem wasn’t fully fixed, I knew it was at least somewhat working since I would get an infinite recursion error any time I clicked on a king piece that was able to capture. I eventually realized that this was because the same piece was being captured over and over, leading to an infinite-jump, rather than just a double-jump. Going back to the example at the start of the section, the black piece on the top-left corner would jump to the bottom-middle. It would then check in all four diagonals, which included the same piece it just captured, and jump back to the top left corner. This would get repeated infinitely, crashing the program. The simple fix to this was to just not check the opposite direction from where the piece just came from. If the previous move was going to the left, I would only check backwards and right. And if the previous move was going right, I would only check backwards and left. And as you can see, the king is now able to capture in both directions on the same turn.