summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2002-04-07 08:44:00 +0000
committerJohn Wiegley <johnw@newartisans.com>2002-04-07 08:44:00 +0000
commit2ef00c4beddb77e546cdc212cc502c5a9a4bba6c (patch)
treef20a250ce3e162fd5580696528d7b8251cdcfcf4
parentb148d84be1c3bd781c4fd11dd0a928fbeeda28fd (diff)
Simplified the event model, and removed session objects. Now
everything just revolves around a game. Gnuchess is now playable to the end, except don't make moves that leave your king in check! The engine still doesn't check for this yet.
-rw-r--r--TODO12
-rw-r--r--chess-algebraic.el6
-rw-r--r--chess-crafty.el17
-rw-r--r--chess-display.el255
-rw-r--r--chess-engine.el77
-rw-r--r--chess-game.el77
-rw-r--r--chess-gnuchess.el25
-rw-r--r--chess-ics1.el2
-rw-r--r--chess-images.el3
-rw-r--r--chess-pgn.el9
-rw-r--r--chess-pos.el12
-rw-r--r--chess-process.el207
-rw-r--r--chess-session.el59
-rw-r--r--chess-standard.el2
-rw-r--r--chess.el55
15 files changed, 279 insertions, 539 deletions
diff --git a/TODO b/TODO
index ba11c81..5c70ad9 100644
--- a/TODO
+++ b/TODO
@@ -1,15 +1,3 @@
-Don't ever use chess-pos-move directly, but instead create ply and
-call chess-ply-next-pos. This will make sure that castling moves are
-interpreted correctly.
-
-Pawn captures while playing gnuchess cause an error.
-
-Is the whole event model just a bit too fragile?
-
-Write a debug function for displaying positions.
-
-The mode-line display is wrong (it's one ply off).
-----------------------------------------------------------------------
* 2.0
** Breakdown
diff --git a/chess-algebraic.el b/chess-algebraic.el
index cd67c6a..3905659 100644
--- a/chess-algebraic.el
+++ b/chess-algebraic.el
@@ -62,6 +62,8 @@ This regexp handles both long and short form.")
(if (eq piece ?O)
(let ((rank (if color 7 0))
(long (= (length (match-string 1 move)) 5)))
+ ;; jww (2002-04-07): This should be moderated by
+ ;; chess-standard!!
(list (chess-rf-to-index rank 4)
(chess-rf-to-index rank (if long 2 6))
(chess-rf-to-index rank (if long 0 7))
@@ -104,8 +106,8 @@ This regexp handles both long and short form.")
(list (if (equal mate "#")
':checkmate
':check))))
- (assert changes)
- (apply 'chess-ply-create position changes)))
+ (and changes
+ (apply 'chess-ply-create position changes))))
(defun chess-ply-to-algebraic (ply &optional long search-func)
"Convert the given PLY to algebraic notation.
diff --git a/chess-crafty.el b/chess-crafty.el
index d9038db..a88a831 100644
--- a/chess-crafty.el
+++ b/chess-crafty.el
@@ -14,13 +14,16 @@
chess-algebraic-regexp "\\)\\s-*$")
(function
(lambda ()
- (let ((position (chess-engine-position nil)))
- (if (string= (if (chess-pos-side-to-move position)
- "White" "Black")
- (match-string 1))
- (funcall chess-engine-response-handler 'move
- (chess-algebraic-to-ply position
- (match-string 2))))))))
+ (let ((position (chess-engine-position nil))
+ (move (match-string 2))
+ ply)
+ (when (string= (if (chess-pos-side-to-move position)
+ "White" "Black")
+ (match-string 1))
+ (setq ply (chess-algebraic-to-ply position move))
+ (unless ply
+ (error "Could not convert engine move: %s" move))
+ (funcall chess-engine-response-handler 'move ply))))))
(cons "Illegal move:\\s-*\\(.*\\)"
(function
(lambda ()
diff --git a/chess-display.el b/chess-display.el
index 5f11e56..e8fc67d 100644
--- a/chess-display.el
+++ b/chess-display.el
@@ -6,7 +6,6 @@
;;; Code:
-(require 'chess-session)
(require 'chess-game)
(require 'chess-algebraic)
(require 'chess-fen)
@@ -47,7 +46,6 @@
;; User interface
;;
-(defvar chess-display-session)
(defvar chess-display-game)
(defvar chess-display-search-function)
(defvar chess-display-variation)
@@ -60,7 +58,6 @@
(defvar chess-display-edit-mode nil)
(defvar chess-display-mode-line "")
-(make-variable-buffer-local 'chess-display-session)
(make-variable-buffer-local 'chess-display-game)
(make-variable-buffer-local 'chess-display-search-function)
(make-variable-buffer-local 'chess-display-variation)
@@ -80,7 +77,7 @@
,@body)
,@body)))
-(defun chess-display-create (style perspective &optional session search-func)
+(defun chess-display-create (style perspective &optional search-func)
"Create a chess display, for displaying chess objects."
(let* ((name (symbol-name style))
(draw (intern-soft (concat name "-draw")))
@@ -90,7 +87,6 @@
(error "There is no known chessboard display style '%s'" name))
(with-current-buffer (generate-new-buffer "*Chessboard*")
(setq cursor-type nil
- chess-display-session session
chess-display-draw-function draw
chess-display-highlight-function highlight
chess-display-perspective perspective
@@ -98,10 +94,6 @@
(chess-display-mode)
(if initialize
(funcall initialize))
- (if session
- (let ((game (chess-session-data session 'current-game)))
- (if game
- (chess-display-set-game nil game))))
(current-buffer))))
(defsubst chess-display-destroy (display)
@@ -110,10 +102,6 @@
(if (buffer-live-p buf)
(kill-buffer buf))))
-(defsubst chess-display-session (display)
- (chess-with-current-buffer display
- chess-display-session))
-
(defsubst chess-display-perspective (display)
(chess-with-current-buffer display
chess-display-perspective))
@@ -149,6 +137,8 @@ without a game object.
If the position is merely edited, it will change the POSITION object
that was passed in."
(chess-with-current-buffer display
+ (if chess-display-game
+ (chess-display-detach-game nil))
(setq chess-display-game nil
chess-display-search-function search-func
chess-display-variation nil
@@ -175,6 +165,8 @@ This differs from a position display, only in that the algebraic form
of the move made to the reach the displayed position will be shown in
the modeline."
(chess-with-current-buffer display
+ (if chess-display-game
+ (chess-display-detach-game nil))
(setq chess-display-game nil
chess-display-search-function search-func
chess-display-variation nil
@@ -198,6 +190,8 @@ the user able to scroll back and forth through the moves in the
variation. Any moves made on the board will extend/change the
variation that was passed in."
(chess-with-current-buffer display
+ (if chess-display-game
+ (chess-display-detach-game nil))
(setq chess-display-game nil
chess-display-search-function search-func
chess-display-variation plies
@@ -218,14 +212,27 @@ This will cause the first ply in the game's main variation to be
displayed. Also, information about the game is shown in the
modeline."
(chess-with-current-buffer display
+ (if chess-display-game
+ (chess-display-detach-game nil))
(setq chess-display-game game
chess-display-search-function nil
chess-display-variation nil
chess-display-index (or index 0)
chess-display-ply nil
chess-display-position nil)
+ (chess-game-add-hook game 'chess-display-event-handler display)
(chess-display-update nil)))
+(defun chess-display-detach-game (display)
+ "Set the display game.
+This will cause the first ply in the game's main variation to be
+displayed. Also, information about the game is shown in the
+modeline."
+ (chess-with-current-buffer display
+ (if chess-display-game
+ (chess-game-remove-hook chess-display-game
+ 'chess-display-event-handler))))
+
(defsubst chess-display-game (display)
(chess-with-current-buffer display
chess-display-game))
@@ -234,17 +241,13 @@ modeline."
(chess-with-current-buffer display
(unless chess-display-index
(error "There is no game or variation currently being displayed."))
- (if chess-display-game
- (unless (chess-game-pos chess-display-game index)
- (error "There is no position in the displayed game at index %d."
- index))
- (if (or (not (integerp index))
- (< index 0)
- (>= index (length chess-display-variation)))
- (error "There is no position in the display variation at index %d."
- index)))
- (setq chess-display-index index)
- (chess-display-update nil)))
+ (unless (or (not (integerp index))
+ (< index 0)
+ (> index (if chess-display-game
+ (chess-game-index chess-display-game)
+ (1+ (length chess-display-variation)))))
+ (setq chess-display-index index)
+ (chess-display-update nil))))
(defsubst chess-display-index (display)
(chess-with-current-buffer display
@@ -266,23 +269,20 @@ The position of PLY must match the currently displayed position.
If only START is given, it must be in algebraic move notation."
(chess-with-current-buffer display
(cond
- ((chess-display-active-p)
- (chess-session-event chess-display-session 'move ply))
(chess-display-game
;; jww (2002-03-28): This should beget a variation within the
;; game, or alter the game, just as SCID allows
(if (= (chess-display-index nil)
(chess-game-index chess-display-game))
- (setq chess-display-index
- (1+ (chess-game-index chess-display-game))))
- (chess-game-move chess-display-game ply))
+ (chess-game-move chess-display-game ply)
+ (error "What to do here?? NYI")))
(chess-display-variation
;; jww (2002-04-02): what if we're in the middle?
(nconc chess-display-variation (list ply))
(setq chess-display-index (1- (length chess-display-variation))))
(chess-display-ply
(setq chess-display-ply ply))
- (t ; an ordinary position
+ (chess-display-position ; an ordinary position
(setq chess-display-position (chess-ply-next-pos ply))))
(chess-display-update nil)))
@@ -292,50 +292,32 @@ The given highlighting MODE is used, or the default if the style you
are displaying with doesn't support that mode. `selected' is a mode
that is supported by most displays, and is the default mode."
(chess-with-current-buffer display
- (if (chess-display-active-p)
- (chess-session-event chess-display-session 'highlight
- index (or mode 'selected))
- (if chess-display-highlight-function
- (funcall chess-display-highlight-function index
- (or mode 'selected))))))
+ (if chess-display-highlight-function
+ (funcall chess-display-highlight-function index
+ (or mode 'selected)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Module method
+;; Event handler
;;
-;;;###autoload
-(defun chess-display (session display event &rest args)
+(defun chess-display-event-handler (game display event &rest args)
"This display module presents a standard chessboard.
See `chess-display-type' for the different kinds of displays."
- (if (eq event 'initialize)
- (chess-display-create
- (car args) (chess-session-data session 'my-color) session)
- (ignore
- (cond
- ((eq event 'shutdown)
- (chess-display-destroy display))
-
- ((eq event 'setup)
- (chess-display-set-game display (car args)))
-
- ((eq event 'highlight)
- ;; calling `chess-display-highlight' here would be recursive
- (if chess-display-highlight-function
- (funcall chess-display-highlight-function
- (car args) (cadr args))))
-
- ((eq event 'pass)
- (chess-display-set-perspective
- display (not (chess-display-perspective display))))
-
- ((eq event 'move)
- (chess-display-set-index
- display (chess-game-index (chess-display-game display)))
- (chess-display-update display))
-
- (t
- (chess-display-update display))))))
+ (cond
+ ((eq event 'shutdown)
+ (chess-display-destroy display))
+
+ ((eq event 'pass)
+ (chess-display-set-perspective
+ display (not (chess-display-perspective display))))
+
+ ((eq event 'move)
+ (chess-display-set-index
+ display (chess-game-index (chess-display-game display)))))
+
+ (unless (eq event 'shutdown)
+ (chess-display-update display)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
@@ -358,10 +340,10 @@ See `chess-display-type' for the different kinds of displays."
(define-key map [?X] 'chess-display-quit)
(define-key map [?M] 'chess-display-manual-move)
- (define-key map [?<] 'chess-display-move-backward)
+ (define-key map [?<] 'chess-display-move-first)
(define-key map [?,] 'chess-display-move-backward)
(define-key map [(meta ?<)] 'chess-display-move-first)
- (define-key map [?>] 'chess-display-move-forward)
+ (define-key map [?>] 'chess-display-move-last)
(define-key map [?.] 'chess-display-move-forward)
(define-key map [(meta ?>)] 'chess-display-move-last)
@@ -406,33 +388,38 @@ The key bindings available in this mode are:
(defun chess-display-set-modeline ()
"Set the modeline to reflect the current game position."
- (let ((ply (chess-display-ply nil))
- (color (chess-pos-side-to-move (chess-display-position nil)))
- (index (chess-display-index nil)))
+ (let ((color (chess-pos-side-to-move (chess-display-position nil)))
+ (index (chess-display-index nil))
+ ply)
(if (and index (= index 0))
(setq chess-display-mode-line
(format " %s START" (if color "White" "BLACK")))
- (setq chess-display-mode-line
- (concat
- " " (if color "White" "BLACK")
- (if index
- (concat " " (int-to-string
- (if (> index 1)
- (/ index 2) (1+ (/ index 2))))))
- (if ply
- (concat ". " (if color "... ")
- (chess-ply-to-algebraic
- ply nil (chess-display-search-function nil)))))))))
+ (cond
+ (chess-display-ply
+ (setq ply chess-display-ply))
+ (chess-display-game
+ (setq ply (chess-game-ply chess-display-game (1- index))))
+ (chess-display-variation
+ (setq ply (nth chess-display-variation (1- index)))))
+ (if ply
+ (setq chess-display-mode-line
+ (concat
+ " " (if color "White" "BLACK")
+ (if index
+ (concat " " (int-to-string
+ (if (> index 1)
+ (/ index 2) (1+ (/ index 2))))))
+ (if ply
+ (concat ". " (if color "... ")
+ (or (chess-ply-to-algebraic
+ ply nil
+ (chess-display-search-function nil))
+ "???")))))))))
(defsubst chess-display-active-p ()
"Return non-nil if the displayed chessboard reflects an active game.
-Basically, it means we are not editing or reviewing.
-The game must be part of an active session (i.e., not just reviewing a
-game object), and the board must represent the current position in
-that game (i.e., not editing the position, or reviewing an earlier
-position within the game)."
- (and chess-display-session
- chess-display-game
+Basically, it means we are playing, not editing or reviewing."
+ (and chess-display-game
(= (chess-display-index nil)
(chess-game-index chess-display-game))
(not chess-display-edit-mode)))
@@ -475,8 +462,8 @@ position within the game)."
(defun chess-display-quit ()
"Quit the current game."
(interactive)
- (if (chess-display-active-p)
- (chess-session-event chess-display-session 'shutdown)
+ (if chess-display-game
+ (chess-game-run-hooks chess-display-game 'shutdown)
(chess-display-destroy nil)))
(defun chess-display-manual-move (move)
@@ -487,9 +474,12 @@ position within the game)."
(if (chess-pos-side-to-move (chess-display-position nil))
"White" "Black")
(1+ (/ (or (chess-display-index nil) 0) 2))))))
- (chess-display-move nil (chess-algebraic-to-ply
- (chess-display-position nil) move
- (chess-display-search-function nil))))
+ (let ((ply (chess-algebraic-to-ply
+ (chess-display-position nil) move
+ (chess-display-search-function nil))))
+ (unless ply
+ (error "Illegal move notation: %s" move))
+ (chess-display-move nil ply)))
(defun chess-display-set-current (dir)
"Change the currently displayed board.
@@ -504,7 +494,8 @@ to the end or beginning."
(if chess-display-game
(chess-game-index chess-display-game)
(1- (length chess-display-variation)))))
- (message "Use '>' to return to the current position")))
+ (unless (chess-display-active-p)
+ (message "Use '>' to return to the current position"))))
(defun chess-display-move-backward ()
(interactive)
@@ -562,9 +553,10 @@ to the end or beginning."
(defun chess-display-send-board ()
"Send the current board configuration to the user."
(interactive)
- (if chess-display-session
- (chess-session-event chess-display-session 'setup
- (chess-game-create (chess-display-position nil))))
+ (if chess-display-game
+ (chess-game-set-plies
+ chess-display-game
+ (list (chess-ply-create (chess-display-position nil)))))
(setq cursor-type nil
chess-display-edit-mode nil))
@@ -599,11 +591,39 @@ to the end or beginning."
(make-variable-buffer-local 'chess-legal-moves-pos)
(make-variable-buffer-local 'chess-legal-moves)
+(defun chess-keyboard-test-move (move)
+ "Return the given MOVE if it matching the user's current input."
+ (let ((i 0) (x 0)
+ (l (length move))
+ (xl (length chess-move-string))
+ (match t))
+ (unless (or (and (equal chess-move-string "ok")
+ (equal move "O-O"))
+ (and (equal chess-move-string "oq")
+ (equal move "O-O-O")))
+ (while (and (< i l) (< x xl))
+ (if (= (aref move i) ?x)
+ (setq i (1+ i)))
+ (if (/= (downcase (aref move i))
+ (aref chess-move-string x))
+ (setq match nil i l)
+ (setq i (1+ i) x (1+ x)))))
+ (if match move)))
+
+(defsubst chess-keyboard-display-moves (&optional move-list)
+ (if (> (length chess-move-string) 0)
+ (message "[%s] %s" chess-move-string
+ (mapconcat 'identity
+ (or move-list
+ (delq nil (mapcar 'chess-keyboard-test-move
+ chess-legal-moves))) " "))))
+
(defun chess-keyboard-shortcut-delete ()
(interactive)
(setq chess-move-string
(substring chess-move-string 0
- (1- (length chess-move-string)))))
+ (1- (length chess-move-string))))
+ (chess-keyboard-display-moves))
(defun chess-keyboard-shortcut (&optional display-only)
(interactive)
@@ -625,40 +645,23 @@ to the end or beginning."
(chess-ply-to-algebraic ply nil search-func)))
(chess-legal-plies position search-func))
'string-lessp)))
- (let ((moves (mapcar
- (function
- (lambda (move)
- (let ((i 0) (x 0)
- (l (length move))
- (xl (length chess-move-string))
- (match t))
- (unless (or (and (equal chess-move-string "ok")
- (equal move "O-O"))
- (and (equal chess-move-string "oq")
- (equal move "O-O-O")))
- (while (and (< i l) (< x xl))
- (if (= (aref move i) ?x)
- (setq i (1+ i)))
- (if (/= (downcase (aref move i))
- (aref chess-move-string x))
- (setq match nil i l)
- (setq i (1+ i) x (1+ x)))))
- (if match move))))
- chess-legal-moves)))
- (setq moves (delq nil moves))
+ (let ((moves (delq nil (mapcar 'chess-keyboard-test-move
+ chess-legal-moves))))
(cond
((= (length moves) 1)
- (chess-display-move nil (chess-algebraic-to-ply
- (chess-display-position nil) (car moves)
- (chess-display-search-function nil)))
+ (let ((ply (chess-algebraic-to-ply
+ (chess-display-position nil) (car moves)
+ (chess-display-search-function nil))))
+ (unless ply
+ (error "Illegal move notation: %s" (car moves)))
+ (chess-display-move nil ply))
(setq chess-move-string nil
chess-legal-moves nil
chess-legal-moves-pos nil))
((null moves)
(chess-keyboard-shortcut-delete))
(t
- (message "[%s] %s" chess-move-string
- (mapconcat 'identity moves " ")))))))
+ (chess-keyboard-display-moves moves))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
diff --git a/chess-engine.el b/chess-engine.el
index 40090ab..19bd4cc 100644
--- a/chess-engine.el
+++ b/chess-engine.el
@@ -6,7 +6,6 @@
;;; Commentary:
-(require 'chess-session)
(require 'chess-game)
(defgroup chess-engine nil
@@ -16,7 +15,6 @@
(defvar chess-engine-regexp-alist nil)
(defvar chess-engine-event-handler nil)
(defvar chess-engine-response-handler nil)
-(defvar chess-engine-session nil)
(defvar chess-engine-position nil)
(defvar chess-engine-game nil)
(defvar chess-engine-search-function nil)
@@ -24,7 +22,6 @@
(make-variable-buffer-local 'chess-engine-regexp-alist)
(make-variable-buffer-local 'chess-engine-event-handler)
(make-variable-buffer-local 'chess-engine-response-handler)
-(make-variable-buffer-local 'chess-engine-session)
(make-variable-buffer-local 'chess-engine-position)
(make-variable-buffer-local 'chess-engine-game)
(make-variable-buffer-local 'chess-engine-search-function)
@@ -51,26 +48,22 @@
(defun chess-engine-do-move (ply)
(cond
- ((and chess-engine-session
- chess-engine-game)
- (chess-session-event chess-engine-session event ply))
(chess-engine-game
(chess-game-move chess-engine-game ply))
- (t
- (apply 'chess-pos-move ply))))
+ (chess-engine-position
+ (setq chess-engine-position (chess-ply-next-pos ply)))))
(defun chess-engine-default-handler (event &rest args)
(cond
((eq event 'move)
(chess-engine-do-move (car args)))))
-(defun chess-engine-create (module &optional user-handler session search-func)
+(defun chess-engine-create (module &optional user-handler search-func)
(let ((regexp-alist (intern-soft (concat (symbol-name module)
"-regexp-alist")))
(handler (intern-soft (concat (symbol-name module) "-handler"))))
(with-current-buffer (generate-new-buffer " *chess-engine*")
- (setq chess-engine-session session
- chess-engine-regexp-alist (symbol-value regexp-alist)
+ (setq chess-engine-regexp-alist (symbol-value regexp-alist)
chess-engine-event-handler handler
chess-engine-response-handler (or 'chess-engine-default-handler
user-handler))
@@ -79,11 +72,6 @@
(error "Failed to start chess engine process"))
(set-process-buffer proc (current-buffer))
(set-process-filter proc 'chess-engine-filter))
- (if session
- (let ((game (chess-session-data session 'current-game)))
- (if game
- (chess-engine-set-game nil game)))
- (chess-engine-set-game nil (chess-game-create nil search-func)))
(current-buffer))))
(defun chess-engine-destroy (engine)
@@ -97,18 +85,21 @@
(defun chess-engine-search-function (engine)
(chess-with-current-buffer engine
- chess-engine-search-function))
-
-(defun chess-engine-set-search-function (engine search-func)
- (chess-with-current-buffer engine
(if chess-engine-game
(chess-game-search-function chess-engine-game)
(or chess-engine-search-function
'chess-standard-search-position))))
-(defun chess-engine-session (engine)
+(defun chess-engine-set-search-function (engine search-func)
+ (chess-with-current-buffer engine
+ (if chess-engine-game
+ (error "Engine is currently linked to a game")
+ (setq chess-engine-search-function search-func))))
+
+(defsubst chess-engine-search-position (engine position target piece)
(chess-with-current-buffer engine
- chess-engine-session))
+ (funcall (chess-engine-search-function nil)
+ position target piece)))
(defun chess-engine-set-option (engine option value)
(chess-with-current-buffer engine
@@ -120,6 +111,8 @@
(defun chess-engine-set-position (engine position)
(chess-with-current-buffer engine
+ (if chess-engine-game
+ (chess-engine-detach-game nil))
(setq chess-engine-game nil
chess-engine-position position)
(chess-engine-command nil 'setup position)))
@@ -132,10 +125,19 @@
(defun chess-engine-set-game (engine game)
(chess-with-current-buffer engine
+ (if chess-engine-game
+ (chess-engine-detach-game nil))
(setq chess-engine-game game
chess-engine-position nil)
+ (chess-game-add-hook game 'chess-engine-event-handler engine)
(chess-engine-command nil 'setup (chess-game-pos game))))
+(defun chess-engine-detach-game (engine)
+ (chess-with-current-buffer engine
+ (if chess-engine-game
+ (chess-game-remove-hook chess-engine-game
+ 'chess-engine-event-handler))))
+
(defun chess-engine-game (engine)
(chess-with-current-buffer engine
chess-engine-game))
@@ -160,26 +162,23 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Module method
+;; Primary event handler
;;
-;;;###autoload
-(defun chess-engine (session engine event &rest args)
+(defun chess-engine-event-handler (game engine event &rest args)
"Handle any commands being sent to this instance of this module."
- (if (eq event 'initialize)
- (chess-engine-create (car args)
- 'chess-engine-session-callback session)
- (with-current-buffer engine
- (unless (apply chess-engine-event-handler event args)
- (cond
- ((eq event 'shutdown)
- (chess-engine-destroy engine))
-
- ((eq event 'setup)
- (chess-engine-set-game engine (car args)))
-
- ((eq event 'pass)
- (chess-engine-pass engine)))))))
+ (with-current-buffer engine
+ (assert (eq game (chess-engine-game nil)))
+ (apply chess-engine-event-handler event args)
+ (cond
+ ((eq event 'shutdown)
+ (chess-engine-destroy engine))
+
+ ((eq event 'setup)
+ (chess-engine-set-game engine (car args)))
+
+ ((eq event 'pass)
+ (chess-engine-pass engine)))))
(defun chess-engine-filter (proc string)
"Process filter for receiving text from a chess process."
diff --git a/chess-game.el b/chess-game.el
index 7e28405..fd3c5fa 100644
--- a/chess-game.el
+++ b/chess-game.el
@@ -25,21 +25,33 @@
("Result" . "*")
("TimeControl" . "-")))
-(defsubst chess-game-tags (game)
+(defsubst chess-game-hooks (game)
"Return the tags alist associated with GAME."
(car game))
-(defsubst chess-game-set-tags (game tags)
+(defsubst chess-game-set-hooks (game hooks)
"Return the tags alist associated with GAME."
- (setcar game tags))
+ (setcar game hooks))
-(defsubst chess-game-plies (game)
+(defun chess-game-add-hook (game function &optional data prepend)
"Return the tags alist associated with GAME."
- (cddr game))
+ (let ((hooks (chess-game-hooks game)))
+ (if (null hooks)
+ (chess-game-set-hooks game (list (cons function data)))
+ (if prepend
+ (chess-game-set-hooks game (cons (cons function data) hooks))
+ (nconc hooks (list (cons function data)))))))
+
+(defsubst chess-game-remove-hook (game function)
+ "Return the tags alist associated with GAME."
+ (chess-game-set-hooks game (assq-delete-all function
+ (chess-game-hooks game))))
-(defsubst chess-game-set-plies (game plies)
+(defsubst chess-game-run-hooks (game &rest args)
"Return the tags alist associated with GAME."
- (setcdr (cdr game) plies))
+ (dolist (hook (chess-game-hooks game))
+ (apply (car hook) game (cdr hook) args)))
+
(defsubst chess-game-search-function (game)
"Return the tags alist associated with GAME."
@@ -47,7 +59,18 @@
(defsubst chess-game-set-search-function (game func)
"Return the tags alist associated with GAME."
- (setcar (cdr game) func))
+ (setcar (cdr game) func)
+ (chess-game-run-hooks game 'rule-change))
+
+
+(defsubst chess-game-tags (game)
+ "Return the tags alist associated with GAME."
+ (nth 2 game))
+
+(defsubst chess-game-set-tags (game tags)
+ "Return the tags alist associated with GAME."
+ (setcar (nthcdr 2 game) tags)
+ (chess-game-run-hooks game 'set-tags))
(defsubst chess-game-tag (game tag)
"Return the value for TAG in GAME."
@@ -58,16 +81,27 @@
"Set a TAG for GAME to VALUE."
(let ((tags (chess-game-tags game)))
(if (null tags)
- (setcar game (list (cons tag value)))
+ (chess-game-set-tags game (list (cons tag value)))
(let ((entry (assoc tag tags)))
(if entry
(setcdr entry value)
- (nconc (car game)
- (list (cons tag value))))))))
+ (nconc tags (list (cons tag value)))))))
+ (chess-game-run-hooks game 'set-tag tag))
-(defun chess-game-del-tag (game tag)
+(defsubst chess-game-del-tag (game tag)
"Set a TAG for GAME to VALUE."
- (setcar game (assq-delete-all tag (chess-game-tags game))))
+ (chess-game-set-tags game (assq-delete-all tag (chess-game-tags game)))
+ (chess-game-run-hooks game 'delete-tag tag))
+
+
+(defsubst chess-game-plies (game)
+ "Return the tags alist associated with GAME."
+ (nth 3 game))
+
+(defsubst chess-game-set-plies (game plies)
+ "Return the tags alist associated with GAME."
+ (setcdr (nthcdr 2 game) plies)
+ (chess-game-run-hooks game 'set-plies))
(defsubst chess-game-index (game)
"Return the GAME's current position index."
@@ -97,6 +131,7 @@
"Return the position related to GAME's INDEX position."
(car (chess-game-ply game index)))
+
(defun chess-game-create (&optional position search-func tags)
"Create a new chess game object.
Optionally use the given starting POSITION (which is recorded using
@@ -104,17 +139,16 @@ the game's FEN tag).
SEARCH-FUNC specifies the function used to test the legality of moves.
TAGS is the starting set of game tags (which can always be changed
later using the various tag-related methods)."
- (let ((game (list tags
- (or search-func 'chess-standard-search-position))))
+ (let ((game
+ (list nil
+ (or search-func 'chess-standard-search-position)
+ tags
+ (list (chess-ply-create (or position
+ (chess-pos-create)))))))
(dolist (tag (cons (cons "Date" (format-time-string "%Y.%m.%d"))
chess-game-default-tags))
(unless (chess-game-tag game (car tag))
(chess-game-set-tag game (car tag) (cdr tag))))
- (chess-game-add-ply game (chess-ply-create
- (or position
- (chess-pos-create))))
- (if position
- (chess-game-set-tag game "FEN" (chess-pos-to-fen position)))
game))
(defun chess-game-move (game ply)
@@ -144,7 +178,8 @@ progress (nil), if it is drawn, resigned, mate, etc."
"0-1" "1-0")))
(t
(chess-game-add-ply game (chess-ply-create
- (chess-ply-next-pos current-ply)))))))
+ (chess-ply-next-pos current-ply)))
+ (chess-game-run-hooks game 'move current-ply)))))
;; A few convenience functions
diff --git a/chess-gnuchess.el b/chess-gnuchess.el
index 09fe89e..1f0e68b 100644
--- a/chess-gnuchess.el
+++ b/chess-gnuchess.el
@@ -8,13 +8,19 @@
(require 'chess-fen)
(require 'chess-algebraic)
+(defvar chess-gnuchess-now-moving nil)
+
(defvar chess-gnuchess-regexp-alist
(list (cons (concat "My move is : \\(" chess-algebraic-regexp "\\)")
(function
(lambda ()
- (funcall chess-engine-response-handler 'move
- (chess-algebraic-to-ply (chess-engine-position nil)
- (match-string 1))))))
+ (let* ((move (match-string 1))
+ (ply (chess-algebraic-to-ply
+ (chess-engine-position nil) move)))
+ (unless ply
+ (error "Could not convert engine move: %s" move))
+ (let ((chess-gnuchess-now-moving t))
+ (funcall chess-engine-response-handler 'move ply))))))
(cons "Illegal move:"
(function
(lambda ()
@@ -29,18 +35,23 @@
(executable-find "gnuchess")))
(message "Starting chess program 'gnuchess'...done")
proc))
+
((eq event 'shutdown)
(chess-engine-send nil "quit\n"))
+
((eq event 'setup)
(chess-engine-send nil (format "setboard %s\n"
(chess-pos-to-fen (car args)))))
+
((eq event 'pass)
(chess-engine-send nil "go\n"))
+
((eq event 'move)
- (chess-engine-send
- nil (concat (chess-ply-to-algebraic
- (car args) nil
- (chess-engine-search-function nil)) "\n")))))
+ (unless chess-gnuchess-now-moving
+ (chess-engine-send nil (concat (chess-ply-to-algebraic
+ (car args) nil
+ (chess-engine-search-function nil))
+ "\n"))))))
(provide 'chess-gnuchess)
diff --git a/chess-ics1.el b/chess-ics1.el
index e086772..1491a63 100644
--- a/chess-ics1.el
+++ b/chess-ics1.el
@@ -8,7 +8,7 @@
;;; Code:
-(defun chess-display-position (&optional position)
+(defun chess-debug-position (&optional position)
"This is a debugging function, and not meant from general use."
(interactive)
(let ((pos (or position (chess-engine-position nil))))
diff --git a/chess-images.el b/chess-images.el
index eb47d02..b4b9488 100644
--- a/chess-images.el
+++ b/chess-images.el
@@ -67,8 +67,7 @@ light_piece."
"The name of the file used for background squares.
This file is optional. If there is no file available by this name, a
solid color square will be created and used. This option exists so
-that specialized squares may be used such as marble tiles, etc.
-jww (2001-06-23): This is still not fully implemented."
+that specialized squares may be used such as marble tiles, etc."
:type 'file
:set 'chess-images-clear-image-cache
:group 'chess-images)
diff --git a/chess-pgn.el b/chess-pgn.el
index 36ce3f0..04a8575 100644
--- a/chess-pgn.el
+++ b/chess-pgn.el
@@ -18,7 +18,10 @@
((looking-at chess-algebraic-regexp)
(goto-char (match-end 0))
(setq prevpos position)
- (let ((ply (chess-game-algebraic-to-ply game (match-string 0))))
+ (let* ((move (match-string 0))
+ (ply (chess-game-algebraic-to-ply game (match-string 0))))
+ (unless ply
+ (error "Error reading move: %s" move))
(setq position (chess-ply-next-pos ply))
(nconc plies (list ply))))
((and top-level
@@ -138,9 +141,7 @@ If INDENTED is non-nil, indent the move texts."
;; (setq move (buffer-substring-no-properties (point) end)
;; coords (chess-algebraic-to-ply chess-display-position move))
;; ;; it will just get reinserted again
-;; (delete-region (point) end))
-;; (chess-session-event chess-current-session 'move
-;; (chess-algebraic-to-ply chess-display-position))))
+;; (delete-region (point) end)))
;;
;; (defun chess-pgn-insert-move (move &optional color sequence)
;; "Insert an algebraic move description into a PGN buffer.
diff --git a/chess-pos.el b/chess-pos.el
index 5eef9c1..b67070a 100644
--- a/chess-pos.el
+++ b/chess-pos.el
@@ -239,13 +239,13 @@ trying to move a blank square."
(if (= piece ? )
(error "Attempted piece move from blank square %s" from))
(chess-pos-set-piece position from ? )
- (chess-pos-set-piece position to piece)
- ;; once a piece is moved, en passant is no longer available
- (chess-pos-set-en-passant position nil)
- ;; toggle the side whose move it is
- (chess-pos-set-side-to-move
- position (not (chess-pos-side-to-move position)))))
+ (chess-pos-set-piece position to piece)))
(setq changes (cddr changes)))
+ ;; once a piece is moved, en passant is no longer available
+ (chess-pos-set-en-passant position nil)
+ ;; toggle the side whose move it is
+ (chess-pos-set-side-to-move position
+ (not (chess-pos-side-to-move position)))
position)
(provide 'chess-pos)
diff --git a/chess-process.el b/chess-process.el
deleted file mode 100644
index 21d4cdb..0000000
--- a/chess-process.el
+++ /dev/null
@@ -1,207 +0,0 @@
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;; Obtain movements and other information from a subprocess
-;;
-;; $Revision$
-
-;;; Commentary:
-
-(require 'chess-session)
-(require 'chess-game)
-(require 'chess-algebraic)
-
-(defgroup chess-process nil
- "Code for reading movements and other commands from a subprocess."
- :group 'chess)
-
-(defvar chess-process-command-or-host nil
- "What type of process is it?
-This could be a string, naming a command to run, in which case it is a
-local connection.
-It could be a cons cell, giving the (HOST . PORT) of a network connection.
-It could be a Lisp function, which will be called to establish
-whatever type of connection it wishes, so long as it returns a buffer
-related to the resulting process.")
-
-(make-variable-buffer-local 'chess-process-command-or-host)
-
-(defvar chess-process-arguments nil
- "If `chess-process-where' is a string or Lisp function, pass these args.")
-(defvar chess-process-game)
-(defvar chess-process-last-pos)
-(defvar chess-process-working nil)
-
-(make-variable-buffer-local 'chess-process-arguments)
-(make-variable-buffer-local 'chess-process-game)
-(make-variable-buffer-local 'chess-process-last-pos)
-(make-variable-buffer-local 'chess-process-working)
-
-(defvar chess-process-triggers nil
- "A list of regexps and the commands that they trigger.
-The alist should be of the form:
-
- ((REGEXP COMMAND ARG1-GROUP ARG2-GROUP ...) ...)
-
-Where the ARG*-GROUP entries specify which parenthesis groups in the
-regexp demarcate those arguments. Anything more complicated than this
-must be handled by modules that derive from this module.")
-
-(make-variable-buffer-local 'chess-process-triggers)
-
-;;; Code:
-
-(defun chess-process (session buffer event &rest args)
- "Handle any commands being sent to this instance of this module."
- (cond
- ((eq event 'initialize)
- (let ((buf (generate-new-buffer " *chess-process*")))
- (with-current-buffer buf
- (setq chess-process-triggers (nth 0 args)
- chess-process-command-or-host (nth 1 args)
- chess-process-arguments (nthcdr 2 args))
- (let ((proc
- (if (stringp chess-process-command-or-host)
- (prog2
- (message "Starting chess program '%s'..."
- chess-process-command-or-host)
- (apply 'start-process "chess-process"
- (current-buffer)
- chess-process-command-or-host
- chess-process-arguments)
- (message "Starting chess program '%s'...done"
- chess-process-command-or-host))
- (prog2
- (message "Connecting to host %s:%d..."
- (car chess-process-command-or-host)
- (cdr chess-process-command-or-host))
- (open-network-stream
- "chess-process" (current-buffer)
- (car chess-process-command-or-host)
- (cdr chess-process-command-or-host))
- (message "Connecting to host %s:%d...done"
- (car chess-process-command-or-host)
- (cdr chess-process-command-or-host))))))
- (unless (and proc (memq (process-status proc) '(run open)))
- (error "Failed to start chess process"))
- (set-process-filter proc 'chess-process-filter))
- buf)))
- ((eq event 'shutdown)
- (if (buffer-live-p buffer)
- (kill-buffer buffer)))
- (t
- (ignore
- (with-current-buffer buffer
- (cond
- ((eq event 'setup)
- (setq chess-process-game (car args)
- chess-process-last-pos (point-min)))))))))
-
-(defun chess-process-filter (proc string)
- "Process filter for receiving text from a chess process."
- (let ((buf (process-buffer proc)))
- (when (buffer-live-p buf)
- (with-current-buffer buf
- (let ((moving (= (point) (process-mark proc))))
- (save-excursion
- ;; Insert the text, advancing the process marker.
- (goto-char (process-mark proc))
- (insert string)
- (set-marker (process-mark proc) (point)))
- (if moving (goto-char (process-mark proc))))
- (unless chess-process-working
- (setq chess-process-working t)
- (unwind-protect
- (progn
- (goto-char chess-process-last-pos)
- (beginning-of-line)
- (while (not (eobp))
- (condition-case err
- (let ((triggers chess-process-triggers))
- (while triggers
- ;; this could be accelerated by joining
- ;; together the regexps
- (when (looking-at (caar triggers))
- (let ((command (nth 1 (car triggers)))
- (args (mapcar 'match-string
- (nthcdr 2 (car triggers)))))
- (cond
- ((functionp command)
- (apply command args))
- ((symbolp command)
- (chess-session-event chess-current-session
- command args))
- (t (eval command)))))
- (setq triggers (cdr triggers))))
- (chess-illegal (error-message-string err)))
- (forward-line)))
- (setq chess-process-last-pos (point)
- chess-process-working nil)))))))
-
-(defun chess-process-let (forms)
- `(let ((str (progn ,@forms)))
- (if (stringp str)
- (ignore
- (process-send-string (get-buffer-process (current-buffer))
- (concat str "\n")))
- str)))
-
-(defun chess-process-insert-forms (event)
- (if (assq event forms)
- (chess-process-let
- (prog1
- (cdr (assq event forms))
- (setq forms (assq-delete-all event forms))))))
-
-(defmacro define-chess-engine (name ignored triggers &rest forms)
- "Define a chess engine.
-NAME is an unquoted symbol name that denotes the engine. This name is
-used as the default string for the chess engine's external command
-name.
-TRIGGERS is a list of process triggers, which fire when the output
-from the process matches certain regexps. See
-`chess-process-triggers' for more information.
-FORMS is an alist of event symbols, and forms to evaluate when such an
-event is received by the module. If these forms return a string, this
-string will be sent to the engine process.
-See the file chess-engines.el for code examples."
- (let ((namestr (symbol-name name)))
- `(progn
- (defcustom ,(intern (concat "chess-" namestr "-command"))
- (and (require 'executable)
- (executable-find ,namestr))
- ,(concat "The name of the " namestr " program.")
- :type 'file
- :group 'chess-process)
-
- (defun ,(intern (concat "chess-" namestr))
- (session buffer event &rest args)
- (cond
- ((eq event 'initialize)
- (with-current-buffer
- (chess-process session buffer event ,triggers
- ,(intern (concat "chess-" namestr "-command")))
- ,(chess-process-insert-forms 'init)
- (current-buffer)))
- ((eq event 'shutdown)
- (when (buffer-live-p buffer)
- (ignore-errors
- ,(chess-process-insert-forms 'shutdown))
- (kill-buffer buffer)))
- (t
- (ignore
- (with-current-buffer buffer
- (cond
- ((eq event 'setup)
- (apply 'chess-process session buffer event args)
- ,(chess-process-insert-forms 'setup))
- ,@(mapcar
- (function
- (lambda (entry)
- `((eq event (quote ,(car entry)))
- ,(chess-process-let (cdr entry))))) forms)
- (t
- (apply 'chess-process session buffer event args)))))))))))
-
-(provide 'chess-process)
-
-;;; chess-process.el ends here
diff --git a/chess-session.el b/chess-session.el
deleted file mode 100644
index 8ddf3c6..0000000
--- a/chess-session.el
+++ /dev/null
@@ -1,59 +0,0 @@
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;; Manage a chess playing/viewing session
-;;
-;; $Revision$
-
-;;; Commentary:
-
-(defun chess-session-create ()
- (cons nil nil))
-
-(defun chess-session-add-listener (session listener &optional front object)
- (if (or front (not (cdr session)))
- (setcdr session (cons (cons listener object)
- (cdr session)))
- (nconc session (list (cons listener object)))))
-
-(defun chess-session-remove-listener (session listener)
- (setcdr session (delq (assq listener (cdr session))
- (cdr session))))
-
-(defun chess-session-data (session sym)
- (cdr (assq sym (car session))))
-
-(defun chess-session-set-data (session sym value)
- (let ((entry (assq sym (car session))))
- (if entry
- (setcdr entry value)
- (setcar session (cons (cons sym value)
- (car session))))))
-
-(defun chess-session-del-data (session sym)
- (setcar session (delq (assq sym (car session))
- (car session))))
-
-(defun chess-session-event (session event &rest args)
- (let ((listeners (cdr session)) result)
- (while (and (or (eq event 'initialize)
- (null result)) listeners)
- (setq result (apply (caar listeners) session (cdar listeners)
- event args))
- (if (eq event 'initialize)
- (setcdr (car listeners) result))
- (setq listeners (cdr listeners)))
- result))
-
-;; (define-chess-module MODULE (&rest args))
-;; (define-chess-module (MODULE BASES...) (&rest args)
-;; :ctor-args (ARGS...)
-;; :create-buffer
-;; (EVENT
-;; FORMS...)
-;; ...)
-;;
-;; (chess-call-derived args &optional base-module)
-
-(provide 'chess-session)
-
-;;; chess-session.el ends here
diff --git a/chess-standard.el b/chess-standard.el
index 68c207c..165cdce 100644
--- a/chess-standard.el
+++ b/chess-standard.el
@@ -73,6 +73,8 @@ indices which indicate where a piece may have moved from."
(< piece ?a)) -1 1))
(c (= bias -1))
p pos candidates)
+ ;; jww (2002-04-07): Don't return candidates that leave the king
+ ;; in check.
(cond
;; if the piece is `t', it means to find the candidates resulting
;; from any piece movement. This is useful for testing whether a
diff --git a/chess.el b/chess.el
index 4d74a4e..3608442 100644
--- a/chess.el
+++ b/chess.el
@@ -73,7 +73,6 @@ a0 243
;; interface commands available in each of those buffer types.
;;; Code:
-(require 'chess-session)
(require 'chess-game)
(require 'chess-display)
@@ -82,7 +81,7 @@ a0 243
(defgroup chess nil
"An Emacs chess playing program."
:group 'games)
-(defconst chess-version "2.0a1"
+(defconst chess-version "2.0a2"
(defconst chess-version "2.0a7"
"The version of the Emacs chess program.")
@@ -100,50 +99,14 @@ a0 243
(defun chess (&optional arg)
"Start a game of chess."
(interactive "P")
- (let ((session (chess-session-create))
- (perspective t)) ; start out as white always
- ;; setup `chess-handler' to receive all events first
- (chess-session-add-listener session 'chess-handler)
- (chess-session-set-data session 'my-color perspective)
- ;; initialize all of the modules, and setup a new game
- (chess-session-event session 'initialize)
- (chess-session-event session 'setup (chess-game-create))
- ;; create a display object linked to the session, and add it to
- ;; the event chain; it is via this object that session events will
- ;; for the most part be generated
- (require chess-default-display)
- (chess-session-add-listener session 'chess-display nil
- (chess-display-create chess-default-display
- perspective session))
- ;; unless prefix arg is given, use `chess-default-engine' to play
- ;; against; otherwise, just create a board for play between two
- ;; people
- (unless arg
- (require chess-default-engine)
- (chess-session-add-listener session 'chess-engine nil
- (chess-engine-create chess-default-engine
- nil session)))))
-
-(defun chess-handler (session window-config event &rest args)
- "React to changes on the chess board in a global Emacs way."
- (if (eq event 'initialize)
- (current-window-configuration)
- (ignore
- (cond
- ((eq event 'shutdown)
- (set-window-configuration window-config))
-
- ((eq event 'setup)
- (chess-session-set-data session 'current-game (car args)))
-
- ((eq event 'pass)
- (let ((color (not (chess-session-data session 'my-color))))
- (message "You are now playing %s" (if color "White" "Black"))
- (chess-session-set-data session 'my-color (not color))))
-
- ((eq event 'move)
- (chess-game-move (chess-session-data session 'current-game)
- (car args)))))))
+ (require chess-default-display)
+ (require chess-default-engine)
+ (let ((game (chess-game-create)) ; start out as white always
+ display engine)
+ (chess-display-set-game
+ (chess-display-create chess-default-display t) game)
+ (chess-engine-set-game
+ (chess-engine-create chess-default-engine) game)))
(aset chess-puzzle-locations 3 puzzle-engine)))))))
(provide 'chess)