summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chess-display.el16
-rw-r--r--chess-game.el3
-rw-r--r--chess-ply.el273
3 files changed, 153 insertions, 139 deletions
diff --git a/chess-display.el b/chess-display.el
index c272a4a..69a7e47 100644
--- a/chess-display.el
+++ b/chess-display.el
@@ -231,8 +231,7 @@ modeline."
(defun chess-display-set-index (display index)
(chess-with-current-buffer display
(chess-display-set-index* nil index)
- (chess-display-update nil t)
- (chess-display-update-modeline)))
+ (chess-display-update nil t)))
(defsubst chess-display-index (display)
(chess-with-current-buffer display
@@ -244,6 +243,7 @@ modeline."
(funcall chess-display-event-handler 'draw
(chess-display-position nil)
(chess-display-perspective nil))
+ (chess-display-update-modeline)
(if (and popup (not chess-display-no-popup)
(chess-display-main-p nil))
(chess-display-popup nil))))
@@ -335,9 +335,6 @@ See `chess-display-type' for the different kinds of displays."
((eq event 'destroy)
(chess-display-detach-game nil))
- ((eq event 'post-move)
- (chess-display-update-modeline))
-
((eq event 'pass)
(let ((my-color (chess-game-data game 'my-color)))
(chess-game-set-data game 'my-color (not my-color))
@@ -525,8 +522,7 @@ The key bindings available in this mode are:
"Just redraw the current display."
(interactive)
(erase-buffer)
- (chess-display-update nil)
- (chess-display-update-modeline))
+ (chess-display-update nil))
(defsubst chess-display-active-p ()
"Return non-nil if the displayed chessboard reflects an active game.
@@ -1041,9 +1037,9 @@ Clicking once on a piece selects it; then click on the target location."
(> piece ?a)
(< piece ?a))
(throw 'message (chess-string 'wrong-color)))
- ;((null (chess-legal-plies position :index coord))
- ; (throw 'message (chess-string 'piece-immobile)))
- )
+ ((and chess-display-highlight-legal
+ (null (chess-legal-plies position :any :index coord)))
+ (throw 'message (chess-string 'piece-immobile))))
(setq chess-display-last-selected (list (point) coord))
(chess-display-highlight nil coord)
(if chess-display-highlight-legal
diff --git a/chess-game.el b/chess-game.el
index 73176b6..55b7588 100644
--- a/chess-game.el
+++ b/chess-game.el
@@ -237,8 +237,7 @@ progress (nil), if it is drawn, resigned, mate, etc."
(chess-game-run-hooks game 'move current-ply))))
(t
- (chess-game-run-hooks game 'move current-ply)
- (chess-game-run-hooks game 'post-move)))))
+ (chess-game-run-hooks game 'move current-ply)))))
(defsubst chess-game-end (game keyword)
"End the current game, by resignation, draw, etc."
diff --git a/chess-ply.el b/chess-ply.el
index 5d0836c..b9141c7 100644
--- a/chess-ply.el
+++ b/chess-ply.el
@@ -115,6 +115,11 @@
(chess-rf-to-index (if color 7 0) (if long 3 5))
(if long :long-castle :castle)))))
+(chess-message-catalog 'english
+ '((pawn-promote-query . "Promote pawn to queen/rook/knight/bishop? ")))
+
+(defvar chess-ply-no-promotions nil)
+
(defun chess-ply-create (position &rest changes)
"Create a ply from the given POSITION by applying the suppiled CHANGES.
This function will guarantee the resulting ply is legal, and will also
@@ -162,9 +167,10 @@ maneuver."
;; haven't already been told, ask for the piece to promote
;; it to
(if (and (not (memq :promote changes))
+ (not chess-ply-no-promotions)
(= (if color 0 7) (chess-index-rank (cadr changes))))
(let ((new-piece (completing-read
- "Promote pawn to queen/rook/knight/bishop? "
+ (chess-string 'pawn-promote-query)
chess-piece-name-table nil t "queen")))
(setq new-piece
(cdr (assoc new-piece chess-piece-name-table)))
@@ -225,6 +231,8 @@ maneuver."
(chess-ply-any-keyword ply :draw :perpetual :repetition :stalemate
:resign :checkmate))
+(defvar chess-ply-throw-if-any nil)
+
(eval-when-compile
(defvar position)
(defvar candidate)
@@ -232,15 +240,19 @@ maneuver."
(defvar plies))
(defsubst chess-ply--add (rank-adj file-adj &optional pos)
"This is totally a shortcut."
- (push (chess-ply-create position candidate
- (or pos (chess-incr-index candidate
- rank-adj file-adj)))
- plies))
+ (let ((ply (chess-ply-create position candidate
+ (or pos (chess-incr-index candidate
+ rank-adj file-adj)))))
+ (when ply
+ (if chess-ply-throw-if-any
+ (throw 'any-found t))
+ (push ply plies))))
(defun chess-legal-plies (position &rest keywords)
"Return a list of all legal plies in POSITION.
KEYWORDS allowed are:
+ :any return t if any piece can move at all
:color <t or nil>
:piece <piece character>
:file <number 0 to 7> [can only be used if :piece is present]
@@ -248,130 +260,137 @@ KEYWORDS allowed are:
These will constrain the plies generated to those matching the above
criteria."
- (if (null keywords)
- (let ((plies (list t)))
- (dolist (p '(?P ?R ?N ?B ?K ?Q ?p ?r ?n ?b ?k ?q))
- (nconc plies (chess-legal-plies position :piece p)))
- (cdr plies))
- (if (memq :color keywords)
- (let ((plies (list t))
- (color (cadr (memq :color keywords))))
- (dolist (p '(?P ?R ?N ?B ?K ?Q))
- (nconc plies (chess-legal-plies position
- :piece (if color p
- (downcase p)))))
- (cdr plies))
- (let* ((piece (cadr (memq :piece keywords)))
- (color (if piece (< piece ?a)
- (chess-pos-side-to-move position)))
- (test-piece
- (upcase (or piece
- (chess-pos-piece position
- (cadr (memq :index keywords))))))
- pos plies file)
- ;; since we're looking for moves of a particular piece, do a
- ;; more focused search
- (dolist (candidate
- (cond
- ((setq pos (cadr (memq :index keywords)))
- (list pos))
- ((setq file (cadr (memq :file keywords)))
- (let (candidates)
- (dotimes (rank 8)
- (setq pos (chess-rf-to-index rank file))
- (if (chess-pos-piece-p position pos piece)
- (push pos candidates)))
- candidates))
- (t
- (chess-pos-search position piece))))
- (cond
- ;; pawn movement, which is diagonal 1 when taking, but forward
- ;; 1 or 2 when moving (the most complex piece, actually)
- ((= test-piece ?P)
- (let* ((bias (if color -1 1))
- (ahead (chess-incr-index candidate bias 0))
- (2ahead (chess-incr-index candidate (if color -2 2) 0)))
- (when (chess-pos-piece-p position ahead ? )
- (chess-ply--add bias 0)
- (if (and (= (if color 6 1) (chess-index-rank candidate))
- (chess-pos-piece-p position 2ahead ? ))
- (chess-ply--add (if color -2 2) 0)))
- (when (setq pos (chess-incr-index candidate bias -1))
- (if (chess-pos-piece-p position pos (not color))
- (chess-ply--add nil nil pos))
- ;; check for en passant capture toward queenside
- (if (= (or (chess-pos-en-passant position) 100)
- (or (chess-incr-index pos (if color 1 -1) 0) 200))
- (chess-ply--add nil nil pos)))
- (when (setq pos (chess-incr-index candidate bias 1))
+ (cond
+ ((null keywords)
+ (let ((plies (list t)))
+ (dolist (p '(?P ?R ?N ?B ?K ?Q ?p ?r ?n ?b ?k ?q))
+ (nconc plies (chess-legal-plies position :piece p)))
+ (cdr plies)))
+ ((memq :any keywords)
+ (let ((chess-ply-throw-if-any t))
+ (catch 'any-found
+ (apply 'chess-legal-plies position (delq :any keywords)))))
+ ((memq :color keywords)
+ (let ((plies (list t))
+ (color (cadr (memq :color keywords))))
+ (dolist (p '(?P ?R ?N ?B ?K ?Q))
+ (nconc plies (chess-legal-plies position
+ :piece (if color p
+ (downcase p)))))
+ (cdr plies)))
+ (t
+ (let* ((piece (cadr (memq :piece keywords)))
+ (color (if piece (< piece ?a)
+ (chess-pos-side-to-move position)))
+ (test-piece
+ (upcase (or piece
+ (chess-pos-piece position
+ (cadr (memq :index keywords))))))
+ (chess-ply-no-promotions t)
+ pos plies file)
+ ;; since we're looking for moves of a particular piece, do a
+ ;; more focused search
+ (dolist (candidate
+ (cond
+ ((setq pos (cadr (memq :index keywords)))
+ (list pos))
+ ((setq file (cadr (memq :file keywords)))
+ (let (candidates)
+ (dotimes (rank 8)
+ (setq pos (chess-rf-to-index rank file))
+ (if (chess-pos-piece-p position pos piece)
+ (push pos candidates)))
+ candidates))
+ (t
+ (chess-pos-search position piece))))
+ (cond
+ ;; pawn movement, which is diagonal 1 when taking, but forward
+ ;; 1 or 2 when moving (the most complex piece, actually)
+ ((= test-piece ?P)
+ (let* ((bias (if color -1 1))
+ (ahead (chess-incr-index candidate bias 0))
+ (2ahead (chess-incr-index candidate (if color -2 2) 0)))
+ (when (chess-pos-piece-p position ahead ? )
+ (chess-ply--add bias 0)
+ (if (and (= (if color 6 1) (chess-index-rank candidate))
+ (chess-pos-piece-p position 2ahead ? ))
+ (chess-ply--add (if color -2 2) 0)))
+ (when (setq pos (chess-incr-index candidate bias -1))
+ (if (chess-pos-piece-p position pos (not color))
+ (chess-ply--add nil nil pos))
+ ;; check for en passant capture toward queenside
+ (if (= (or (chess-pos-en-passant position) 100)
+ (or (chess-incr-index pos (if color 1 -1) 0) 200))
+ (chess-ply--add nil nil pos)))
+ (when (setq pos (chess-incr-index candidate bias 1))
+ (if (chess-pos-piece-p position pos (not color))
+ (chess-ply--add nil nil pos))
+ ;; check for en passant capture toward kingside
+ (if (= (or (chess-pos-en-passant position) 100)
+ (or (chess-incr-index pos (if color 1 -1) 0) 200))
+ (chess-ply--add nil nil pos)))))
+
+ ;; the rook, bishop and queen are the easiest; just look along
+ ;; rank and file and/or diagonal for the nearest pieces!
+ ((memq test-piece '(?R ?B ?Q))
+ (dolist (dir (cond
+ ((= test-piece ?R)
+ '( (-1 0)
+ (0 -1) (0 1)
+ (1 0)))
+ ((= test-piece ?B)
+ '((-1 -1) (-1 1)
+
+ (1 -1) (1 1)))
+ ((= test-piece ?Q)
+ '((-1 -1) (-1 0) (-1 1)
+ (0 -1) (0 1)
+ (1 -1) (1 0) (1 1)))))
+ ;; up the current file
+ (setq pos (apply 'chess-incr-index candidate dir))
+ ;; jww (2002-04-11): In Fischer Random castling, the rook can
+ ;; move in wacky ways
+ (while pos
+ (if (chess-pos-piece-p position pos ? )
+ (progn
+ (chess-ply--add nil nil pos)
+ (setq pos (apply 'chess-incr-index pos dir)))
(if (chess-pos-piece-p position pos (not color))
(chess-ply--add nil nil pos))
- ;; check for en passant capture toward kingside
- (if (= (or (chess-pos-en-passant position) 100)
- (or (chess-incr-index pos (if color 1 -1) 0) 200))
- (chess-ply--add nil nil pos)))))
-
- ;; the rook, bishop and queen are the easiest; just look along
- ;; rank and file and/or diagonal for the nearest pieces!
- ((memq test-piece '(?R ?B ?Q))
- (dolist (dir (cond
- ((= test-piece ?R)
- '( (-1 0)
- (0 -1) (0 1)
- (1 0)))
- ((= test-piece ?B)
- '((-1 -1) (-1 1)
-
- (1 -1) (1 1)))
- ((= test-piece ?Q)
- '((-1 -1) (-1 0) (-1 1)
- (0 -1) (0 1)
- (1 -1) (1 0) (1 1)))))
- ;; up the current file
- (setq pos (apply 'chess-incr-index candidate dir))
- ;; jww (2002-04-11): In Fischer Random castling, the rook can
- ;; move in wacky ways
- (while pos
- (if (chess-pos-piece-p position pos ? )
- (progn
- (chess-ply--add nil nil pos)
- (setq pos (apply 'chess-incr-index pos dir)))
- (if (chess-pos-piece-p position pos (not color))
- (chess-ply--add nil nil pos))
- (setq pos nil)))))
-
- ;; the king is a trivial case of the queen, except when castling
- ((= test-piece ?K)
- (dolist (dir '((-1 -1) (-1 0) (-1 1)
- (0 -1) (0 1)
- (1 -1) (1 0) (1 1)))
- (setq pos (apply 'chess-incr-index candidate dir))
- (if (and pos
- (or (chess-pos-piece-p position pos ? )
- (chess-pos-piece-p position pos (not color))))
- (chess-ply--add nil nil pos)))
-
- (if (chess-pos-can-castle position (if color ?K ?k))
- (chess-ply--add 0 2))
- (if (chess-pos-can-castle position (if color ?Q ?q))
- (chess-ply--add 0 -2)))
-
- ;; the knight is a zesty little piece; there may be more than
- ;; one, but at only one possible square in each direction
- ((= test-piece ?N)
- (dolist (dir '((-2 -1) (-2 1)
- (-1 -2) (-1 2)
- (1 -2) (1 2)
- (2 -1) (2 1)))
- ;; up the current file
- (if (and (setq pos (apply 'chess-incr-index candidate dir))
- (or (chess-pos-piece-p position pos ? )
- (chess-pos-piece-p position pos (not color))))
- (chess-ply--add nil nil pos))))
-
- (t (chess-error 'piece-unrecognized))))
-
- (delq nil plies)))))
+ (setq pos nil)))))
+
+ ;; the king is a trivial case of the queen, except when castling
+ ((= test-piece ?K)
+ (dolist (dir '((-1 -1) (-1 0) (-1 1)
+ (0 -1) (0 1)
+ (1 -1) (1 0) (1 1)))
+ (setq pos (apply 'chess-incr-index candidate dir))
+ (if (and pos
+ (or (chess-pos-piece-p position pos ? )
+ (chess-pos-piece-p position pos (not color))))
+ (chess-ply--add nil nil pos)))
+
+ (if (chess-pos-can-castle position (if color ?K ?k))
+ (chess-ply--add 0 2))
+ (if (chess-pos-can-castle position (if color ?Q ?q))
+ (chess-ply--add 0 -2)))
+
+ ;; the knight is a zesty little piece; there may be more than
+ ;; one, but at only one possible square in each direction
+ ((= test-piece ?N)
+ (dolist (dir '((-2 -1) (-2 1)
+ (-1 -2) (-1 2)
+ (1 -2) (1 2)
+ (2 -1) (2 1)))
+ ;; up the current file
+ (if (and (setq pos (apply 'chess-incr-index candidate dir))
+ (or (chess-pos-piece-p position pos ? )
+ (chess-pos-piece-p position pos (not color))))
+ (chess-ply--add nil nil pos))))
+
+ (t (chess-error 'piece-unrecognized))))
+
+ (delq nil plies)))))
(provide 'chess-ply)