5. Evaluate possible movesNow, we know the battlefield and have the evaluator in hand, we can realize the first sentence in the algorithm. In this section, we'll add a function evalmoves() to AI class, which generates and evaluates possible moves.
Let's open boora-0.4.wz with a text editor and save it as boora-0.5.wz.
Add data members mystone and movelist to AI class. (Listing 5-1) mystone is the color of the stone the AI player plays, movelist stores the generated moves.
mystone is initialized in initAI(). (Listing 5-2)
Add compvals() and evalmoves()to AI class. (Listing 5-3)
Function comvals() compares two moves by their evalues. We don't directly call this function, but use it to sort movelist by values of moves (see the last line in function evalmoves().)
Function evalmoves()loops over hotspots, calling putstone() to place a stone on an empty spot, calling evaluate() to calculate the value of the move, calling remove() to get the stone removed, adding index of the spot and its value to movelist. The function, in the end, sorts movelist by the values of moves in descending order, so the first one is the best move so far.
Modify makemove() in order to test evalmoves()and movelist. (Listing 5-4)
After calling evalmoves() to generate and evaluate possible moves, the function picks up the first entry, the best move so far, from movelist, if movelist is not empty; otherwise, it calls randmove() to make a random move. It logs the move to hotspots.
Play against the program. We notice that it has the trend to form winning patterns and it does have chance to win if we don't take it seriously. This means evalmoves() works. Let it pay against a previous version, say, boora-0.1.wz, it definitely wins, no matter whether it plays black or white stone. Pretty exciting, huh? Our program won't just goof around anymore!
Watch carefully, we find out that its first move is still random, if it plays black stone. The reason is that evalmoves() cannot generate any move, if hotspots is empty. We treat this special case by hard-coding a move. (Listing 5-5)
Test again, we see that it won't make random move anymore. Instead, it simply puts a stone on the center of the board, if it plays black stone. So, we don't need randmove() anymore. After goofing around for four programming episodes, randmove() can retire now, of course, with honor. Shall we throw a party to celebrate its retirement?
Before we go, let's do some clean up as usual. (Listing 5-6) randmove() is retired. Checking the returns of lastmove() is not necessary, because it is guaranteed to return a move if the board is not empty. The details of getting the best-so-far move are hidden in the new function greedymove().
Play against the program. For the the first time, we need to pay a bit more attention in order to win.