ICS 180A, Spring 1997:
Strategy and board game programming
Shannon's original paper on computer chess listed two possible strategies.
Even worse, it falls prey to what's known as the horizon effect. Suppose, in chess, we have a program searching seven levels deep, and that it has trapped its knight in the corner of the board (say in exchange for a rook) in a way that, if it played well, would end up with the knight captured within the next seven moves. But, by sacrificing a pawn elsewhere on the board, maybe the program could delay that capture by another move. That delay would then push the capture past the program's search horizon, so what it sees along that line of play would just be the loss of a pawn instead of the loss of a knight. The knight would still end up being captured, but far enough from the current position that the program doesn't see it. So, it sacrifices its pawn, thinking that will save the knight. The very next move, the same situation occurs, so it sacrifices another pawn, and another, until very soon it's lost a lot more material than the knight was ever worth, and will still end up losing the knight anyway. This sort of tailspin, in which a sequence of moderately bad moves is used to delay some worse consequence, is known as the "horizon effect" and it used to be an easy way to win games against computers (until better algorithms let them avoid this problem).
Unfortunately, "obviously bad" moves are often not bad at all, but are brilliant sacrifices that win the game. If you don't find one you should have made, you'll have to work harder and find some other way to win. Worse, if you don't see that your opponent is about to spring some such move sequence on you, you'll fall into the trap and lose.
How do we know when the eval is likely inaccurate?
Quiescence search is the idea of, after reaching the main search horizon, running a Turing-like search in which we only expand capturing moves (or sometimes, capturing and checking) moves. For games other than chess, the main idea would be to only include moves which make large changes to the evaluation. Such a search must also include "pass" moves in which we decide to stop capturing. Once both players pass, we stop expanding. That way, the evaluation function is only called on "quiescent" nodes at which it isn't about to change by making a capture.
One trick helps make sure this extension idea terminate: only extend by a fraction of a level. Specifically, make the "depth" counter record some multiple of the number of levels you really want to search, say depth=levels*24. Then, in recursive calls to alpha-beta search, pass a value of depth-24+extension. If the extension is always strictly less than 24, the method is guaranteed to terminate, and you can choose which situations result in larger or smaller extensions.