r4726: *** empty log message ***
authorKevin M. Rosenberg <kevin@rosenberg.net>
Thu, 1 May 2003 19:26:46 +0000 (19:26 +0000)
committerKevin M. Rosenberg <kevin@rosenberg.net>
Thu, 1 May 2003 19:26:46 +0000 (19:26 +0000)
io-clim.lisp
original/othello-orig.lisp [deleted file]
original/othello2-orig.lisp [deleted file]

index e0146f5bb825bb0133edc486ae57fc19a75795cf..61357dd081511da952d49430492473fda1b54d89 100644 (file)
@@ -8,7 +8,7 @@
 ;;;;  Programer:      Kevin M. Rosenberg
 ;;;;  Date Started:   1 Nov 2001
 ;;;;
-;;;; $Id: io-clim.lisp,v 1.9 2003/04/03 16:29:52 kevin Exp $
+;;;; $Id: io-clim.lisp,v 1.10 2003/05/01 19:26:46 kevin Exp $
 ;;;;
 ;;;; This file is Copyright (c) 2001-2002 by Kevin M. Rosenberg 
 ;;;;
@@ -19,6 +19,8 @@
 
 (in-package :reversi)
 
+#+mcclim (shadowing-import 'clim-internals::stream-set-cursor-position)
+
 (defparameter cell-inner-width 40)
 (defparameter cell-inner-height 40)
 (defparameter half-cell-inner-width 20)
                  (+ label-height (* cell-height i)
                       half-cell-inner-height))
                 :align-x :left :align-y :center))
