;; Author: Mario Lang <mlang@delysid.org>
-;; This file is free software; you can redistribute it and/or modify
+;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
-;; This file is distributed in the hope that it will be useful,
+;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
(defgroup chess-ai ()
"A simple chess engine written in Emacs Lisp.
-This module does not allow for configuring search time used to calculate
+This module does not allow to configure search time used to calculate
reply moves. You can only specify the search depth (see `chess-ai-depth')."
:group 'chess)
"The default search depth used to prune the search tree.
If `chess-ai-quiescence' is non-nil, quiescence search will be performed after
-the ply depth limit has been reached."
+this ply depth limit has been reached."
:group 'chess-ai
:type 'integer)
chess-ai-passed-pawn))))
;; Mobility
(when chess-ai-mobility
- (setq
- v
- (+
- v
- (-
- (+
- (if white-queens
- (length (chess-legal-plies position :piece ?Q
- :candidates white-queens))
- 0)
- (if white-rooks
- (length (chess-legal-plies position :piece ?R
- :candidates white-rooks))
- 0)
- (if white-bishops
- (length (chess-legal-plies position :piece ?B
- :candidates white-bishops))
- 0)
- (if white-knights
- (length (chess-legal-plies position :piece ?N
- :candidates white-knights))
- 0))
+ (let ((chess-ply-checking-mate t))
+ (setq
+ v
(+
- (if black-queens
- (length (chess-legal-plies position :piece ?q
- :candidates black-queens))
- 0)
- (if black-rooks
- (length (chess-legal-plies position :piece ?r
- :candidates black-rooks))
- 0)
- (if black-bishops
- (length (chess-legal-plies position :piece ?b
- :candidates black-bishops))
- 0)
- (if black-knights
- (length (chess-legal-plies position :piece ?n
- :candidates black-knights))
- 0))))))
+ v
+ (-
+ (+
+ (if white-queens
+ (length (chess-legal-plies position :piece ?Q
+ :candidates white-queens))
+ 0)
+ (if white-rooks
+ (length (chess-legal-plies position :piece ?R
+ :candidates white-rooks))
+ 0)
+ (if white-bishops
+ (length (chess-legal-plies position :piece ?B
+ :candidates white-bishops))
+ 0)
+ (if white-knights
+ (length (chess-legal-plies position :piece ?N
+ :candidates white-knights))
+ 0))
+ (+
+ (if black-queens
+ (length (chess-legal-plies position :piece ?q
+ :candidates black-queens))
+ 0)
+ (if black-rooks
+ (length (chess-legal-plies position :piece ?r
+ :candidates black-rooks))
+ 0)
+ (if black-bishops
+ (length (chess-legal-plies position :piece ?b
+ :candidates black-bishops))
+ 0)
+ (if black-knights
+ (length (chess-legal-plies position :piece ?n
+ :candidates black-knights))
+ 0)))))))
(if (chess-pos-side-to-move position)
v
A `cons' cell is returned where `cdr' is the supposedly best move from POSITION
and `car' is the score of that move. If there is no legal move from POSITION
\(or DEPTH is 0), `cdr' will be nil."
- (let ((chess-ply-allow-interactive-query nil))
- (if (zerop depth)
- (cons (funcall eval-fn position) nil)
- (let ((plies (let ((chess-ai-mobility nil)
- (chess-ai-quiescence nil))
- (sort
- (mapcar
- (lambda (ply)
- (chess-ply-set-keyword
- ply :score
- (- (chess-ai-search (chess-ply-next-pos ply)
- 1
- (1+ most-negative-fixnum)
- most-positive-fixnum
- #'chess-ai-eval-static)))
- ply)
- (chess-legal-plies
- position :color (chess-pos-side-to-move position)))
- (lambda (lhs rhs)
- (> (chess-ply-keyword lhs :score)
- (chess-ply-keyword rhs :score)))))))
- (if (null plies)
- (cons (funcall eval-fn position) nil)
- (let* ((best-ply (car plies))
- (progress (make-progress-reporter
- (format "Thinking... (%s) "
- (chess-ply-to-algebraic best-ply))
- 0 (length plies))))
- (cl-loop for i from 1
- for ply in plies
- do (let ((value (- (chess-ai-search
- (chess-ply-next-pos ply)
- (1- depth) (- upper-bound) (- lower-bound)
- eval-fn))))
- (progress-reporter-update progress i)
- (accept-process-output nil 0.05)
- (when (> value lower-bound)
- (setq lower-bound value
- best-ply ply)
- (progress-reporter-force-update
- progress
- i
- (format "Thinking... (%s {cp=%d}) "
- (chess-ply-to-algebraic best-ply)
- lower-bound))))
- until (>= lower-bound upper-bound))
- (progress-reporter-done progress)
- (cons lower-bound best-ply)))))))
+ (if (zerop depth)
+ (cons (funcall eval-fn position) nil)
+ (let ((plies (let ((chess-ai-mobility nil)
+ (chess-ai-quiescence nil))
+ (sort
+ (mapcar
+ (lambda (ply)
+ (chess-ply-set-keyword
+ ply :score
+ (- (chess-ai-search (chess-ply-next-pos ply)
+ 1
+ (1+ most-negative-fixnum)
+ most-positive-fixnum
+ #'chess-ai-eval-static)))
+ ply)
+ (chess-legal-plies
+ position :color (chess-pos-side-to-move position)))
+ (lambda (lhs rhs)
+ (> (chess-ply-keyword lhs :score)
+ (chess-ply-keyword rhs :score)))))))
+ (if (null plies)
+ (cons (funcall eval-fn position) nil)
+ (let* ((best-ply (car plies))
+ (progress (make-progress-reporter
+ (format "Thinking... (%s) "
+ (chess-ply-to-algebraic best-ply))
+ 0 (length plies))))
+ (cl-loop for i from 1
+ for ply in plies
+ do (let ((value (- (chess-ai-search
+ (chess-ply-next-pos ply)
+ (1- depth) (- upper-bound) (- lower-bound)
+ eval-fn))))
+ (progress-reporter-update progress i)
+ (accept-process-output nil 0.05)
+ (when (> value lower-bound)
+ (setq lower-bound value
+ best-ply ply)
+ (progress-reporter-force-update
+ progress
+ i
+ (format "Thinking... (%s {cp=%d}) "
+ (chess-ply-to-algebraic best-ply)
+ lower-bound))))
+ until (>= lower-bound upper-bound))
+ (progress-reporter-done progress)
+ (cons lower-bound best-ply))))))
(defun chess-ai-best-move (position &optional depth eval-fn)
- "Find the best move for POSITION."
+ "Find the best move for POSITION.
+DEPTH defaults to the value of `chess-ai-depth'."
(cdr (chess-ai-eval position (or depth chess-ai-depth)
(1+ most-negative-fixnum) most-positive-fixnum
(or eval-fn #'chess-ai-eval-static))))