Al Simulation
How the AISim3.py Code Works
A lot of these functions are very similar to one another, and some of them use the new isOnSide() function. Here's a review of the new algorithms we've made:
Function | Description |
---|---|
getRandomMove() | Randomly choose a valid move to make. |
getCornerSideBestMove () | Take a corner move if available. If there is no corner, take a space on the side. If no sides are available, use the regular getComputerMove() algorithm. |
getSideBestMove() | Take a side space if there is one available. If not, then use the regular getComputerMove() algorithm (side spaces are chosen before corner spaces). |
getWorstMove() | Take the space that will result in the fewest tiles being flipped. |
getCornerWorstMove() | Take a corner space, if available. If not, use the getWorstMove() algorithm. |
Comparing the Random Algorithm Against the Regular Algorithm
Now the only thing to do is replace one of the getComputerMove() calls in the main part of the program with one of the new functions. Then we can run several games and see how often one algorithm wins over the other. First, let's replace O's algorithm with the one in getComputerMove() with getRandomMove() on line 351:
351. x, y = getRandomMove(mainBoard, 'O')
When we run the program with a hundred games now, it may look something like this:
Welcome to Reversi! Enter number of games to run: 100 Game #0: X scored 25 points. O scored 38 points. Game #1: X scored 32 points. O scored 32 points. Game #2: X scored 15 points. O scored 0 points. Game #3: X scored 50 points. O scored 14 points. ...skipped for brevity... Game #96: X scored 31 points. O scored 33 points. Game #97: X scored 41 points. O scored 23 points. Game #98: X scored 33 points. O scored 31 points. Game #99: X scored 45 points. O scored 19 points. X wins 84 games (84.0%), O wins 15 games (15.0%), ties for 1 games (1.0%) of 100.0 games total.
Wow! X win far more often than O did. That means that the algorithm in getComputerMove() (take any available corners, otherwise take the space that flips the most tiles) wins more games than the algorithm in getRandomMove() (which just makes moves randomly). This makes sense, because making intelligent choices is usually going to be better than just choosing things at random.
Comparing the Random Algorithm Against Itself
What if we changed O's algorithm to also use the algorithm in getRandomMove()? Let's find out by changing O's function call on line 351 from getComputerMove() to getRandomMove() and running the program again.
Welcome to Reversi! Enter number of games to run: 100 Game #0: X scored 37 points. O scored 24 points. Game #1: X scored 19 points. O scored 45 points. ...skipped for brevity... Game #98: X scored 27 points. O scored 37 points. Game #99: X scored 38 points. O scored 22 points. X wins 42 games (42.0%), O wins 54 games (54.0%), ties for 4 games (4.0%) of 100.0 games total.
As you can see, when both players are making random moves, they each win about 50% of the time. (In the above case, O just happen to get lucky and won a little bit more than half of the time.)
Just like moving on the corner spaces is a good idea because they cannot be flipped, moving on the side pieces may also be a good idea. On the side, the tile has the edge of the board and is not as out in the open as the other pieces. The corners are still preferable to the side spaces, but moving on the sides (even when there is a move that can flip more pieces) may be a good strategy.
Comparing the Regular Algorithm Against the CornersSideBest Algorithm
Change X's algorithm on line 346 to use getComputerMove() (our original algorithm) and O's algorithm on line 351 to use getCornerSideBestMove(), and let's run a hundred games to see which is better. Try changing the function calls and running the program again.
Welcome to Reversi! Enter number of games to run: 100 Game #0: X scored 52 points. O scored 12 points. Game #1: X scored 10 points. O scored 54 points. ...skipped for brevity... Game #98: X scored 41 points. O scored 23 points. Game #99: X scored 46 points. O scored 13 points. X wins 65 games (65.0%), O wins 31 games (31.0%), ties for 4 games (4.0%) of 100.0 games total.
Wow! That's unexpected. It seems that choosing the side spaces over a space that flips more tiles is a bad strategy to use. The benefit of the side space is not greater than the cost of choosing a space that flips fewer of the opponent's tiles. Can we be sure of these results? Let's run the program again, but this time let's have the program play one thousand games. This may take a few minutes for your computer to run (but it would take days for you to do this by hand!) Try changing the function calls and running the program again.
Welcome to Reversi! Enter number of games to run: 1000 Game #0: X scored 20 points. O scored 44 points. Game #1: X scored 54 points. O scored 9 points. ...skipped for brevity... Game #998: X scored 38 points. O scored 23 points. Game #999: X scored 38 points. O scored 26 points. X wins 611 games (61.1%), O wins 363 games (36.3%), ties for 26 games (2.6%) of 1000.0 games total.
The more accurate statistics from the thousand-games run are about the same as the statistics from the hundred-games run. It seems that choosing the move that flips the most tiles is a better idea than choosing a side move.
Comparing the Regular Algorithm Against the Worst Algorithm
Now set the X player's algorithm on line 346 to use getComputerMove() and the O player's algorithm on line 351 to getWorstMove(), and run a hundred games. Try changing the function calls and running the program again.
Welcome to Reversi! Enter number of games to run: 100 Game #0: X scored 50 points. O scored 14 points. Game #1: X scored 38 points. O scored 8 points. ...skipped for brevity... Game #98: X scored 36 points. O scored 16 points. Game #99: X scored 19 points. O scored 0 points. X wins 98 games (98.0%), O wins 2 games (2.0%), ties for 0 games (0.0%) of 100.0 games total.
Whoa! The algorithm in getWorstMove(), which always choose the move that flips the fewest tiles, will almost always lose to our regular algorithm. This isn't really surprising at all.
Comparing the Regular Algorithm Against the WorstCorner Algorithm
How about when we replace getWorstMove() on line 351 with getCornerWorstMove(), which is the same algorithm except it takes any available corner pieces. Try changing the function calls and running the program again.
Welcome to Reversi! Enter number of games to run: 100 Game #0: X scored 36 points. O scored 7 points. Game #1: X scored 44 points. O scored 19 points. ...skipped for brevity... Game #98: X scored 47 points. O scored 17 points. Game #99: X scored 36 points. O scored 18 points. X wins 94 games (94.0%), O wins 6 games (6.0%), ties for 0 games (0.0%) of 100.0 games total.
The getCornerWorstMove() still loses most of the games, but it seems to win a few more games than getWorstMove() (6% compared to 2%). Does taking the corner spaces when they are available really make a difference?
Comparing the Worst Algorithm Against the WorstCorner Algorithm
We can check by setting X's algorithm to getWorstMove() and O's algorithm to getCornerWorstMove(), and then running the program. Try changing the function calls and running the program again.
Welcome to Reversi! Enter number of games to run: 100 Game #0: X scored 25 points. O scored 39 points. Game #1: X scored 26 points. O scored 33 points. ...skipped for brevity... Game #98: X scored 36 points. O scored 25 points. Game #99: X scored 29 points. O scored 35 points. X wins 32 games (32.0%), O wins 67 games (67.0%), ties for 1 games (1.0%) of 100.0 games total.
Yes, it does seem like taking the algorithm that takes the corners when it can does translate into more wins. While we have found out that going for the sides makes you lose more often, going for the corners is always a good idea.
Learning New Things by Running Simulation Experiments
This chapter didn't really cover a game, but it modeled various strategies for Reversi. If we thought that taking side moves in Reversi was a good idea, we would have to spend days, even weeks, carefully playing games of Reversi by hand and writing down the results. But if we know how to program a computer to play Reversi, then we can have the computer play Reversi using these strategies for us. If you think about it, you will realize that the computer is executing millions of lines of our Python program in seconds! Your experiments with the simulation of Reversi can help you learn more about playing Reversi in real life.
In fact, this chapter would make a good science fair project. Your problem can be which set of moves leads to the most wins against other sets of moves, and make a hypothesis about which is the best strategy. After running several simulations, you can determine which strategy works best. You can make a science fair project out of a simulation of any board game! And it is all because you know exactly how to instruct the computer to do it, step by step, line by line. You can speak the computer's language, and get it to do large amounts of data processing and number crunching for you.
That's all for the text-based games in this book. Games that only use text can be fun, even though there simple. But most modern games use graphics, sound, and animation to make much more exciting looking games. For the rest of the chapters in this book, we will learn how to create games with graphics by using a Python module called Pygame.