summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2002-04-18 18:30:19 +0000
committerJohn Wiegley <johnw@newartisans.com>2002-04-18 18:30:19 +0000
commit563cf2037068f67f6786172b029363aaa7d52776 (patch)
tree549c69928ccc019093fed062f6999462fbb431db
parent2b0db13d4cdc3aaadd7dd458c1097c668577a072 (diff)
Many efficiency improvements and bug fixes.
-rw-r--r--chess-algebraic.el122
-rw-r--r--chess-common.el4
-rw-r--r--chess-crafty.el1
-rw-r--r--chess-display.el110
-rw-r--r--chess-engine.el35
-rw-r--r--chess-game.el14
-rw-r--r--chess-gnuchess.el1
-rw-r--r--chess-ics.el3
-rw-r--r--chess-input.el2
-rw-r--r--chess-module.el6
-rw-r--r--chess-network.el2
-rw-r--r--chess-pgn.el20
-rw-r--r--chess-phalanx.el1
-rw-r--r--chess-plain.el4
-rw-r--r--chess-ply.el16
-rw-r--r--chess-pos.el41
-rw-r--r--chess-var.el7
-rw-r--r--chess.el87
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)
diff --git a/chess.el b/chess.el
index 2400a7c..4b90b56 100644
--- a/chess.el
+++ b/chess.el
@@ -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)