We used the video code provided by Professor Land and added our own code for game functionality. We split the program into 8 main functions, main, drawboard, makeMove, computerPlayer, isWinner, reDrawBoard, flipCount, and checkIfValid. The game starts by displaying the start screen and waiting for the player to choose their level: easy or hard. Then drawboard() draws the playing board and all the variables are initialized. The cursor is put in the upper left hand corner and the four starting pieces are drawn in the center squares. We drew the playing pieces beforehand and stored them as 8x8 bitmaps. That way, it was faster to draw them each time we needed to reset the board. The matrix board contains the value of the chip in that space. If it is empty it is -1, -2 means a white chip, +2 means a black chip, and 3 means it is a valid move.
The method for checking the buttons was a pretty crude one. We had two variables for each push button. The buttons were checked every 5 frames. If the button was pressed a variable, butB1old for example, was set at one. If in the next frame it was no longer pressed, butB1 was set at one and butB1old to zero. This told us that the button had been pressed but was no longer pressed. Then, if butB1 was one, we performed the specified function.
The game starts with the player's turn. Over several frames, checkIfValid is called. This function goes through every spot on the board and checks if it is a valid move for the player. From each square there are 8 possible directions of movement, which we called north, northeast, east, southeast, south, southwest, west, and northwest. For each direction, we check if it is a valid move. If the next piece in that direction is the other player’s, and the sequence ends with your own piece, then it is a valid move. We created a moves matrix which is 8x8 like the board. Stored in the matrix are 64 8-bit numbers, one for each board space. Each bit in the number represents one of the eight possible directions. So, for example, if east is a valid direction of movement, bit 5 is set high. Each of the eight directions is checked in checkIfValid each time it is called. Additionally, if there is at least one valid move for that square, the board matrix for that square is set to 3.
If checkIfValid returns a one, there is at least one valid move for the player. If not, play skips to the other player’s turn. Once the player selects a square to move to, using the C button, the makeMove function is called if that space is a valid move. The makeMove function works similarly to the checkIfValid function. It checks every bit of the moves matrix for each direction. If the bit is one, it changes all the chips of the other player’s to the value of their own. It does this until it reaches its own chip again.
After makeMove, the board has to be redrawn showing the new values of all the chips. Since this involved drawing 64 8x8 bitmaps on the board, we split up the reDrawBoard() function over 32 frames. Each time it is called, it draws two chips on the board. It checks the value of the board and draws the appropriate chip. Once the board has been redrawn, the function draws the cursor in the upper left hand corner of the board and it is the computer’s turn.
All of the computer’s functions are written in computerPlayer(). It is similar to the human’s turn, except it doesn’t involve moving the cursor or checking the push buttons. First checkIfValid is called and if the computer has no moves, it is the human’s turn. Then two different algorithms can be performed, based on whether it is set at an easy or hard difficulty level. The AI for the easy play is the greedy algorithm, while hard takes into account weights of the squares. For both levels, FlipCount() is called which, for each space on the board, returns the number of chips of the other player’s that will be flipped. It is essentially the same as makeMove, but instead of changing the board matrix, it only returns a value. Then, for the hard level, a weight is assigned to the square. The corners are the most desirable, so they have the highest weight of 100, followed by other side pieces with weights of 10. The so-called “X” squares, which are near the corner squares, have a negative weight of -5. The rest of the pieces have a weight of 1. Then the weight is added to the flip count, and if it is greater than the previous, the current move is stored. After checking all 64 spots, the move with the highest flip/weight combination is chosen by the computer. If the level is set to easy, it only takes into account the flip count.
After choosing a square, makeMove is called, followed by reDrawBoard. In order for the person to see where the computer moves to, we inserted a delay before the board is redrawn. An “X” is drawn in the square where the computer will move, and then after about a minute’s delay, the board is redrawn. Then it becomes the human’s turn once again.
After each turn, isWinner is called, which checks if the game is over. The game is over if the board is full, one of the players doesn’t have any chips left, or neither player has a valid move. If this is the case, the player with the most number of chips wins the game. A winning message is displayed to the screen and it asks the player to press “B” if they wish to play again. If so, the starting screen is redrawn and all the variables are reset.