diff options
| author | John Wiegley <johnw@newartisans.com> | 2002-03-11 20:57:21 +0000 |
|---|---|---|
| committer | John Wiegley <johnw@newartisans.com> | 2002-03-11 20:57:21 +0000 |
| commit | 871e9bb270b35c621265fc56ec582bdd39900e2a (patch) | |
| tree | 0f031b50dba5beb8a49e697f2488831a32f69655 | |
| parent | 442c62fd96d5cb79ab34faf1d8108d86372e96c3 (diff) | |
changes
| -rw-r--r-- | TODO | 10 | ||||
| -rw-r--r-- | chess-algebraic.el | 16 | ||||
| -rw-r--r-- | chess-crafty.el | 45 | ||||
| -rw-r--r-- | chess-display.el | 29 | ||||
| -rw-r--r-- | chess-engines.el | 56 | ||||
| -rw-r--r-- | chess-game.el | 108 | ||||
| -rw-r--r-- | chess-gnuchess.el | 38 | ||||
| -rw-r--r-- | chess-pgn.el | 114 | ||||
| -rw-r--r-- | chess-ply.el | 12 | ||||
| -rw-r--r-- | chess-process.el | 105 | ||||
| -rw-r--r-- | chess-session.el | 10 | ||||
| -rw-r--r-- | chess-standard.el | 16 | ||||
| -rw-r--r-- | chess.el | 7 |
13 files changed, 313 insertions, 253 deletions
@@ -1,5 +1,15 @@ * 2.0 +** Breakdown + +*** Core library +*** Display modules +*** Chess engines + +** Finished writing `define-chess-module' + +** Call `chess-game-move' in chess-display to move the pieces + ** Keyboard shortcuts *** Right now "nf, nf", causes an error diff --git a/chess-algebraic.el b/chess-algebraic.el index 0b041cb..d32bbbb 100644 --- a/chess-algebraic.el +++ b/chess-algebraic.el @@ -33,7 +33,6 @@ ;; $Revision$ -(require 'chess-pos) (require 'chess-ply) (defconst chess-algebraic-pieces-regexp "[RNBKQ]") @@ -52,7 +51,7 @@ "A regular expression that matches all possible algebraic moves. This regexp handles both long and short form.") -(defun chess-algebraic-to-ply (position move) +(defun chess-algebraic-to-ply (position move &optional search-func) "Convert the algebraic notation MOVE for POSITION to a ply." (when (string-match chess-algebraic-regexp move) (let* ((color (chess-pos-side-to-move position)) @@ -77,10 +76,9 @@ This regexp handles both long and short form.") ;; move, to determine which piece is meant by the ;; piece indicator (when (setq candidates - (funcall (car chess-modules) nil nil - 'search position target - (if color piece - (downcase piece)))) + (funcall (or search-func chess-standard-search) + position target (if color piece + (downcase piece)))) (if (= (length candidates) 1) (list (car candidates) target) (if (null source) @@ -101,7 +99,7 @@ This regexp handles both long and short form.") ':check)))) (apply 'chess-ply-create position changes)))) -(defun chess-ply-to-algebraic (ply &optional long) +(defun chess-ply-to-algebraic (ply &optional long search-func) "Convert the given PLY to algebraic notation. If LONG is non-nil, render the move into long notation." (if (null (car (chess-ply-changes ply))) @@ -122,8 +120,8 @@ If LONG is non-nil, render the move into long notation." "O-O-O")))) str (let ((candidates - (funcall (car chess-modules) - nil nil 'search pos to from-piece)) + (funcall (or search-func chess-standard-search) + pos to from-piece)) (rank 0) (file 0) (from-rank (/ from 8)) (from-file (mod from 8)) diff --git a/chess-crafty.el b/chess-crafty.el deleted file mode 100644 index d15be54..0000000 --- a/chess-crafty.el +++ /dev/null @@ -1,45 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; Play against the crafty engine -;; -;; $Revision$ - -(require 'chess-process) - -(defgroup chess-crafty nil - "Interface code for playing against crafty. Uses `chess-process'." - :group 'chess) - -(defcustom chess-crafty-command (and (require 'executable) - (executable-find "crafty")) - "The name of the crafty program." - :type 'string - :group 'chess-crafty) - -;;; Code: - -;;;###autoload -(defun chess-crafty (session buffer event &rest args) - (if (not (eq event 'initialize)) - (apply 'chess-process session buffer event args) - (with-current-buffer - (chess-process session buffer event chess-process-triggers - chess-crafty-command) - (process-send-string (get-buffer-process (current-buffer)) - (concat "display nogeneral\n" - "display nochanges\n" - "display noextstats\n" - "display nohashstats\n" - "display nomoves\n" - "display nonodes\n" - "display noply1\n" - "display nostats\n" - "display notime\n" - "display novariation\n" - "alarm off\n" - "ansi off\n")) - (current-buffer)))) - -(provide 'chess-crafty) - -;;; chess-crafty.el ends here diff --git a/chess-display.el b/chess-display.el index 4453d28..d1212b7 100644 --- a/chess-display.el +++ b/chess-display.el @@ -185,8 +185,7 @@ The key bindings available in this mode are: " " (int-to-string (if (> index 1) (/ index 2) (1+ (/ index 2)))) ". " (if color "... ") - (chess-ply-to-algebraic - (chess-game-ply chess-display-game (1- index)))))))) + (chess-game-ply-to-algebraic chess-display-game)))))) (defsubst chess-display-current-p () "Return non-nil if the displayed chessboard reflects the current game. @@ -237,7 +236,7 @@ This means that no editing is being done." "Send the current board configuration to the user." (interactive) (chess-session-event chess-current-session 'setup - (chess-game-create nil chess-display-position))) + (chess-game-create chess-display-position))) (defun chess-display-copy-board () "Send the current board configuration to the user." @@ -283,7 +282,7 @@ This means that no editing is being done." "White" "Black") (1+ (/ chess-display-game-index 2)))))) (chess-session-event chess-current-session 'move - (chess-algebraic-to-ply chess-display-position move))) + (chess-game-algebraic-to-ply chess-display-game move))) (defun chess-display-set-current (dir) "Change the currently displayed board. @@ -346,13 +345,14 @@ to the end or beginning." (char-to-string (downcase last-command-char))))) (unless (and chess-legal-moves (eq chess-display-position chess-legal-moves-pos)) - (setq chess-legal-moves-pos chess-display-position - chess-legal-moves - (sort (mapcar 'chess-ply-to-algebraic - (chess-legal-plies chess-display-position - (chess-pos-side-to-move - chess-display-position))) - 'string-lessp))) + (let ((search-func (chess-game-search-func chess-display-game))) + (setq chess-legal-moves-pos chess-display-position + chess-legal-moves + (sort (mapcar (function + (lambda (ply) + (chess-ply-to-algebraic ply nil search-func))) + (chess-legal-plies chess-display-position search-func)) + 'string-lessp)))) (let ((moves (mapcar (function (lambda (move) @@ -376,9 +376,10 @@ to the end or beginning." (setq moves (delq nil moves)) (cond ((= (length moves) 1) - (chess-session-event chess-current-session 'move - (chess-algebraic-to-ply chess-display-position - (car moves))) + (chess-session-event + chess-current-session 'move + (chess-algebraic-to-ply chess-display-position (car moves) + (chess-game-search-func chess-display-game))) (setq chess-move-string nil chess-legal-moves nil chess-legal-moves-pos nil)) diff --git a/chess-engines.el b/chess-engines.el new file mode 100644 index 0000000..c014972 --- /dev/null +++ b/chess-engines.el @@ -0,0 +1,56 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Play against popular chess engines +;; +;; $Revision$ + +(require 'chess-process) + +(define-chess-engine crafty (&rest args) + (list (list + (concat "\\s-*\\(White\\|Black\\)\\s-*([0-9]+):\\s-+\\(" + chess-algebraic-regexp "\\)\\s-*$") + (function + (lambda (color move) + (if (string= (if (chess-game-side-to-move chess-process-game) + "White" "Black") + color) + (chess-session-event + chess-current-session 'move + (chess-algebraic-to-ply + (chess-game-pos chess-process-game) move))))) + 1 2) + '("Illegal move:\\s-*\\(.*\\)" + (signal 'chess-illegal (match-string 1)))) + (init (concat "display nogeneral\n" + "display nochanges\n" + "display noextstats\n" + "display nohashstats\n" + "display nomoves\n" + "display nonodes\n" + "display noply1\n" + "display nostats\n" + "display notime\n" + "display novariation\n" + "alarm off\n" + "ansi off")) + (shutdown "quit") + (move (chess-game-ply-to-algebraic chess-process-game (car args))) + (pass "go")) + +(define-chess-engine gnuchess (&rest args) + (list (list + (concat "My move is : \\(" chess-algebraic-regexp "\\)") + (function + (lambda (move) + (chess-session-event chess-current-session 'move + (chess-algebraic-to-ply + (chess-game-pos chess-process-game) move)))) + 1) + '("Illegal move:\\s-*\\(.*\\)" + (signal 'chess-illegal (match-string 1)))) + (shutdown "quit") + (move (chess-game-ply-to-algebraic chess-process-game (car args))) + (pass "go")) + +;;; chess-engines.el ends here diff --git a/chess-game.el b/chess-game.el index 44df33d..b4aceb5 100644 --- a/chess-game.el +++ b/chess-game.el @@ -10,15 +10,16 @@ ;; game, and a list of plies representing the main variation. (require 'chess-ply) +(require 'chess-algebraic) (defconst chess-game-default-tags - (list '("Event" . "Computer chess game") - '("Round" . "-") - (cons "Site" (system-name)) - '("White" . "?") - '("Black" . "?") - '("Result" . "*") - '("TimeControl" . "-"))) + `(("Event" . "Computer chess game") + ("Round" . "-") + ("Site" . ,(system-name)) + ("White" . "?") + ("Black" . "?") + ("Result" . "*") + ("TimeControl" . "-"))) (defsubst chess-game-tags (game) "Return the tags alist associated with GAME." @@ -30,11 +31,27 @@ (defsubst chess-game-plies (game) "Return the tags alist associated with GAME." - (cdr game)) + (cddr game)) (defsubst chess-game-set-plies (game plies) "Return the tags alist associated with GAME." - (setcdr game plies)) + (setcdr (cdr game) plies)) + +(defsubst chess-game-validation-func (game) + "Return the tags alist associated with GAME." + (car (cadr game))) + +(defsubst chess-game-set-validation-func (game func) + "Return the tags alist associated with GAME." + (setcar (cadr game) func)) + +(defsubst chess-game-search-func (game) + "Return the tags alist associated with GAME." + (cdr (cadr game))) + +(defsubst chess-game-set-search-func (game func) + "Return the tags alist associated with GAME." + (setcdr (cadr game) func)) (defsubst chess-game-tag (game tag) "Return the value for TAG in GAME." @@ -58,7 +75,7 @@ (defsubst chess-game-index (game) "Return the GAME's current position index." - (length (cdr game))) + (length (chess-game-plies game))) (defsubst chess-game-seq (game) "Return the current GAME sequence." @@ -70,26 +87,38 @@ (defun chess-game-ply (game &optional index) "Return the position related to GAME's INDEX position." (if index - (nth index (cdr game)) - (car (last (cdr game))))) + (nth index (chess-game-plies game)) + (car (last (chess-game-plies game))))) + +(defsubst chess-game-add-ply (game ply) + "Return the position related to GAME's INDEX position." + (nconc (chess-game-plies game) (list ply))) (defun chess-game-pos (game &optional index) "Return the position related to GAME's INDEX position." (car (chess-game-ply game index))) -(defun chess-game-create (&optional tags position) +(defun chess-game-create (&rest keywords) "Create a new chess game object. -If TAGS is non-nil, it is a list of cons cell that define starting -tags to use. If POSITION is non-nil, the game starts at that -position." - (let ((game (cons nil nil))) - (dolist (tag chess-game-default-tags) - (chess-game-set-tag game (car tag) (cdr tag))) - (chess-game-set-tag game "Date" (format-time-string "%Y.%m.%d")) - (dolist (tag tags) - (chess-game-set-tag game (car tag) (cdr tag))) - (setcdr game (list (chess-ply-create - (or position (chess-pos-create))))) +Keywords may be specified to customize the game object. The supported +keywords are: + + :position POS ; set the start position + :search FUNC ; function used to search chess positions + :validate FUNC ; function used to validate chess moves + :tags ALIST" + (let ((game (list (cdr (assq ':tags keywords)) + (cons (or (cdr (assq ':validate keywords)) + chess-standard-validate) + (or (cdr (assq ':search keywords)) + chess-standard-search))))) + (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 (cdr (assq ':position keywords)) + (chess-pos-create)))) game)) (defun chess-game-move (game ply) @@ -99,7 +128,10 @@ The 'changes' of the last ply reflect whether the game is currently in progress (nil), if it is drawn, resigned, mate, etc." (let ((current-ply (chess-game-ply game)) (changes (chess-ply-changes ply))) - (assert (equal (chess-ply-pos current-ply) (chess-ply-pos ply))) + (unless (equal (chess-ply-pos current-ply) + (chess-ply-pos ply)) + (error "Positions do not match")) + (funcall (chess-game-validation-func game) ply) (chess-ply-set-changes current-ply changes) (cond ((or (memq ':draw changes) @@ -109,12 +141,26 @@ progress (nil), if it is drawn, resigned, mate, etc." (chess-game-set-tag game "Result" "1/2-1/2")) ((or (memq ':resign changes) (memq ':checkmate changes)) - (chess-game-set-tag game "Result" - (if (chess-game-side-to-move game) - "0-1" "1-0"))) - (t (nconc (cdr game) - (list (chess-ply-create - (chess-ply-next-pos current-ply)))))))) + (chess-game-set-tag game "Result" (if (chess-game-side-to-move game) + "0-1" "1-0"))) + (t + (chess-game-add-ply game (chess-ply-create + (chess-ply-next-pos current-ply))))))) + +;; A few convenience functions + +(defsubst chess-game-legal-plies (game) + "Return all legal plies from GAME's current position." + (chess-legal-plies (chess-game-pos game) + (chess-game-search-func game))) + +(defsubst chess-game-algebraic-to-ply (game move) + (chess-algebraic-to-ply (chess-game-pos game) move + (chess-game-search-func game))) + +(defsubst chess-game-ply-to-algebraic (game &optional ply long) + (chess-ply-to-algebraic (or ply (chess-game-ply game)) long + (chess-game-search-func game))) (provide 'chess-game) diff --git a/chess-gnuchess.el b/chess-gnuchess.el deleted file mode 100644 index c304a8b..0000000 --- a/chess-gnuchess.el +++ /dev/null @@ -1,38 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; Play against the gnuchess engine -;; -;; $Revision$ - -(require 'chess-process) - -(defgroup chess-gnuchess nil - "Interface code for playing against gnuchess. Uses `chess-process'." - :group 'chess) - -(defcustom chess-gnuchess-command (and (require 'executable) - (executable-find "gnuchess")) - "The name of the gnuchess program." - :type 'string - :group 'chess-gnuchess) - -;;;###autoload -(defun chess-gnuchess (session buffer event &rest args) - (if (not (eq event 'initialize)) - (apply 'chess-process session buffer event args) - (chess-process session buffer event - (list (list - (concat "My move is : \\(" - chess-algebraic-regexp "\\)") - (function - (lambda (move) - (chess-session-event - chess-current-session 'move - (chess-algebraic-to-ply - (chess-game-pos chess-process-game) move)))) 1) - '("Illegal move:" (error "Illegal move"))) - chess-gnuchess-command))) - -(provide 'chess-gnuchess) - -;;; chess-gnuchess.el ends here diff --git a/chess-pgn.el b/chess-pgn.el index 841cccb..36ce3f0 100644 --- a/chess-pgn.el +++ b/chess-pgn.el @@ -18,7 +18,7 @@ ((looking-at chess-algebraic-regexp) (goto-char (match-end 0)) (setq prevpos position) - (let ((ply (chess-algebraic-to-ply position (match-string 0)))) + (let ((ply (chess-game-algebraic-to-ply game (match-string 0)))) (setq position (chess-ply-next-pos ply)) (nconc plies (list ply)))) ((and top-level @@ -64,30 +64,30 @@ (chess-pos-copy chess-starting-position)) t))) game))) -(defun chess-pgn-insert-annotations (index ply) +(defun chess-pgn-insert-annotations (game index ply) (dolist (ann (chess-pos-annotations (chess-ply-pos ply))) (if (stringp ann) (insert (format " {%s}" ann)) (assert (listp ann)) - (chess-pgn-insert-plies index ann)))) + (chess-pgn-insert-plies game index ann)))) -(defun chess-pgn-insert-plies (index plies &optional +(defun chess-pgn-insert-plies (game index plies &optional for-black indented no-annotations) "NYI: Still have to implement INDENTED argument." (while plies (unless for-black (insert (format "%d. %s" index - (chess-ply-to-algebraic (car plies)))) + (chess-game-ply-to-algebraic game (car plies)))) (unless no-annotations - (chess-pgn-insert-annotations index (car plies))) + (chess-pgn-insert-annotations game index (car plies))) (setq plies (cdr plies) index (1+ index))) (when plies (when for-black (insert (format "%d. ..." index)) (setq for-black nil)) - (insert (format " %s" (chess-ply-to-algebraic (car plies)))) + (insert (format " %s" (chess-game-ply-to-algebraic game (car plies)))) (unless no-annotations - (chess-pgn-insert-annotations index (car plies))) + (chess-pgn-insert-annotations game index (car plies))) (setq plies (cdr plies))) (if plies (insert ? )))) @@ -107,7 +107,7 @@ If INDENTED is non-nil, indent the move texts." (insert (format "[%s \"%s\"]\n" (car tag) (cdr tag)))) (insert ?\n) (let ((begin (point))) - (chess-pgn-insert-plies 1 (chess-game-plies game)) + (chess-pgn-insert-plies game 1 (chess-game-plies game)) (insert (or (chess-game-tag game "Result") "*") ?\n) (fill-region begin (point)))) @@ -116,54 +116,54 @@ If INDENTED is non-nil, indent the move texts." ;; PGN-mode for editing and browsing PGN files. ;; -(defvar chess-pgn-mode-map - (let ((map (make-sparse-keymap))) - (define-key map [??] 'describe-mode) - (define-key map [?T] 'text-mode) - (define-key map [return] 'chess-pgn-move) - (define-key map [(control ?m)] 'chess-pgn-move) - map) - "Keymap used by Chess PGN mode.") - -(define-derived-mode chess-pgn-mode text-mode "Chess" - "A mode for editing Chess PGN files.") - -(defun chess-pgn-move () - "Make a move from a PGN buffer." - (interactive) - (let ((end (point)) - coords move) - (save-excursion - (skip-chars-backward "^ ") - (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)))) - -(defun chess-pgn-insert-move (move &optional color sequence) - "Insert an algebraic move description into a PGN buffer. -If move is the symbol `wait', it means reflect that we are now waiting -for the opponent to make his move. If move is the symbol `ready', it -means our opponent is now waiting for us to move our move. Otherwise, -move should be a string representing the algebraic notation for the -move." - (while (= (char-before) ?.) - (delete-backward-char 1)) - (cond - ((eq move 'wait) - (insert "...")) - ((eq move 'ready) t) - (t - (if (= (char-syntax (char-before)) ? ) - (insert move)) - (if color - (move-to-column 11 t) - (insert ?\n (format "%d. " (1+ sequence)))))) - (let ((wind (get-buffer-window (current-buffer)))) - (if wind - (set-window-point wind (point))))) +;; (defvar chess-pgn-mode-map +;; (let ((map (make-sparse-keymap))) +;; (define-key map [??] 'describe-mode) +;; (define-key map [?T] 'text-mode) +;; (define-key map [return] 'chess-pgn-move) +;; (define-key map [(control ?m)] 'chess-pgn-move) +;; map) +;; "Keymap used by Chess PGN mode.") +;; +;; (define-derived-mode chess-pgn-mode text-mode "Chess" +;; "A mode for editing Chess PGN files.") +;; +;; (defun chess-pgn-move () +;; "Make a move from a PGN buffer." +;; (interactive) +;; (let ((end (point)) +;; coords move) +;; (save-excursion +;; (skip-chars-backward "^ ") +;; (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)))) +;; +;; (defun chess-pgn-insert-move (move &optional color sequence) +;; "Insert an algebraic move description into a PGN buffer. +;; If move is the symbol `wait', it means reflect that we are now waiting +;; for the opponent to make his move. If move is the symbol `ready', it +;; means our opponent is now waiting for us to move our move. Otherwise, +;; move should be a string representing the algebraic notation for the +;; move." +;; (while (= (char-before) ?.) +;; (delete-backward-char 1)) +;; (cond +;; ((eq move 'wait) +;; (insert "...")) +;; ((eq move 'ready) t) +;; (t +;; (if (= (char-syntax (char-before)) ? ) +;; (insert move)) +;; (if color +;; (move-to-column 11 t) +;; (insert ?\n (format "%d. " (1+ sequence)))))) +;; (let ((wind (get-buffer-window (current-buffer)))) +;; (if wind +;; (set-window-point wind (point))))) (provide 'chess-pgn) diff --git a/chess-ply.el b/chess-ply.el index 172c154..65c11b7 100644 --- a/chess-ply.el +++ b/chess-ply.el @@ -45,6 +45,7 @@ ;;; Code: (require 'chess-pos) +(require 'chess-standard) (defgroup chess-ply nil "Routines for manipulating chess plies." @@ -69,19 +70,20 @@ (defsubst chess-ply-create (position &rest changes) (cons position changes)) -(defun chess-legal-plies (position color) - "Return a list of all legal plies in POSITION for COLOR." +(defun chess-legal-plies (position &optional search-func) + "Return a list of all legal plies in POSITION." (let (plies) (dotimes (rank 8) (dotimes (file 8) (let* ((to (chess-rf-to-index rank file)) (piece (chess-pos-piece position to))) (when (or (eq piece ? ) - (if color + (if (chess-pos-side-to-move position) (> piece ?a) (< piece ?a))) - (dolist (candidate (funcall (car chess-modules) - nil nil 'search position to t)) + (dolist (candidate (funcall (or search-func + chess-standard-search) + position to t)) (push (chess-ply-create position candidate to) plies)))))) plies)) diff --git a/chess-process.el b/chess-process.el index 729cc8b..21d4cdb 100644 --- a/chess-process.el +++ b/chess-process.el @@ -36,23 +36,7 @@ related to the resulting process.") (make-variable-buffer-local 'chess-process-last-pos) (make-variable-buffer-local 'chess-process-working) -(defvar chess-process-triggers - (list (list - (concat "\\s-*\\(white\\|black\\)\\s-*([0-9]+):\\s-+\\(" - chess-algebraic-regexp "\\)\\s-*$") - (function - (lambda (color move) - (if (if (chess-game-side-to-move chess-process-game) - (string= (downcase color) "white") - (string= (downcase color) "black")) - (chess-session-event - chess-current-session 'move - (chess-algebraic-to-ply - (chess-game-pos chess-process-game) move))))) - 1 2) - '(".*illegal move:\\s-*\\(.*\\)" - (signal 'chess-illegal (match-string 1))) - '(".+?\015" (replace-match ""))) +(defvar chess-process-triggers nil "A list of regexps and the commands that they trigger. The alist should be of the form: @@ -102,25 +86,15 @@ must be handled by modules that derive from this module.") (set-process-filter proc 'chess-process-filter)) buf))) ((eq event 'shutdown) - (when (buffer-live-p buffer) - (ignore-errors - (process-send-string (get-buffer-process buffer) "quit\n")) - (kill-buffer buffer))) + (if (buffer-live-p buffer) + (kill-buffer buffer))) (t (ignore (with-current-buffer buffer - (let (cmdstr) - (cond - ((eq event 'setup) - (setq chess-process-game (car args) - chess-process-last-pos (point-min))) - ((eq event 'move) - (setq cmdstr (concat (chess-ply-to-algebraic (car args)) "\n"))) - ((eq event 'pass) - (setq cmdstr "go\n"))) - (if (and cmdstr (not chess-process-working)) - (process-send-string (get-buffer-process (current-buffer)) - cmdstr)))))))) + (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." @@ -163,6 +137,71 @@ must be handled by modules that derive from this module.") (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 index 6f0dde4..e282223 100644 --- a/chess-session.el +++ b/chess-session.el @@ -44,6 +44,16 @@ (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 bc45d3f..b70c028 100644 --- a/chess-standard.el +++ b/chess-standard.el @@ -23,28 +23,12 @@ ;; $Revision$ -(require 'chess-session) -(require 'chess-pos) -(require 'chess-ply) -(require 'chess-game) - (defgroup chess-standard nil "The rules of standard chess." :group 'chess) ;;; Code: -;;;###autoload -(defun chess-standard (session var event &rest args) - (cond - ((eq event 'move) - (ignore - (chess-standard-validate (car args)) - (chess-game-move (chess-session-data session 'current-game) - (car args)))) - ((eq event 'search) - (apply 'chess-standard-search args)))) - (defun chess-standard-validate (ply) "Validate the given PLY against standard chess rules." (let* ((pos (chess-ply-pos ply)) @@ -84,13 +84,10 @@ a0 243 (defconst chess-version "2.0a7" "The version of the Emacs chess program.") (defcustom chess-modules - (list 'chess-standard 'chess-crafty + (list 'chess-crafty (if (display-graphic-p) 'chess-images 'chess-ascii)) - "Default module set to be used when starting a chess session. -Any rules modules, if they are being used, must appear first in this -list! This usually means `chess-standard' must be the very first -entry." + 'chess-images 'chess-ics1) :type (list 'radio (apropos-internal "\\`chess-[^-]+\\'" 'functionp)) :type 'sexp :group 'chess) |
