This was not a problem in my Scheme code, because when run manually, it does print everything correctly. (See below on how you can download this code and try it yourself.) I actually don't know what caused this; presumably it was some funny problem with an output buffer not being flushed to a file. It was not a problem with my program crashing.
There was not time to run another round robin tournament, so I ran a limited tournament:
This was a round robin tournament, and there were 46 entries. For each pair of students, we played two games, so both players had a chance to be X and O. That's 90 games for each student and a total of 2070 games which took several computer-days to run. This tournament used the regular alpha-beta minimax search since the version I had written to choose among the optimal moves had a bug in it.
It turns out that many students' players had bugs in them. I'm not exactly sure how they got by the pretesting. So I added some error trapping mechanisms to the tournament program. If there was an error generated during a call to your evaluation function, then a random valid move is picked on your behalf.
Here are the results:
We'll be emailing the transcripts of all your games soon.
Problem 5 was scored as follows. Any student that had uploaded a
valid player by the assignment deadline received 5 points. The
remaining 35 points were determined from the tournament results.
These were based on an average of your ranking from the two versions
of the results above. For each ranking, the top player received 35
points, the bottom player received 5 points. Players in the middle
received points linearly proportional to their ranking (not wins or
score). Students that tied in a ranking received the same score for
that ranking. Points from the two rankings were averaged. For
example, if you were exactly in the middle of one ranking, you would
have gotten 20 points, and if you were exactly 2/3 in the ranking from
the bottom, you would have gotten 25 points from that ranking.
Averaged and rounded, this would come out to 23 points.
Announcements
If you got 115 states and column 1, you may have done the same thing that I initially did which was to switch the order of the current-player and max-player arguments to the evaluation function in the ab-min-player procedure.
This file of compiled Scheme code contains the procedures that implement Nim, allow you to play against the computer for Nim and Welter's game, and some support code for Connect 4.
This file of Scheme source code contains the remaining support code for Connect 4, in particular, the state represntation and feature detectors.
Some of these might actually be the same applet...
Hints
I suggest you try drawing out the game tree and figuring out what the paths are for optimal games and checking whether you've in fact returned one of them.
(inf:> 7 2) ==> #t (inf:> 7 'pos-infinity) ==> #f (inf:= 'neg-infinity 'neg-infinity) ==> #t (inf:max 8 'neg-infinity) ==> 8 (inf:min 8 'neg-infinity) ==> neg-infinityNote that the inf:max and inf:min procedures, unlike their regular counterparts, only take 2 arguments.
(define (create-c4-player eval-fn depth-cutoff) (define (ab-minimax board player) (second (ab-max board player eval-fn 'neg-infinity 'pos-infinity 0 depth-cutoff))) ab-minimax)In my implementation, the convention I use is that the ab-max and ab-min procedures return a list where the first element is the value of the subtree and the second element is the best move. Since the player function must return a move, it only takes the second element of this list.
You can use whatever convention you want in what your ab-max and ab-min procedures return so long as the player function returns a valid move, i.e. an integer between 1 and 7 inclusive.