minimax.lisp,
which contains the game-independent implementation of the minimax
algorithm, and othello.lisp,
which contains the plugins to minimax for the othello game.
The code in the files above provides the following definitions that you may find useful:
*max* |
[Constant] |
*min* |
[Constant] |
*debug* |
[Variable] |
nil, the minimax function will output
information about each node in the state tree it examines. When
nil, minimax will output nothing. Useful for debugging
your heuristic.
state |
[Structure] |
board:The game board this state represents.
This is the most important slot in the structure for the purposes of
your heuristic. The individual positions on the board can be accessed
with the get-posn function, described below.
bottom: This slot is non-nil if the state is a
end of game state (board full or someone won), nil
otherwise. If non-nil, the value must be one of the
following: BLK if the state represents a victory for
Black, WHT if the state represents a victory for White, or
DRAW if the state represents a full board.
You should use this slot - your heuristic should return
*max* if the value is WHT,
*min* if the value is BLK,
and 0 if the value is DRAW.
parent:The state which is the parent of this state in
the search tree. If nil, this is the top of the search.
You can probably ignore this slot, though you may use it if you want.
children:A list of states which are the children of
this state. If nil, it means either than this state has
not yet been expanded, or that the state has no children (i.e. it
represents a full board, or a win/loss). You can ignore this slot, as
it should be nil when your function is called.
heuristic:The value of the heuristic for this
state. You can ignore this slot, the minimax function will not call
your heuristic function unless this slot is empty.
cost: The cost of this state. This is used by the
minimax function for pruning, you can ignore this slot.
max: Max is t if the state represents
the computer's move, and nil if the state represents the
opponent's move. You can ignore this slot as well, your heuristic
function should always return a value that is from the computer's
perspective (White), the minimax algorithm takes care of alternating min
and max.
move: This slot indicates the (x,y) coords of the move most
recently made. You can probably ignore this slot as well.
below: The number of nodes that have been expanded
below this one, used to gather stats about the search for display
purposes. You can ignore this slot as it should be 0 when your
heuristic function is called.
The following function is provided for you to access individual positions on the game board (the board slot of a state):
get-posn board row col |
[Function] |
BLK, WHT, or
NIL, which should be the contents of the board at
position row, col. The indices begin at zero, with the top
left position being (0,0), and the bottom right being
(7,7).
The examples below show the results based on the board to the right:
> (get-posn (state-board state) 0 0) ; top left corner NIL > (get-posn (state-board state) 7 0) ; bottom left corner NIL > (get-posn (state-board state) 7 7) ; bottom right corner NIL > (get-posn (state-board state) 0 7) ; Top right corner NIL > (get-posn (state-board state) 3 3) ; fourth column, fourth spot from the top. WHT > (get-posn (state-board state) 4 3) ; fourth column, fifth spot from the top.
You are only required to provide one function, although this function may well call a series of other functions you define. You should give the function a name that reflects your own name:
your-name state |
[Function] |
Your function must return *max* if, and
only if, state represents a winning position for White (the
computer always plays as White), *min* if, and only
if, state represents a winning position for Black, and
0 if the state represents a draw (full board). You can
get this information immediately from the bottom slot of
the state (see above). The value it
returns for non-winning boards must be within this range, with, in
general, negative numbers indicating advantages for Black, positive
numbers indicating advantages for White, and 0 representing a purely
neutral state of the game. Your function should always evaluate a
state from the perspective of the White player.
Your function may call any number of other support functions to do its job, including any of the support functions in the two LISP files that were not explicitly documented here.
The file your heuristic is in should have the same name as your
heuristic function, with a ".lisp" extension. In
addition, the first line of your file must be: (in-package
:cl-user)
The main part of the project will be playing against your heuristic, trying to analyze its performance, and improving it. A web interface has been provided for this, and you will have to submit your heuristic to the web server to use it. First, however, you must test your code to be sure it works. Play a few games against it to be sure it runs without errors before you submit it to the server. To test your code, you have to download the support code and make use of the ASCII text interface for playing a game. Follow these instructions:
minimax.lisp,
and
othello.lisp.
There is code for the default heuristic, which basically just checks
for win/loss, in default.lisp.
You might find this useful in getting started.
When the files are all loaded, you can play a text-based game by using the following functions:
start-text-game heuristic ply |
[Function] |
play x y |
[Function] |
After a game is over, you should not call play again, unless
you call the function start-text-game.
Deliverables
You are required to hand in two things: your heuristic code, and a
writeup. Before you hand in your heuristic, you should test it to be
sure it works.
There will be a tournament amongst all the heuristics. The winner
will receive a prize.
For your writeup, consider that the point of this project is for you to experiment with your heuristic. Instead of spending your time implementing all of minimax, you only have to implement a heuristic, and then play. Play a lot of games against it. For each game, see if you can figure out why it makes each move. Watch in particular for "don't care" moves, which tend to be the topmost then leftmost possible move, and see if you can determine why it makes these moves and iteratively improve your heuristic (a good player never makes a "don't care" move).
You should get a feel for conceptualizing a game-playing strategy as an algorithm that returns a number.
Your writeup should include a description of what your heuristic is supposed to be doing. In other words, describe in English the strategy your heuristic implements. Then discuss your analysis of its strengths and weaknesses from your game-playing observations. Consider how prone it is to the horizon effect, and discuss ways you might (or have) overcome them.
Get an early start, this is way more than it looks.
The writeup should be submitted by email.
To submit your heuristic code, drop your file into the dropbox and send me email indicating the name of the file, I will then install it on the server.
Please test your heuristic to be sure it doesn't generate errors before submitting it.