-    (if (find-package 'mcclim)
-       (setf (stream-set-cursor-position stream)
-             (values label-width label-height))
-       (stream-set-cursor-position stream label-width label-height))
+    (stream-set-cursor-position stream label-width label-height)
     (surrounding-output-with-border (stream)
       (formatting-table (stream :y-spacing 0 :x-spacing 0)
        (dotimes (row 8)
diff --git a/original/othello-orig.lisp b/original/othello-orig.lisp
deleted file mode 100644 (file)
index d964c83..0000000
+++ /dev/null
@@ -1,451 +0,0 @@
-;;;; -*- Mode: Lisp; Syntax: Common-Lisp -*-
-;;;; Code from Paradigms of AI Programming
-;;;; Copyright (c) 1991 Peter Norvig
-
-;;;; File othello.lisp: An othello monitor, with all strategies
-;;;; up to and including section 18.8
-
-;;; One bug fix by Alberto Segre, segre@cs.cornell.edu, March 1993.
-
-(defun mappend (fn list)
-  "Append the results of calling fn on each element of list.
-  Like mapcon, but uses append instead of nconc."
-  (apply #'append (mapcar fn list)))
-
-(defun random-elt (seq) 
-  "Pick a random element out of a sequence."
-  (elt seq (random (length seq))))
-
-(defun concat-symbol (&rest args)
-  "Concatenate symbols or strings to form an interned symbol"
-  (intern (format nil "~{~a~}" args)))
-
-(defun cross-product (fn xlist ylist)
-  "Return a list of all (fn x y) values."
-  (mappend #'(lambda (y)
-               (mapcar #'(lambda (x) (funcall fn x y))
-                       xlist))
-           ylist))
-
-(defconstant all-directions '(-11 -10 -9 -1 1 9 10 11))
-
-(defconstant empty 0 "An empty square")
-(defconstant black 1 "A black piece")
-(defconstant white 2 "A white piece")
-(defconstant outer 3 "Marks squares outside the 8x8 board")
-
-(deftype piece () `(integer ,empty ,outer))
-
-(defun name-of (piece) (char ".@O?" piece))
-
-(defun opponent (player) (if (eql player black) white black))
-
-(deftype board () '(simple-array piece (100)))
-
-(defun bref (board square) (aref board square))
-(defsetf bref (board square) (val) 
-  `(setf (aref ,board ,square) ,val))
-
-(defun copy-board (board)
-  (copy-seq board))
-
-(defconstant all-squares
-  (loop for i from 11 to 88 when (<= 1 (mod i 10) 8) collect i))
-
-(defun initial-board ()
-  "Return a board, empty except for four pieces in the middle."
-  ;; Boards are 100-element vectors, with elements 11-88 used,
-  ;; and the others marked with the sentinel OUTER.  Initially
-  ;; the 4 center squares are taken, the others empty.
-  (let ((board (make-array 100 :element-type 'piece
-                           :initial-element outer)))
-    (dolist (square all-squares)
-      (setf (bref board square) empty))
-    (setf (bref board 44) white   (bref board 45) black
-          (bref board 54) black   (bref board 55) white)
-    board))
-
-(defun count-difference (player board)
-  "Count player's pieces minus opponent's pieces."
-  (- (count player board)
-     (count (opponent player) board)))
-
-(defun valid-p (move)
-  "Valid moves are numbers in the range 11-88 that end in 1-8."
-  (and (integerp move) (<= 11 move 88) (<= 1 (mod move 10) 8)))
-
-(defun legal-p (move player board)
-  "A Legal move must be into an empty square, and it must
-  flip at least one opponent piece."
-  (and (eql (bref board move) empty)
-       (some #'(lambda (dir) (would-flip? move player board dir))
-             all-directions)))
-
-(defun make-move (move player board)
-  "Update board to reflect move by player"
-  ;; First make the move, then make any flips
-  (setf (bref board move) player)
-  (dolist (dir all-directions)
-    (make-flips move player board dir))
-  board)
-
-(defun make-flips (move player board dir)
-  "Make any flips in the given direction."
-  (let ((bracketer (would-flip? move player board dir)))
-    (when bracketer
-      (loop for c from (+ move dir) by dir until (eql c bracketer)
-            do (setf (bref board c) player)))))
-
-(defun would-flip? (move player board dir)
-  "Would this move result in any flips in this direction?
-  If so, return the square number of the bracketing piece."
-  ;; A flip occurs if, starting at the adjacent square, c, there
-  ;; is a string of at least one opponent pieces, bracketed by 
-  ;; one of player's pieces
-  (let ((c (+ move dir)))
-    (and (eql (bref board c) (opponent player))
-         (find-bracketing-piece (+ c dir) player board dir))))
-
-(defun find-bracketing-piece (square player board dir)
-  "Return the square number of the bracketing piece."
-  (cond ((eql (bref board square) player) square)
-        ((eql (bref board square) (opponent player))
-         (find-bracketing-piece (+ square dir) player board dir))
-        (t nil)))
-
-(defun next-to-play (board previous-player print)
-  "Compute the player to move next, or NIL if nobody can move."
-  (let ((opp (opponent previous-player)))
-    (cond ((any-legal-move? opp board) opp)
-          ((any-legal-move? previous-player board) 
-           (when print
-             (format t "~&~c has no moves and must pass."
-                     (name-of opp)))
-           previous-player)
-          (t nil))))
-
-(defun any-legal-move? (player board)
-  "Does player have any legal moves in this position?"
-  (some #'(lambda (move) (legal-p move player board))
-        all-squares))
-
-(defun random-strategy (player board)
-  "Make any legal move."
-  (random-elt (legal-moves player board)))
-
-(defun legal-moves (player board)
-  "Returns a list of legal moves for player"
-  ;;*** fix, segre, 3/30/93.  Was remove-if, which can share with all-squares.
-  (loop for move in all-squares
-       when (legal-p move player board) collect move))
-
-(defun maximize-difference (player board)
-  "A strategy that maximizes the difference in pieces."
-  (funcall (maximizer #'count-difference) player board))
-
-(defun maximizer (eval-fn)
-  "Return a strategy that will consider every legal move,
-  apply EVAL-FN to each resulting board, and choose 
-  the move for which EVAL-FN returns the best score.
-  FN takes two arguments: the player-to-move and board"
-  #'(lambda (player board)
-      (let* ((moves (legal-moves player board))
-             (scores (mapcar #'(lambda (move)
-                                (funcall
-                                 eval-fn
-                                 player
-                                 (make-move move player
-                                            (copy-board board))))
-                             moves))
-             (best  (apply #'max scores)))
-        (elt moves (position best scores)))))
-
-(defparameter *weights*
-  '#(0   0   0  0  0  0  0   0   0 0
-     0 120 -20 20  5  5 20 -20 120 0
-     0 -20 -40 -5 -5 -5 -5 -40 -20 0
-     0  20  -5 15  3  3 15  -5  20 0
-     0   5  -5  3  3  3  3  -5   5 0
-     0   5  -5  3  3  3  3  -5   5 0
-     0  20  -5 15  3  3 15  -5  20 0
-     0 -20 -40 -5 -5 -5 -5 -40 -20 0
-     0 120 -20 20  5  5 20 -20 120 0
-     0   0   0  0  0  0  0   0   0 0))
-
-(defun weighted-squares (player board)
-  "Sum of the weights of player's squares minus opponent's."
-  (let ((opp (opponent player)))
-    (loop for i in all-squares
-          when (eql (bref board i) player) 
-          sum (aref *weights* i)
-          when (eql (bref board i) opp)
-          sum (- (aref *weights* i)))))
-
-(defconstant winning-value most-positive-fixnum)
-(defconstant losing-value  most-negative-fixnum)
-
-(defun final-value (player board)
-  "Is this a win, loss, or draw for player?"
-  (case (signum (count-difference player board))
-    (-1 losing-value)
-    ( 0 0)
-    (+1 winning-value)))
-
-(defun minimax (player board ply eval-fn)
-  "Find the best move, for PLAYER, according to EVAL-FN,
-  searching PLY levels deep and backing up values."
-  (if (= ply 0)
-      (funcall eval-fn player board)
-      (let ((moves (legal-moves player board)))
-        (if (null moves)
-            (if (any-legal-move? (opponent player) board)
-                (- (minimax (opponent player) board
-                            (- ply 1) eval-fn))
-                (final-value player board))
-            (let ((best-move nil)
-                  (best-val nil))
-              (dolist (move moves)
-                (let* ((board2 (make-move move player
-                                          (copy-board board)))
-                       (val (- (minimax
-                                 (opponent player) board2
-                                 (- ply 1) eval-fn))))
-                  (when (or (null best-val)
-                            (> val best-val))
-                    (setf best-val val)
-                    (setf best-move move))))
-              (values best-val best-move))))))
-
-(defun minimax-searcher (ply eval-fn)
-  "A strategy that searches PLY levels and then uses EVAL-FN."
-  #'(lambda (player board)
-      (multiple-value-bind (value move)
-          (minimax player board ply eval-fn) 
-        (declare (ignore value))
-        move)))
-
-(defun alpha-beta (player board achievable cutoff ply eval-fn)
-  "Find the best move, for PLAYER, according to EVAL-FN,
-  searching PLY levels deep and backing up values,
-  using cutoffs whenever possible."
-  (if (= ply 0)
-      (funcall eval-fn player board)
-      (let ((moves (legal-moves player board)))
-        (if (null moves)
-            (if (any-legal-move? (opponent player) board)
-                (- (alpha-beta (opponent player) board
-                               (- cutoff) (- achievable)
-                               (- ply 1) eval-fn))
-                (final-value player board))
-            (let ((best-move (first moves)))
-              (loop for move in moves do
-                (let* ((board2 (make-move move player
-                                          (copy-board board)))
-                       (val (- (alpha-beta
-                                 (opponent player) board2
-                                 (- cutoff) (- achievable)
-                                 (- ply 1) eval-fn))))
-                  (when (> val achievable)
-                    (setf achievable val)
-                    (setf best-move move)))
-                until (>= achievable cutoff))
-              (values achievable best-move))))))
-
-(defun alpha-beta-searcher (depth eval-fn)
-  "A strategy that searches to DEPTH and then uses EVAL-FN."
-  #'(lambda (player board)
-      (multiple-value-bind (value move)
-          (alpha-beta player board losing-value winning-value
-                      depth eval-fn) 
-        (declare (ignore value))
-        move)))
-
-(defun modified-weighted-squares (player board)
-  "Like WEIGHTED-SQUARES, but don't take off for moving
-  near an occupied corner."
-  (let ((w (weighted-squares player board)))
-    (dolist (corner '(11 18 81 88))
-      (when (not (eql (bref board corner) empty))
-        (dolist (c (neighbors corner))
-          (when (not (eql (bref board c) empty))
-            (incf w (* (- 5 (aref *weights* c))
-                       (if (eql (bref board c) player)
-                           +1 -1)))))))
-    w))
-
-(let ((neighbor-table (make-array 100 :initial-element nil)))
-  ;; Initialize the neighbor table
-  (dolist (square all-squares)
-    (dolist (dir all-directions)
-      (if (valid-p (+ square dir))
-          (push (+ square dir)
-                (aref neighbor-table square)))))
-
-  (defun neighbors (square)
-    "Return a list of all squares adjacent to a square."
-    (aref neighbor-table square)))
-
-(let ((square-names 
-        (cross-product #'concat-symbol
-                       '(? a b c d e f g h ?)
-                       '(? 1 2 3 4 5 6 7 8 ?))))
-
-  (defun h8->88 (str)
-    "Convert from alphanumeric to numeric square notation."
-    (or (position (string str) square-names :test #'string-equal)
-        str))
-
-  (defun 88->h8 (num)
-    "Convert from numeric to alphanumeric square notation."
-    (if (valid-p num)
-        (elt square-names num)
-        num)))
-
-(defun human (player board)
-  "A human player for the game of Othello"
-  (format t "~&~c to move ~a: " (name-of player)
-          (mapcar #'88->h8 (legal-moves player board)))
-  (h8->88 (read)))
-
-(defvar *move-number* 1 "The number of the move to be played")
-
-(defun othello (bl-strategy wh-strategy 
-                &optional (print t) (minutes 30))
-  "Play a game of othello.  Return the score, where a positive
-  difference means black, the first player, wins."
-  (let ((board (initial-board))
-        (clock (make-array (+ 1 (max black white))
-                           :initial-element 
-                           (* minutes 60 
-                              internal-time-units-per-second))))
-    (catch 'game-over
-      (loop for *move-number* from 1
-            for player = black then (next-to-play board player print)
-            for strategy = (if (eql player black) 
-                               bl-strategy
-                               wh-strategy)
-            until (null player)
-            do (get-move strategy player board print clock))
-      (when print
-        (format t "~&The game is over.  Final result:")
-        (print-board board clock))
-      (count-difference black board))))
-
-(defvar *clock* (make-array 3) "A copy of the game clock")
-(defvar *board* (initial-board) "A copy of the game board")
-
-(defun get-move (strategy player board print clock)
-  "Call the player's strategy function to get a move.
-  Keep calling until a legal move is made."
-  ;; Note we don't pass the strategy function the REAL board.
-  ;; If we did, it could cheat by changing the pieces on the board.
-  (when print (print-board board clock))
-  (replace *clock* clock)
-  (let* ((t0 (get-internal-real-time))
-         (move (funcall strategy player (replace *board* board)))
-         (t1 (get-internal-real-time)))
-    (decf (elt clock player) (- t1 t0))
-    (cond
-      ((< (elt clock player) 0)
-       (format t "~&~c has no time left and forfeits."
-               (name-of player))
-       (THROW 'game-over (if (eql player black) -64 64)))
-      ((eq move 'resign)
-       (THROW 'game-over (if (eql player black) -64 64)))
-      ((and (valid-p move) (legal-p move player board))
-       (when print
-         (format t "~&~c moves to ~a." 
-                 (name-of player) (88->h8 move)))
-       (make-move move player board))
-      (t (warn "Illegal move: ~a" (88->h8 move))
-         (get-move strategy player board print clock)))))
-
-(defun print-board (&optional (board *board*) clock)
-  "Print a board, along with some statistics."
-  ;; First print the header and the current score
-  (format t "~2&    a b c d e f g h   [~c=~2a ~c=~2a (~@d)]"
-          (name-of black) (count black board)
-          (name-of white) (count white board)
-          (count-difference black board))
-  ;; Print the board itself
-  (loop for row from 1 to 8 do
-        (format t "~&  ~d " row)
-        (loop for col from 1 to 8
-              for piece = (bref board (+ col (* 10 row)))
-              do (format t "~c " (name-of piece))))
-  ;; Finally print the time remaining for each player
-  (when clock
-    (format t "  [~c=~a ~c=~a]~2&"
-            (name-of black) (time-string (elt clock black))
-            (name-of white) (time-string (elt clock white)))))
-
-(defun time-string (time)
-  "Return a string representing this internal time in min:secs."
-  (multiple-value-bind (min sec)
-      (floor (round time internal-time-units-per-second) 60)
-    (format nil "~2d:~2,'0d" min sec)))
-
-(defun random-othello-series (strategy1 strategy2 
-                              n-pairs &optional (n-random 10))
-  "Play a series of 2*n games, starting from a random position."
-  (othello-series
-    (switch-strategies #'random-strategy n-random strategy1)
-    (switch-strategies #'random-strategy n-random strategy2)
-    n-pairs))
-
-(defun switch-strategies (strategy1 m strategy2)
-  "Make a new strategy that plays strategy1 for m moves,
-  then plays according to strategy2."
-  #'(lambda (player board)
-      (funcall (if (<= *move-number* m) strategy1 strategy2)
-               player board)))
-
-(defun othello-series (strategy1 strategy2 n-pairs)
-  "Play a series of 2*n-pairs games, swapping sides."
-  (let ((scores
-          (loop repeat n-pairs
-             for random-state = (make-random-state)
-             collect (othello strategy1 strategy2 nil)
-             do (setf *random-state* random-state)
-             collect (- (othello strategy2 strategy1 nil)))))
-    ;; Return the number of wins (1/2 for a tie),
-    ;; the total of the point differences, and the
-    ;; scores themselves, all from strategy1's point of view.
-    (values (+ (count-if #'plusp scores)
-               (/ (count-if #'zerop scores) 2))
-            (apply #'+ scores)
-            scores)))
-
-(defun round-robin (strategies n-pairs &optional
-                    (n-random 10) (names strategies))
-  "Play a tournament among the strategies.
-  N-PAIRS = games each strategy plays as each color against
-  each opponent.  So with N strategies, a total of
-  N*(N-1)*N-PAIRS games are played."
-  (let* ((N (length strategies))
-         (totals (make-array N :initial-element 0))
-         (scores (make-array (list N N)
-                             :initial-element 0)))
-    ;; Play the games
-    (dotimes (i N)
-      (loop for j from (+ i 1) to (- N 1) do 
-          (let* ((wins (random-othello-series
-                         (elt strategies i)
-                         (elt strategies j)
-                         n-pairs n-random))
-                 (losses (- (* 2 n-pairs) wins)))
-            (incf (aref scores i j) wins)
-            (incf (aref scores j i) losses)
-            (incf (aref totals i) wins)
-            (incf (aref totals j) losses))))
-    ;; Print the results
-    (dotimes (i N)
-      (format t "~&~a~20T ~4f: " (elt names i) (elt totals i))
-      (dotimes (j N)
-        (format t "~4f " (if (= i j) '---
-                             (aref scores i j)))))))
-
-(defun mobility (player board)
-  "The number of moves a player has."
-  (length (legal-moves player board)))
-
diff --git a/original/othello2-orig.lisp b/original/othello2-orig.lisp
deleted file mode 100644 (file)
index 001d305..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-;;;; -*- Mode: Lisp; Syntax: Common-Lisp -*-
-;;;; Code from Paradigms of AI Programming
-;;;; Copyright (c) 1991 Peter Norvig
-
-;;;; File othello2.lisp:  More strategies for othello.lisp,
-;;;; from section 18.9 onward (alpha-beta2, alpha-beta3, iago).
-;;;; If a compiled version of edge-table.lisp exists, then merely
-;;;; load it after you load this file.  Otherwise, load this file,
-;;;; evaluate (init-edge-table) (this will take a really long time),
-;;;; then compile edge-table.lisp.  This will save the edge-table for
-;;;; future use.
-
-;(requires "othello")
-
-(defconstant all-squares
-  (sort (loop for i from 11 to 88 
-             when (<= 1 (mod i 10) 8) collect i)
-        #'> :key #'(lambda (sq) (elt *weights* sq))))
-
-(defstruct (node) square board value)
-
-(defun alpha-beta-searcher2 (depth eval-fn)
-  "Return a strategy that does A-B search with sorted moves."
-  #'(lambda (player board)
-      (multiple-value-bind (value node)
-          (alpha-beta2
-            player (make-node :board board
-                              :value (funcall eval-fn player board))
-            losing-value winning-value depth eval-fn)
-        (declare (ignore value))
-        (node-square node))))
-
-(defun alpha-beta2 (player node achievable cutoff ply eval-fn)
-  "A-B search, sorting moves by eval-fn"
-  ;; Returns two values: achievable-value and move-to-make
-  (if (= ply 0)
-      (values (node-value node) node)
-      (let* ((board (node-board node))
-             (nodes (legal-nodes player board eval-fn)))
-        (if (null nodes)
-            (if (any-legal-move? (opponent player) board)
-                (values (- (alpha-beta2 (opponent player)
-                                        (negate-value node)
-                                        (- cutoff) (- achievable)
-                                        (- ply 1) eval-fn))
-                        nil)
-                (values (final-value player board) nil))
-            (let ((best-node (first nodes)))
-              (loop for move in nodes
-                    for val = (- (alpha-beta2
-                                   (opponent player)
-                                   (negate-value move)
-                                   (- cutoff) (- achievable)
-                                   (- ply 1) eval-fn))
-                    do (when (> val achievable)
-                         (setf achievable val)
-                         (setf best-node move))
-                    until (>= achievable cutoff))
-              (values achievable best-node))))))
-
-(defun negate-value (node)
-  "Set the value of a node to its negative."
-  (setf (node-value node) (- (node-value node)))
-  node)
-
-(defun legal-nodes (player board eval-fn)
-  "Return a list of legal moves, each one packed into a node."
-  (let ((moves (legal-moves player board)))
-    (sort (map-into
-            moves
-            #'(lambda (move)
-                (let ((new-board (make-move move player
-                                            (copy-board board))))
-                  (make-node
-                    :square move :board new-board
-                    :value (funcall eval-fn player new-board))))
-            moves)
-          #'> :key #'node-value)))
-
-(defvar *ply-boards*
-  (apply #'vector (loop repeat 40 collect (initial-board))))
-
-(defun alpha-beta3 (player board achievable cutoff ply eval-fn
-                    killer)
-  "A-B search, putting killer move first."
-  (if (= ply 0)
-      (funcall eval-fn player board)
-      (let ((moves (put-first killer (legal-moves player board))))
-        (if (null moves)
-            (if (any-legal-move? (opponent player) board)
-                (- (alpha-beta3 (opponent player) board
-                                (- cutoff) (- achievable)
-                                (- ply 1) eval-fn nil))
-                (final-value player board))
-            (let ((best-move (first moves))
-                  (new-board (aref *ply-boards* ply))
-                  (killer2 nil)
-                  (killer2-val winning-value))
-              (loop for move in moves
-                    do (multiple-value-bind (val reply)
-                           (alpha-beta3
-                             (opponent player)
-                             (make-move move player
-                                        (replace new-board board))
-                             (- cutoff) (- achievable)
-                             (- ply 1) eval-fn killer2)
-                         (setf val (- val))
-                         (when (> val achievable)
-                           (setf achievable val)
-                           (setf best-move move))
-                         (when (and reply (< val killer2-val))
-                           (setf killer2 reply)
-                           (setf killer2-val val)))
-                    until (>= achievable cutoff))
-              (values achievable best-move))))))
-
-(defun alpha-beta-searcher3 (depth eval-fn)
-  "Return a strategy that does A-B search with killer moves."
-  #'(lambda (player board)
-      (multiple-value-bind (value move)
-          (alpha-beta3 player board losing-value winning-value
-                       depth eval-fn nil)
-        (declare (ignore value))
-        move)))
-
-(defun put-first (killer moves)
-  "Move the killer move to the front of moves,
-  if the killer move is in fact a legal move."
-  (if (member killer moves)
-      (cons killer (delete killer moves))
-      moves))
-
-(defun mobility (player board)
-  "Current Mobility is the number of legal moves.
-  Potential mobility is the number of blank squares
-  adjacent to an opponent that are not legal moves.
-  Returns current and potential mobility for player."
-  (let ((opp (opponent player))
-        (current 0)    ; player's current mobility
-        (potential 0)) ; player's potential mobility
-    (dolist (square all-squares)
-      (when (eql (bref board square) empty)
-        (cond ((legal-p square player board)
-               (incf current))
-              ((some #'(lambda (sq) (eql (bref board sq) opp))
-                     (neighbors square))
-               (incf potential)))))
-    (values current (+ current potential))))
-
-(defvar *edge-table* (make-array (expt 3 10))
-  "Array of values to player-to-move for edge positions.")
-
-(defconstant edge-and-x-lists
-  '((22 11 12 13 14 15 16 17 18 27)
-    (72 81 82 83 84 85 86 87 88 77)
-    (22 11 21 31 41 51 61 71 81 72)
-    (27 18 28 38 48 58 68 78 88 77))
-  "The four edges (with their X-squares).")
-
-(defun edge-index (player board squares)
-  "The index counts 1 for player; 2 for opponent,
-  on each square---summed as a base 3 number."
-  (let ((index 0))
-    (dolist (sq squares)
-      (setq index (+ (* index 3)
-                     (cond ((eql (bref board sq) empty) 0)
-                           ((eql (bref board sq) player) 1)
-                           (t 2)))))
-    index))
-
-(defun edge-stability (player board)
-  "Total edge evaluation for player to move on board."
-  (loop for edge-list in edge-and-x-lists
-        sum (aref *edge-table*
-                  (edge-index player board edge-list))))
-
-(defconstant top-edge (first edge-and-x-lists))
-
-(defun init-edge-table ()
-  "Initialize *edge-table*, starting from the empty board."
-  ;; Initialize the static values
-  (loop for n-pieces from 0 to 10 do 
-        (map-edge-n-pieces
-          #'(lambda (board index)
-              (setf (aref *edge-table* index)
-                    (static-edge-stability black board)))
-          black (initial-board) n-pieces top-edge 0))
-  ;; Now iterate five times trying to improve:
-  (dotimes (i 5) 
-    ;; Do the indexes with most pieces first
-    (loop for n-pieces from 9 downto 1 do 
-          (map-edge-n-pieces
-            #'(lambda (board index)
-                (setf (aref *edge-table* index)
-                      (possible-edge-moves-value
-                        black board index)))
-            black (initial-board) n-pieces top-edge 0))))
-
-(defun map-edge-n-pieces (fn player board n squares index)
-  "Call fn on all edges with n pieces."
-  ;; Index counts 1 for player; 2 for opponent
-  (cond
-    ((< (length squares) n) nil)
-    ((null squares) (funcall fn board index))
-    (t (let ((index3 (* 3 index))
-             (sq (first squares)))
-         (map-edge-n-pieces fn player board n (rest squares) index3)
-         (when (and (> n 0) (eql (bref board sq) empty))
-           (setf (bref board sq) player)
-           (map-edge-n-pieces fn player board (- n 1) (rest squares)
-                              (+ 1 index3))
-           (setf (bref board sq) (opponent player))
-           (map-edge-n-pieces fn player board (- n 1) (rest squares)
-                              (+ 2 index3))
-           (setf (bref board sq) empty))))))
-
-(defun possible-edge-moves-value (player board index)
-  "Consider all possible edge moves. 
-  Combine their values into a single number."
-  (combine-edge-moves
-    (cons
-      (list 1.0 (aref *edge-table* index)) ;; no move
-      (loop for sq in top-edge             ;; possible moves
-            when (eql (bref board sq) empty)
-            collect (possible-edge-move player board sq)))
-    player))
-
-(defun possible-edge-move (player board sq)
-  "Return a (prob val) pair for a possible edge move."
-  (let ((new-board (replace (aref *ply-boards* player) board)))
-    (make-move sq player new-board)
-    (list (edge-move-probability player board sq)
-          (- (aref *edge-table*
-                   (edge-index (opponent player)
-                               new-board top-edge))))))
-
-(defun combine-edge-moves (possibilities player)
-  "Combine the best moves."
-  (let ((prob 1.0)
-        (val 0.0)
-        (fn (if (eql player black) #'> #'<)))
-    (loop for pair in (sort possibilities fn :key #'second)
-          while (>= prob 0.0)
-          do (incf val (* prob (first pair) (second pair)))
-             (decf prob (* prob (first pair))))
-    (round val)))
-
-(let ((corner/xsqs '((11 . 22) (18 . 27) (81. 72) (88 . 77))))
-  (defun corner-p (sq) (assoc sq corner/xsqs))
-  (defun x-square-p (sq) (rassoc sq corner/xsqs))
-  (defun x-square-for (corner) (cdr (assoc corner corner/xsqs)))
-  (defun corner-for (xsq) (car (rassoc xsq corner/xsqs))))
-
-(defun edge-move-probability (player board square)
-  "What's the probability that player can move to this square?"
-  (cond
-    ((x-square-p square) .5) ;; X-squares
-    ((legal-p square player board) 1.0) ;; immediate capture
-    ((corner-p square) ;; move to corner depends on X-square
-     (let ((x-sq (x-square-for square)))
-       (cond
-         ((eql (bref board x-sq) empty) .1)
-         ((eql (bref board x-sq) player) 0.001)
-         (t .9))))
-    (t (/ (aref
-            '#2A((.1  .4 .7)
-                 (.05 .3  *)
-                 (.01  *  *))
-            (count-edge-neighbors player board square)
-            (count-edge-neighbors (opponent player) board square))
-          (if (legal-p square (opponent player) board) 2 1)))))
-
-(defun count-edge-neighbors (player board square)
-  "Count the neighbors of this square occupied by player."
-  (count-if #'(lambda (inc)
-                (eql (bref board (+ square inc)) player))
-            '(+1 -1)))
-
-(defparameter *static-edge-table*
-  '#2A(;stab  semi    un 
-       (   *    0 -2000) ; X
-       ( 700    *     *) ; corner
-       (1200  200   -25) ; C
-       (1000  200    75) ; A
-       (1000  200    50) ; B
-       (1000  200    50) ; B
-       (1000  200    75) ; A
-       (1200  200   -25) ; C
-       ( 700    *     *) ; corner
-       (   *    0 -2000) ; X
-       ))
-
-(defun static-edge-stability (player board)
-  "Compute this edge's static stability"
-  (loop for sq in top-edge
-        for i from 0
-        sum (cond
-              ((eql (bref board sq) empty) 0)
-              ((eql (bref board sq) player)
-               (aref *static-edge-table* i
-                     (piece-stability board sq)))
-              (t (- (aref *static-edge-table* i
-                          (piece-stability board sq)))))))
-
-(let ((stable 0) (semi-stable 1) (unstable 2))
-  
-  (defun piece-stability (board sq)
-    (cond
-      ((corner-p sq) stable)
-      ((x-square-p sq)
-       (if (eql (bref board (corner-for sq)) empty)
-           unstable semi-stable))
-      (t (let* ((player (bref board sq))
-                (opp (opponent player))
-                (p1 (find player board :test-not #'eql
-                          :start sq :end 19))
-                (p2 (find player board :test-not #'eql
-                          :start 11 :end sq
-                          :from-end t)))
-           (cond
-             ;; unstable pieces can be captured immediately
-             ;; by playing in the empty square
-             ((or (and (eql p1 empty) (eql p2 opp))
-                  (and (eql p2 empty) (eql p1 opp)))
-              unstable)
-             ;; Semi-stable pieces might be captured
-             ((and (eql p1 opp) (eql p2 opp)
-                   (find empty board :start 11 :end 19))
-              semi-stable)
-             ((and (eql p1 empty) (eql p2 empty))
-              semi-stable)
-             ;; Stable pieces can never be captured
-             (t stable)))))))
-
-(defun Iago-eval (player board)
-  "Combine edge-stability, current mobility and
-  potential mobility to arrive at an evaluation."
-  ;; The three factors are multiplied by coefficients
-  ;; that vary by move number:
-  (let ((c-edg (+ 312000 (* 6240 *move-number*)))
-        (c-cur (if (< *move-number* 25)
-                   (+ 50000 (* 2000 *move-number*))
-                   (+ 75000 (* 1000 *move-number*))))
-        (c-pot 20000))
-    (multiple-value-bind (p-cur p-pot)
-        (mobility player board)
-      (multiple-value-bind (o-cur o-pot)
-          (mobility (opponent player) board)
-        ;; Combine the three factors into one sum:
-        (+ (round (* c-edg (edge-stability player board)) 32000)
-           (round (* c-cur (- p-cur o-cur)) (+ p-cur o-cur 2))
-           (round (* c-pot  (- p-pot o-pot)) (+ p-pot o-pot 2)))))))
-
-(defun Iago (depth)
-  "Use an approximation of Iago's evaluation function."
-  (alpha-beta-searcher3 depth #'iago-eval))
-