diff options
| author | John Wiegley <johnw@newartisans.com> | 2002-04-18 18:30:19 +0000 |
|---|---|---|
| committer | John Wiegley <johnw@newartisans.com> | 2002-04-18 18:30:19 +0000 |
| commit | 563cf2037068f67f6786172b029363aaa7d52776 (patch) | |
| tree | 549c69928ccc019093fed062f6999462fbb431db | |
| parent | 2b0db13d4cdc3aaadd7dd458c1097c668577a072 (diff) | |
Many efficiency improvements and bug fixes.
| -rw-r--r-- | chess-algebraic.el | 122 | ||||
| -rw-r--r-- | chess-common.el | 4 | ||||
| -rw-r--r-- | chess-crafty.el | 1 | ||||
| -rw-r--r-- | chess-display.el | 110 | ||||
| -rw-r--r-- | chess-engine.el | 35 | ||||
| -rw-r--r-- | chess-game.el | 14 | ||||
| -rw-r--r-- | chess-gnuchess.el | 1 | ||||
| -rw-r--r-- | chess-ics.el | 3 | ||||
| -rw-r--r-- | chess-input.el | 2 | ||||
| -rw-r--r-- | chess-module.el | 6 | ||||
| -rw-r--r-- | chess-network.el | 2 | ||||
| -rw-r--r-- | chess-pgn.el | 20 | ||||
| -rw-r--r-- | chess-phalanx.el | 1 | ||||
| -rw-r--r-- | chess-plain.el | 4 | ||||
| -rw-r--r-- | chess-ply.el | 16 | ||||
| -rw-r--r-- | chess-pos.el | 41 | ||||
| -rw-r--r-- | chess-var.el | 7 | ||||
| -rw-r--r-- | chess.el | 87 |
18 files changed, 317 insertions, 159 deletions
diff --git a/chess-algebraic.el b/chess-algebraic.el index 0bdcac8..7cdb253 100644 --- a/chess-algebraic.el +++ b/chess-algebraic.el @@ -112,66 +112,80 @@ This regexp handles both long and short form.") (if promotion (nconc changes (list :promote (aref promotion 0)))))) - (if (and trust mate) - (nconc changes (list (if (equal mate "#") :checkmate :check)))) + (when trust + (if mate + (nconc changes (list (if (equal mate "#") :checkmate :check)))) + (nconc changes (list :san move))) + (assert changes) (or ply (apply 'chess-ply-create position trust changes))))) +(defsubst chess-ply--move-text (ply long) + (or (and (chess-ply-keyword ply :castle) "O-O") + (and (chess-ply-keyword ply :long-castle) "O-O-O") + (let* ((pos (chess-ply-pos ply)) + (from (chess-ply-source ply)) + (to (chess-ply-target ply)) + (from-piece (chess-pos-piece pos from)) + (color (chess-pos-side-to-move pos)) + (rank 0) (file 0) + (from-rank (/ from 8)) + (from-file (mod from 8)) + (differentiator (chess-ply-keyword ply :which))) + (unless differentiator + (let ((candidates (chess-search-position pos to + from-piece))) + (when (> (length candidates) 1) + (dolist (candidate candidates) + (if (= (/ candidate 8) from-rank) + (setq rank (1+ rank))) + (if (= (mod candidate 8) from-file) + (setq file (1+ file)))) + (cond + ((= file 1) + (setq differentiator (+ from-file ?a))) + ((= rank 1) + (setq differentiator (+ (- 7 from-rank) ?1))) + (t (chess-error 'could-not-diff))) + (chess-ply-set-keyword ply :which differentiator)))) + (concat + (unless (= (upcase from-piece) ?P) + (char-to-string (upcase from-piece))) + (if long + (chess-index-to-coord from) + (if differentiator + (prog1 + (char-to-string differentiator) + (chess-ply-changes ply)) + (if (and (not long) (= (upcase from-piece) ?P) + (/= (chess-index-file from) + (chess-index-file to))) + (char-to-string (+ (chess-index-file from) ?a))))) + (if (or (/= ? (chess-pos-piece pos to)) + (chess-ply-keyword ply :en-passant)) + "x" (if long "-")) + (chess-index-to-coord to) + (let ((promote (chess-ply-keyword ply :promote))) + (if promote + (concat "=" (char-to-string + (upcase (cadr promote)))))) + (if (chess-ply-keyword ply :check) "+" + (if (chess-ply-keyword ply :checkmate) "#")))))) + (defun chess-ply-to-algebraic (ply &optional long) "Convert the given PLY to algebraic notation. If LONG is non-nil, render the move into long notation." - (if (let ((source (chess-ply-source ply))) - (or (null source) (symbolp source))) - "" - (or (and (chess-ply-keyword ply :castle) "O-O") - (and (chess-ply-keyword ply :long-castle) "O-O-O") - (let* ((pos (chess-ply-pos ply)) - (from (chess-ply-source ply)) - (to (chess-ply-target ply)) - (from-piece (chess-pos-piece pos from)) - (color (chess-pos-side-to-move pos)) - (rank 0) (file 0) - (from-rank (/ from 8)) - (from-file (mod from 8)) - (differentiator (chess-ply-keyword ply :which))) - (unless differentiator - (let ((candidates (chess-search-position pos to from-piece))) - (when (> (length candidates) 1) - (dolist (candidate candidates) - (if (= (/ candidate 8) from-rank) - (setq rank (1+ rank))) - (if (= (mod candidate 8) from-file) - (setq file (1+ file)))) - (cond - ((= file 1) - (setq differentiator (+ from-file ?a))) - ((= rank 1) - (setq differentiator (+ (- 7 from-rank) ?1))) - (t (chess-error 'could-not-diff))) - (chess-ply-set-keyword ply :which differentiator)))) - (concat - (unless (= (upcase from-piece) ?P) - (char-to-string (upcase from-piece))) - (if long - (chess-index-to-coord from) - (if differentiator - (prog1 - (char-to-string differentiator) - (chess-ply-changes ply)) - (if (and (not long) (= (upcase from-piece) ?P) - (/= (chess-index-file from) - (chess-index-file to))) - (char-to-string (+ (chess-index-file from) ?a))))) - (if (or (/= ? (chess-pos-piece pos to)) - (chess-ply-keyword ply :en-passant)) - "x" (if long "-")) - (chess-index-to-coord to) - (let ((promote (chess-ply-keyword ply :promote))) - (if promote - (concat "=" (char-to-string - (upcase (cadr promote)))))) - (if (chess-ply-keyword ply :check) "+" - (if (chess-ply-keyword ply :checkmate) "#"))))))) + (let (source san) + (cond + ((or (null (setq source (chess-ply-source ply))) + (symbolp source)) + "") + ((setq san (chess-ply-keyword ply :san)) + san) + (t + (let ((move (chess-ply--move-text ply long))) + (chess-ply-set-keyword ply :san move) + move))))) (provide 'chess-algebraic) diff --git a/chess-common.el b/chess-common.el index 347bbd6..d568dad 100644 --- a/chess-common.el +++ b/chess-common.el @@ -8,7 +8,9 @@ (require 'chess-engine) +(defvar chess-common-engine-name nil) (defvar chess-common-temp-files nil) +(make-variable-buffer-local 'chess-common-engine-name) (make-variable-buffer-local 'chess-common-temp-files) (defmacro chess-with-temp-file (&rest body) @@ -76,6 +78,8 @@ (chess-game-undo game (car args)))) ((eq event 'move) + (if (= 1 (chess-game-index game)) + (chess-game-set-tag game "Black" chess-engine-opponent-name)) (chess-engine-send nil (concat (chess-ply-to-algebraic (car args)) "\n")) (if (chess-game-over-p game) (chess-game-set-data game 'active nil))))) diff --git a/chess-crafty.el b/chess-crafty.el index 22f67ca..fa19b4d 100644 --- a/chess-crafty.el +++ b/chess-crafty.el @@ -61,6 +61,7 @@ "display novariation\n" "alarm off\n" "ansi off\n")) + (setq chess-engine-opponent-name "Crafty") t))) ((eq event 'setup-pos) diff --git a/chess-display.el b/chess-display.el index ff2da04..c67c81f 100644 --- a/chess-display.el +++ b/chess-display.el @@ -7,7 +7,6 @@ (require 'chess-var) (require 'chess-algebraic) (require 'chess-fen) -(require 'chess-mouse) (require 'chess-input) (defgroup chess-display nil @@ -35,14 +34,20 @@ (defcustom chess-display-mode-line-format '(" " chess-display-side-to-move " " - chess-display-move-text + chess-display-move-text " " (:eval (let ((white (chess-game-data chess-module-game 'white-remaining)) (black (chess-game-data chess-module-game 'black-remaining))) (if (and white black) - (format " W %02d:%02d B %02d:%02d" + (format "W %02d:%02d B %02d:%02d " (/ (floor white) 60) (% (abs (floor white)) 60) - (/ (floor black) 60) (% (abs (floor black)) 60)))))) + (/ (floor black) 60) (% (abs (floor black)) 60))))) + "(" (:eval (chess-game-tag chess-module-game "White")) "-" + (:eval (chess-game-tag chess-module-game "Black")) ", " + (:eval (chess-game-tag chess-module-game "Site")) + (:eval (let ((date (chess-game-tag chess-module-game "Date"))) + (and (string-match "\\`\\([0-9]\\{4\\}\\)" date) + (concat " " (match-string 1 date))))) ")") "The format of a chess display's modeline. See `mode-line-format' for syntax details." :type 'sexp @@ -128,7 +133,7 @@ See `mode-line-format' for syntax details." (chess-display-set-index* nil 1) (chess-game-set-plies chess-module-game (list ply (chess-ply-create* - (chess-ply-next-pos ply) t))))) + (chess-ply-next-pos ply)))))) (defun chess-display-ply (display) (chess-with-current-buffer display @@ -176,8 +181,10 @@ also view the same game." (if (= index 0) (chess-string 'mode-start) (concat (int-to-string (if (> index 1) - (/ index 2) - (1+ (/ index 2)))) + (if (= (mod index 2) 0) + (/ index 2) + (1+ (/ index 2))) + 1)) ". " (and (= 0 (mod index 2)) "... ") (chess-ply-to-algebraic (chess-game-ply chess-module-game (1- index))))) @@ -265,6 +272,9 @@ If only START is given, it must be in algebraic move notation." ;; game, or alter the game, just as SCID allows (if (= chess-display-index (chess-game-index chess-module-game)) (let ((chess-display-handling-event t)) + (if (= chess-display-index 0) + (chess-game-set-tag chess-module-game "White" + chess-full-name)) (chess-display-paint-move nil ply) (chess-game-move chess-module-game ply)) (error "What to do here?? NYI")))) @@ -452,6 +462,8 @@ See `chess-display-type' for the different kinds of displays." (define-key map [(control ?c) (control ?t)] 'chess-display-undo) (define-key map [?X] 'chess-display-quit) + (define-key map [(control ?r)] 'chess-display-search-backward) + (define-key map [(control ?s)] 'chess-display-search-forward) (define-key map [(control ?y)] 'chess-display-yank-board) (dolist (key '(?a ?b ?c ?d ?e ?f ?g ?h @@ -564,6 +576,88 @@ Basically, it means we are playing, not editing or reviewing." (with-current-buffer display (chess-display-set-from-fen (buffer-string)))))))) +(defvar chess-display-search-map + (let ((map (copy-keymap minibuffer-local-map))) + (dolist (key '(?a ?b ?c ?d ?e ?f ?g ?h + ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 + ?r ?n ?b ?q ?k + ?R ?N ?B ?Q ?K + ?o ?O ?x)) + (define-key map (vector key) 'chess-display-search-key)) + (define-key map [backspace] 'chess-display-search-delete) + (define-key map [delete] 'chess-display-search-delete) + (define-key map [(control ?h)] 'chess-display-search-delete) + (define-key map [(control ?r)] 'chess-display-search-again) + (define-key map [(control ?s)] 'chess-display-search-again) + map)) + +(defvar chess-display-search-direction nil) +(defvar chess-current-display nil) +(defvar chess-display-previous-index nil) + +(make-variable-buffer-local 'chess-display-previous-index) + +(chess-message-catalog 'english + '((san-not-found . "Could not find a matching move"))) + +(defun chess-display-search (&optional reset again) + (interactive) + (let ((str (concat "\\`" (minibuffer-contents))) + limit index) + (with-current-buffer chess-current-display + (setq index (if reset + chess-display-previous-index + chess-display-index)) + (if again + (setq index (if chess-display-search-direction + (1+ index) + (- index 2)))) + (catch 'found + (while (if chess-display-search-direction + (< index (or limit + (setq limit + (chess-game-index chess-module-game)))) + (>= index 0)) + (let* ((ply (chess-game-ply chess-module-game index)) + (san (chess-ply-keyword ply :san)) + (case-fold-search t)) + (when (and san (string-match str san)) + (chess-display-set-index nil (1+ index)) + (throw 'found t))) + (setq index (funcall (if chess-display-search-direction '1+ '1-) + index))) + (chess-error 'san-not-found))))) + +(defun chess-display-search-again () + (interactive) + (debug) + (chess-display-search nil t)) + +(defun chess-display-search-key () + (interactive) + (call-interactively 'self-insert-command) + (chess-display-search)) + +(defun chess-display-search-delete () + (interactive) + (call-interactively 'delete-backward-char) + (chess-display-search t)) + +(defun chess-display-search-backward (&optional direction) + (interactive) + (setq chess-display-previous-index chess-display-index) + (condition-case err + (let ((chess-display-search-direction direction) + (chess-current-display (current-buffer))) + (read-from-minibuffer "Find algebraic move: " nil + chess-display-search-map)) + (quit + (chess-display-set-index nil chess-display-previous-index)))) + +(defun chess-display-search-forward () + (interactive) + (chess-display-search-backward t)) + (defun chess-display-set-piece () "Set the piece under point to command character, or space for clear." (interactive) @@ -842,7 +936,7 @@ Clicking once on a piece selects it; then click on the target location." (throw 'message (chess-string 'move-not-legal))) (chess-display-move nil ply (car last-sel) (point)))) (setq chess-display-last-selected nil)) - (chess-display-assert-can-move position) + (chess-assert-can-move position) (let ((piece (chess-pos-piece position coord))) (cond ((eq piece ? ) diff --git a/chess-engine.el b/chess-engine.el index ebce110..050b29d 100644 --- a/chess-engine.el +++ b/chess-engine.el @@ -19,12 +19,14 @@ (defvar chess-engine-current-marker nil) (defvar chess-engine-pending-offer nil) (defvar chess-engine-pending-arg nil) +(defvar chess-engine-opponent-name nil) (make-variable-buffer-local 'chess-engine-regexp-alist) (make-variable-buffer-local 'chess-engine-response-handler) (make-variable-buffer-local 'chess-engine-current-marker) (make-variable-buffer-local 'chess-engine-pending-offer) (make-variable-buffer-local 'chess-engine-pending-arg) +(make-variable-buffer-local 'chess-engine-opponent-name) (defvar chess-engine-process nil) (defvar chess-engine-last-pos nil) @@ -97,6 +99,8 @@ (when (and (not chess-engine-inhibit-auto-pass) (chess-game-data game 'my-color) (= (chess-game-index game) 0)) + (chess-game-set-tag game "White" chess-engine-opponent-name) + (chess-game-set-tag game "Black" chess-full-name) (chess-message 'now-black) (chess-game-run-hooks game 'pass) ;; if no one else flipped my-color, we'll do it @@ -115,15 +119,16 @@ ((eq event 'match) (if (chess-game-data game 'active) (chess-engine-command nil 'busy) - (if (y-or-n-p - (if (and (car args) (> (length (car args)) 0)) - (chess-string 'want-to-play (car args)) - (chess-string 'want-to-play-a))) - (progn - (let ((chess-engine-handling-event t)) - (chess-engine-set-position nil)) - (chess-engine-command nil 'accept)) - (chess-engine-command nil 'decline))) + (let ((name (and (> (length (car args)) 0) (car args)))) + (if (y-or-n-p (if name + (chess-string 'want-to-play (car args)) + (chess-string 'want-to-play-a))) + (progn + (setq chess-engine-opponent-name (or name "Anonymous")) + (let ((chess-engine-handling-event t)) + (chess-engine-set-position nil)) + (chess-engine-command nil 'accept)) + (chess-engine-command nil 'decline)))) t) ((eq event 'setup-pos) @@ -191,11 +196,13 @@ (when chess-engine-pending-offer (if (eq chess-engine-pending-offer 'match) (unless (chess-game-data game 'active) - (if (and (car args) (> (length (car args)) 0)) - (chess-message 'opp-ready (car args)) - (chess-message 'opp-ready-a)) - (let ((chess-engine-handling-event t)) - (chess-engine-set-position nil))) + (let ((name (and (> (length (car args)) 0) (car args)))) + (if name + (chess-message 'opp-ready (car args)) + (chess-message 'opp-ready-a)) + (setq chess-engine-opponent-name (or name "Anonymous")) + (let ((chess-engine-handling-event t)) + (chess-engine-set-position nil)))) (let ((chess-engine-handling-event t)) (cond ((eq chess-engine-pending-offer 'draw) diff --git a/chess-game.el b/chess-game.el index 43a62e5..b28d7f9 100644 --- a/chess-game.el +++ b/chess-game.el @@ -158,8 +158,8 @@ This conveys the status of the game at the given index." "Return the current GAME sequence." (let ((index (chess-game-index game))) (if (> index 1) - (/ index 2) - (1+ (/ index 2))))) + (1+ (/ index 2)) + 1))) (defsubst chess-game-side-to-move (game) (chess-pos-side-to-move (chess-game-pos game))) @@ -216,8 +216,7 @@ TAGS is the starting set of game tags (which can always be changed later using the various tag-related methods)." (let ((game (list nil tags nil (list (chess-ply-create* (or position - (chess-pos-create)) - (null position)))))) + chess-starting-position)))))) (dolist (tag (cons (cons "Date" (format-time-string "%Y.%m.%d")) chess-game-default-tags)) (unless (chess-game-tag game (car tag)) @@ -236,10 +235,13 @@ progress (nil), if it is drawn, resigned, mate, etc." (if (chess-ply-final-p current-ply) (chess-error 'add-to-completed)) - (assert (equal position (chess-ply-pos current-ply))) + (assert current-ply) + (assert (and position (eq position (chess-ply-pos current-ply)))) + (assert changes) + (chess-ply-set-changes current-ply changes) (chess-game-add-ply game (chess-ply-create* - (chess-ply-next-pos current-ply) t)) + (chess-ply-next-pos current-ply))) (let ((long (> (length changes) 2))) (cond diff --git a/chess-gnuchess.el b/chess-gnuchess.el index 9e54642..759dab9 100644 --- a/chess-gnuchess.el +++ b/chess-gnuchess.el @@ -45,6 +45,7 @@ (when (and (processp proc) (eq (process-status proc) 'run)) (process-send-string proc "nopost\n") + (setq chess-engine-opponent-name "Crafty") t))) ((eq event 'setup-pos) diff --git a/chess-ics.el b/chess-ics.el index 9f3fd4e..4cdd42c 100644 --- a/chess-ics.el +++ b/chess-ics.el @@ -236,6 +236,9 @@ who is black." (add-hook 'comint-output-filter-functions 'chess-ics-filter t t) + (setq comint-prompt-regexp "^[^%\n]*% *" + comint-scroll-show-maximum-output t) + (let ((proc (get-buffer-process (current-buffer)))) (if (nth 2 server) (progn diff --git a/chess-input.el b/chess-input.el index 9a3a28a..d72281f 100644 --- a/chess-input.el +++ b/chess-input.el @@ -68,7 +68,7 @@ (let* ((position (chess-display-position nil)) (color (chess-pos-side-to-move position)) char) - (chess-display-assert-can-move position) + (chess-assert-can-move position) (unless (memq last-command '(chess-keyboard-shortcut chess-keyboard-shortcut-delete)) (setq chess-move-string nil)) diff --git a/chess-module.el b/chess-module.el index 9494af9..59f51e6 100644 --- a/chess-module.el +++ b/chess-module.el @@ -26,9 +26,9 @@ (defun chess-module-create (derived game &optional buffer-name &rest ctor-args) (let* ((name (symbol-name derived)) - (handler (intern-soft (concat name "-handler"))) - buffer) - (unless handler + handler buffer) + (unless (and (require derived nil t) + (setq handler (intern-soft (concat name "-handler")))) (chess-error 'no-such-module name)) (with-current-buffer (generate-new-buffer (or buffer-name (format " *%s*" name))) diff --git a/chess-network.el b/chess-network.el index 05df3dc..2cec4ec 100644 --- a/chess-network.el +++ b/chess-network.el @@ -151,6 +151,8 @@ (chess-engine-send nil "illegal\n")) ((eq event 'move) + (if (= 1 (chess-game-index game)) + (chess-game-set-tag game "Black" chess-engine-opponent-name)) (chess-engine-send nil (concat (chess-ply-to-algebraic (car args)) "\n")) (if (chess-game-over-p game) (chess-game-set-data game 'active nil)))))) diff --git a/chess-pgn.el b/chess-pgn.el index 41abf86..672244b 100644 --- a/chess-pgn.el +++ b/chess-pgn.el @@ -38,7 +38,7 @@ (chess-game-set-tag game "Result" (match-string-no-properties 0)) (unless (eq t (car (last plies))) (nconc plies (list (chess-ply-create* - (chess-ply-next-pos (car (last plies))) t)))) + (chess-ply-next-pos (car (last plies))))))) (throw 'done t)) ((looking-at "{") @@ -52,7 +52,7 @@ (forward-char) (skip-chars-forward " \t\n") (chess-pos-add-annotation - prevpos (chess-pgn-read-plies game (chess-pos-copy prevpos)))) + prevpos (chess-pgn-read-plies game prevpos))) ((and (not top-level) (looking-at ")")) @@ -61,7 +61,7 @@ (t (nconc plies (list (chess-ply-create* - (chess-ply-next-pos (car (last plies))) t))) + (chess-ply-next-pos (car (last plies)))))) (throw 'done t))) (skip-chars-forward " \t\n"))) (cdr plies))) @@ -84,16 +84,14 @@ (chess-game-set-tag game (match-string-no-properties 1) (read (match-string-no-properties 2))) (goto-char (match-end 0))) - (let ((fen (chess-game-tag game "FEN"))) + (let* ((fen (chess-game-tag game "FEN")) + (position (if fen + (chess-fen-to-pos fen) + chess-starting-position))) (chess-game-set-plies - game (or (chess-pgn-read-plies - game (if fen - (chess-fen-to-pos fen) - (chess-pos-copy chess-starting-position)) t) + game (or (chess-pgn-read-plies game position t) ;; set the starting position to the FEN string - (list (chess-ply-create* (if fen - (chess-fen-to-pos fen) - chess-starting-position) fen))))) + (list (chess-ply-create* position))))) game))) (defun chess-pgn-insert-annotations (game index ply) diff --git a/chess-phalanx.el b/chess-phalanx.el index 08d851f..37a7331 100644 --- a/chess-phalanx.el +++ b/chess-phalanx.el @@ -35,6 +35,7 @@ (when (and (processp proc) (eq (process-status proc) 'run)) (process-send-string proc "nopost\n") + (setq chess-engine-opponent-name "Phalanx") t))) (t diff --git a/chess-plain.el b/chess-plain.el index 6041dba..5f1ab4b 100644 --- a/chess-plain.el +++ b/chess-plain.el @@ -131,8 +131,8 @@ modify `chess-plain-piece-chars' to avoid real confusion.)" (t pchar))) (p (char-to-string piece))) (add-text-properties 0 1 (list 'face (if (> piece ?a) - 'chess-ics1-black-face - 'chess-ics1-white-face)) p) + 'chess-plain-black-face + 'chess-plain-white-face)) p) p)))) (defsubst chess-plain-draw-square (pos piece index) diff --git a/chess-ply.el b/chess-ply.el index 27154bc..f3cd865 100644 --- a/chess-ply.el +++ b/chess-ply.el @@ -122,16 +122,16 @@ :target king-target)) (list king king-target rook (chess-rf-to-index (if color 7 0) (if long 3 5)) - (if long :long-castle :castle))))) + (if long :long-castle :castle)) + (assert (not "Could not determine castling manuever"))))) (chess-message-catalog 'english '((pawn-promote-query . "Promote pawn to queen/rook/knight/bishop? "))) (defvar chess-ply-checking-mate nil) -(defsubst chess-ply-create* (position &optional direct) - (list (if direct position - (chess-pos-copy position)))) +(defsubst chess-ply-create* (position) + (list position)) (defun chess-ply-create (position &optional valid-p &rest changes) "Create a ply from the given POSITION by applying the suppiled CHANGES. @@ -141,7 +141,7 @@ also extend castling, and will prompt for a promotion piece. Note: Do not pass in the rook move if CHANGES represents a castling maneuver." - (let* ((ply (cons (chess-pos-copy position) changes)) + (let* ((ply (cons position changes)) (color (chess-pos-side-to-move position)) piece) (if (or (null changes) (symbolp (car changes))) @@ -200,6 +200,7 @@ maneuver." (memq :checkmate changes) (memq :stalemate changes)) (let* ((chess-ply-checking-mate t) + ;; jww (2002-04-17): this is a memory waste? (next-pos (chess-ply-next-pos ply)) (next-color (not color)) (king (chess-pos-king-index next-pos next-color)) @@ -265,7 +266,10 @@ KEYWORDS allowed are: :target <specific target index> These will constrain the plies generated to those matching the above -criteria." +criteria. + +NOTE: All of the returned plies will reference the same copy of the +position object passed in." (cond ((null keywords) (let ((plies (list t))) diff --git a/chess-pos.el b/chess-pos.el index d016eef..5099a17 100644 --- a/chess-pos.el +++ b/chess-pos.el @@ -77,6 +77,9 @@ "Routines for manipulating chess positions." :group 'chess) +(defvar chess-pos-white-always-on-move nil) +(make-variable-buffer-local 'chess-pos-white-always-on-move) + (defconst chess-starting-position [;; the eight ranks and files of the chess position ?r ?n ?b ?q ?k ?b ?n ?r @@ -107,7 +110,9 @@ (aref position index)) (defsubst chess-pos-king-index (position color) - (aref position (if color 72 73))) + (or (aref position (if color 72 73)) + (aset position (if color 72 73) + (chess-pos-search position (if color ?K ?k))))) (defsubst chess-pos-set-king-pos (position color index) (aset position (if color 72 73) index)) @@ -124,15 +129,15 @@ "Return whether the king can castle on SIDE. SIDE must be either ?q or ?k (case determines color)." (aref position (+ 65 (if (< side ?a) - (if (= side ?K) 0 1) - (if (= side ?k) 2 3))))) + (if (= side ?K) 0 1) + (if (= side ?k) 2 3))))) (defsubst chess-pos-set-can-castle (position side value) "Set whether the king can castle on SIDE. SIDE must be either ?q or ?k (case determines color)." (aset position (+ 65 (if (< side ?a) - (if (= side ?K) 0 1) - (if (= side ?k) 2 3))) value)) + (if (= side ?K) 0 1) + (if (= side ?k) 2 3))) value)) (defsubst chess-pos-en-passant (position) "Return index of pawn that can be captured en passant, or nil." @@ -316,12 +321,12 @@ trying to move a blank square." ((= piece ?r) (let ((king (chess-pos-king-index position color))) - (if (and (chess-pos-can-castle position (if color ?K ?k)) + (if (and (chess-pos-can-castle position (if color ?Q ?q)) (< (chess-index-file (car changes)) king)) - (chess-pos-set-can-castle position (if color ?K ?k) nil) - (if (and (chess-pos-can-castle position (if color ?Q ?q)) + (chess-pos-set-can-castle position (if color ?Q ?q) nil) + (if (and (chess-pos-can-castle position (if color ?K ?k)) (> (chess-index-file (car changes)) king)) - (chess-pos-set-can-castle position (if color ?Q ?q) nil))))) + (chess-pos-set-can-castle position (if color ?K ?k) nil))))) ((and (= piece ?p) (> (abs (- (chess-index-rank (cadr changes)) @@ -329,7 +334,8 @@ trying to move a blank square." (chess-pos-set-en-passant position (cadr changes)))))) ;; toggle the side whose move it is - (chess-pos-set-side-to-move position (not color)) + (unless chess-pos-white-always-on-move + (chess-pos-set-side-to-move position (not color))) ;; promote the piece if we were meant to (let ((new-piece (cadr (memq :promote changes)))) @@ -535,28 +541,27 @@ Note: All of the pieces specified by CANDIDATES must be of the same type." (let ((cand candidates) (piece (chess-pos-piece position (car candidates))) - (pos (chess-pos-copy position)) last-cand king-pos) (while cand ;; determine the resulting position - (chess-pos-set-piece pos (car cand) ? ) - (chess-pos-set-piece pos target piece) + (chess-pos-set-piece position (car cand) ? ) + (chess-pos-set-piece position target piece) ;; find the king (only once if the king isn't moving) (if (or (null king-pos) (memq piece '(?K ?k))) - (setq king-pos (chess-pos-king-index pos color))) + (setq king-pos (chess-pos-king-index position color))) ;; can anybody from the opposite side reach him? if so, ;; drop the candidate (if (catch 'in-check - (chess-search-position pos king-pos (not color) t)) + (chess-search-position position king-pos (not color) t)) (if last-cand (setcdr last-cand (cdr cand)) (setq candidates (cdr candidates))) (setq last-cand cand)) ;; return the position to its original state - (when (cdr cand) - (chess-pos-set-piece pos target ? ) - (chess-pos-set-piece pos (car cand) piece)) + (chess-pos-set-piece position target ? ) + (chess-pos-set-piece position (car cand) piece) + ;; try the next candidate (setq cand (cdr cand))) candidates)) diff --git a/chess-var.el b/chess-var.el index 95586cb..851d06d 100644 --- a/chess-var.el +++ b/chess-var.el @@ -47,8 +47,7 @@ Optionally use the given starting POSITION. SEARCH-FUNC specifies the function used to test the legality of moves. TAGS is the starting set of var tags (which can always be changed later using the various tag-related methods)." - (list (chess-ply-create* (or position (chess-pos-create)) - (null position)))) + (list (chess-ply-create* (or position chess-starting-position)))) (defun chess-var-move (var ply) "Make a move in the current VAR, from FROM to TO. @@ -60,10 +59,10 @@ progress (nil), if it is drawn, resigned, mate, etc." (position (chess-ply-pos ply))) (if (chess-ply-final-p current-ply) (chess-error 'add-to-completed)) - (assert (equal position (chess-ply-pos current-ply))) + (assert (eq position (chess-ply-pos current-ply))) (chess-ply-set-changes current-ply changes) (chess-var-add-ply var (chess-ply-create* - (chess-ply-next-pos current-ply) t)))) + (chess-ply-next-pos current-ply))))) (provide 'chess-var) @@ -76,6 +76,7 @@ (require 'chess-game) (require 'chess-display) (require 'chess-engine) +(require 'chess-random) (require 'chess-database) (require 'chess-file) @@ -118,29 +119,24 @@ available." :group 'chess) (defun chess--create-display (module game my-color disable-popup) - (if (require module nil t) - (let ((display (chess-display-create game module my-color))) - (when display - (chess-game-set-data game 'my-color my-color) - (if disable-popup - (chess-display-disable-popup display)) - display)))) - -(defun chess--create-module (module game) - (and (require module nil t) - (chess-module-create module game))) + (when (require module nil t) + (let ((display (chess-display-create game module my-color))) + (when display + (chess-game-set-data game 'my-color my-color) + (if disable-popup + (chess-display-disable-popup display)) + display)))) (defun chess--create-engine (module game response-handler ctor-args) - (if (require module nil t) - (let ((engine (apply 'chess-engine-create module game - response-handler ctor-args))) - (when engine - ;; for the sake of engines which are ready to play now, and - ;; which don't need connect/accept negotiation (most - ;; computerized engines fall into this category), we need to - ;; let them know we're ready to begin - (chess-engine-command engine 'ready) - engine)))) + (let ((engine (apply 'chess-engine-create module game + response-handler ctor-args))) + (when engine + ;; for the sake of engines which are ready to play now, and + ;; which don't need connect/accept negotiation (most + ;; computerized engines fall into this category), we need to + ;; let them know we're ready to begin + (chess-engine-command engine 'ready) + engine))) (defun chess-create-modules (module-list create-func &rest args) (let (objects) @@ -159,6 +155,9 @@ available." (setq module (cdr module))))))) (nreverse objects))) +(chess-message-catalog 'english + '((no-engines-found . "Could not find any chess engines to play against; install gnuchess!"))) + ;;;###autoload (defun chess (&optional engine disable-popup engine-response-handler &rest engine-ctor-args) @@ -190,7 +189,7 @@ available." (chess-display-popup (car objects))) (nconc objects (chess-create-modules chess-default-modules - 'chess--create-module game)) + 'chess-module-create game)) (push (car (chess-create-modules (list (or engine chess-default-engine)) 'chess--create-engine game @@ -198,6 +197,9 @@ available." engine-ctor-args)) objects) + (unless (car objects) + (chess-message 'no-engines-found)) + objects)) (defalias 'chess-session 'chess) @@ -225,13 +227,17 @@ available." (setq display (chess-create-display)) (chess-display-set-game display game)))) +(defvar chess-puzzle-indices nil) +(defvar chess-puzzle-position nil) +(make-variable-buffer-local 'chess-puzzle-indices) +(make-variable-buffer-local 'chess-puzzle-position) + ;;;###autoload (defun chess-puzzle (file &optional index) "Pick a random puzzle from FILE, and solve it against the default engine. The spacebar in the display buffer is bound to `chess-puzzle-next', making it easy to go on to the next puzzle once you've solved one." (interactive "fRead chess puzzles from: ") - (random t) (let* ((database (chess-database-open 'chess-file file)) (objects (and database (chess-session))) (display (cadr objects))) @@ -242,22 +248,39 @@ making it easy to go on to the next puzzle once you've solved one." 'chess-database-event-handler database) (chess-game-set-data (chess-display-game nil) 'database database) (define-key (current-local-map) [? ] 'chess-puzzle-next) + (let ((count (chess-database-count database))) + (setq chess-puzzle-indices (make-vector count nil)) + (dotimes (i count) + (aset chess-puzzle-indices i i)) + (random t) + (shuffle-vector chess-puzzle-indices) + (setq chess-puzzle-position 0)) (chess-puzzle-next))))) +(chess-message-catalog 'english + '((bad-game-read . "Error reading game at position %d") + (end-of-puzzles . "There are no more puzzles in this collection"))) + (defun chess-puzzle-next () "Play the next puzzle in the collection, selected randomly." (interactive) (let* ((game (chess-display-game nil)) (database (chess-game-data game 'database)) - (index (random (chess-database-count database))) - (next-game (chess-database-read database index))) - (if (null next-game) - (error "Error reading game at position %d" index) - (chess-display-set-game nil next-game 0) - (chess-game-set-data game 'my-color - (chess-pos-side-to-move (chess-game-pos game))) - (dolist (key '(database database-index database-count)) - (chess-game-set-data game key (chess-game-data next-game key)))))) + (index chess-puzzle-position) + next-game) + (if (= index (length chess-puzzle-indices)) + (chess-message 'end-of-puzzles) + (setq chess-puzzle-position (1+ chess-puzzle-position)) + (if (null (setq next-game + (chess-database-read database + (aref chess-puzzle-indices index)))) + (chess-error 'bag-game-read + (aref chess-puzzle-indices index)) + (chess-display-set-game nil next-game 0) + (chess-game-set-data game 'my-color + (chess-pos-side-to-move (chess-game-pos game))) + (dolist (key '(database database-index database-count)) + (chess-game-set-data game key (chess-game-data next-game key))))))) (provide 'chess) |
