Homework 4: Game tree search
Your assignment is to write a parallel game tree search for Othello,
using the Cilk language. We borrowed the idea for this assignment
(with permission) from Rice's Spring 2007 COMP 422 course.
Here
is the website describing their version of the assignment. We have
modified their provided code to include a timer and a (naive) computer
player, and changed the requirements somewhat.
Requirements
- Using Cilk, implement a parallel version of alpha/beta search.
You may optionally implement another form of pruning search for
comparison. The maximum depth of the search should be a parameter.
- Use Rice's
COMP 422 website as a guideline for benchmarking and writing
your report. (Please don't run on more than 8 processors, unless
you are on a machine other than PSI.)
- Our input specification is slightly different: we use
command-line arguments rather than a script. These input
requirements are not strict: you may modify them as you think
appropriate, as long as you include instructions for how to run
your program.
- Our timing requirements are also different: we would prefer that
you time each move, rather than the entire execution of the
program. This lets you as a human player play against the
computer, and still collect meaningful timings. You don't have
to report all the timings for all the moves: think of a
way to report only the relevant data. (Remember that runtime per
move may change as the game progresses, so averaging over the
whole game probably isn't a good idea!)
- The provided code offers a framework for playing and reasoning
about Othello games. You may use and modify any of the provided
code.
- You should implement at least two different board evaluation
functions. Compare the performance of each, both in terms of
runtime and in terms of successful game play. (You may wish to
play computer vs. computer to do this comparison, in which case
you'll need to modify the provided code to change how timings
are collected.)
- Compare runtime per turn as a function of number of processors,
maximum search depth, and board evaluation function. Also test
the effectiveness of your computer player, both by playing
against it as a human player, and by playing one of your computer
players (with one board evaluation function) against another
computer player (with the same board evaluation function, and
with a different one). It's up to you how to report playing
effectiveness.
Provided code
UPDATE (mfh 10:31 12 Oct 2007):
bugfix in othello.cilk. Please refresh provided code from Git repository
(preferred) or current tarball.
Grading criteria
These are borrowed from Rice's assignment.
-
10% Program correctness:
Does it work, especially in the end cases in which a player may not be
able to move? Can the computer play itself fairly without causing
data corruption? Is the program thread-safe (or if not, was this
non-safety justified by extensive tests? -- probably you shouldn't
try this)?
- 40% Program parallelization,
clarity, and documentation: Is it a parallel program? Were
parallelism and the features of Cilk thoughtfully exploited?
Can we understand, build, and run your code?
- 10% Program scalability and
performance: Did your cleverness pay off? Cilk is known
to be highly effective for game tree search. If you don't get
some kind of speedup, then you're probably doing something wrong
(note that you need to supply the number of processors as a
command-line argument to your executable, and not to cilkc).
-
40% Writeup: the usual
benchmarking methodology and clear writeup.
Due date
Homework 4 is due Thursday, 25 October, at 5pm. However, we
strongly recommend starting early, because completing
the tests may require playing by hand against the computer, which
requires interactive batch jobs.
Hints
Cilk features
Cilk offers some features that can help you implement game tree search
efficiently. In particular, an alpha/beta search will not need any
locks, if you use inlets to update alpha and beta. You can also use
"abort" within an inlet to break off search early.
Optional parallel optimizations
- The "young brothers wait" optimization (described in the Cilkchess paper).
- Experiment with Cilk's option to pin threads to processors.
Optional sequential optimizations
- Implement iterative deepening (recommended, as a way to limit
search time).
- Improve the board evaluation heuristics. You can find many
different heuristic evaluation functions in the source code
for Peter Norvig's book
Paradigms of Artificial Intelligence Programming: Case Studies
in Common Lisp. (Common Lisp looks enough like Scheme that
you shouldn't have problems reading the code, but Mark can help
you if you have any questions, as he knows Common Lisp pretty
well.)
- Implement quiescence search (don't search a node if you think
its score won't change much).
- Try a different search other than alpha/beta. You may find
null-move pruning an interesting alternative, as null moves are
possible in Othello (though not by choice), unlike in chess.
- Exploit symmetry in the opening moves, in order to reduce the
size of the search space.
- With iterative deepening: use a (thread-safe) hash table to
keep track of the best child of each node you've seen before, and
search that child first. (This is hard, because you'll need to find
or implement an efficient
thread-safe hash table. The Cilk team found this hard enough that
they opted for a NON-thread-safe hash table. Some people have built
thread-safe non-locking hash tables that exploit atomic operations
and/or memory fences.)
References
-
Cilk
5.4.6 manual (please read!!!)
-
S. Russell and P. Norvig. "Artificial Intelligence: A Modern
Approach." Prentice-Hall, 1995. (There has since been at least
one newer edition. Mark has a copy of the first edition in his
office.)
-
D. Dailey and C. E. Leiserson. "Using Cilk to write multiprocessor
chess programs," 2001.
PDF.
This is a very readable paper with a good overview of the history
of Cilk and some of the motivations behind its design. Check the
references if you're interested in other forms of pruning minimax
search, other than alpha/beta search. You'll also find a good
discussion and implementation sketch of a transposition table (shared
hash table). Strictly speaking, a transposition table isn't necessary
for Othello, because positions don't repeat (unlike in Chess), but you
may find it useful for exploiting symmetry or caching the ordering in
which children are searched with iterative deepening.
-
Cilk Pousse report.
This describes the game tree search code that the Cilk team wrote in a
72-hour programming contest in 1998, for an unfamilar game called
Pousse. (Let us reassure you that very little of the 72 hours was
spent coding; they spent almost all of that time refining their
solution and running benchmarks to train and improve their
heuristics.) This report practically gives away the solution,
incidentally!
Last updated 12 Oct 2007.