summaryrefslogtreecommitdiff
path: root/chess-ai.el
blob: 1cb083faf58421105826756bceec2b47a957e798 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
;;; chess-ai.el --- A Chess playing module

;; Copyright (C) 2004  Free Software Foundation, Inc.

;; Author: Mario Lang <mlang@delysid.org>

;; This file 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.

;; This file 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.

;;; Commentary:

;; BUGS: Opponent moves are not displayed on the board!  But they are announced
;; and shown in the mode-line, strange!

;;; Code:

(require 'chess-common)
(require 'chess-pos)
(require 'chess-ply)

(defvar chess-pawn-value 100)
(defvar chess-knight-value 300)
(defvar chess-bishop-value 300)
(defvar chess-rook-value 500)
(defvar chess-queen-value 900)
(defvar chess-king-value 10000)

(defun chess-eval-static (position)
  (assert (vectorp position))
  (let ((v 0)
	(status (chess-pos-status position)))
    (if (eq status :checkmate)
	-64000
      (if (eq status :stalemate)
	  v
	(dotimes (i 64 (if (chess-pos-side-to-move position) v (- v)))
	  (let ((piece (aref position i)))
	    (cond
	     ((= piece ?P) (incf v chess-pawn-value))
	     ((= piece ?p) (decf v chess-pawn-value))
	     ((= piece ?K) (incf v chess-king-value))
	     ((= piece ?k) (decf v chess-king-value))
	     ((= piece ?Q) (incf v chess-queen-value))
	     ((= piece ?q) (decf v chess-queen-value))
	     ((= piece ?R) (incf v chess-rook-value))
	     ((= piece ?r) (decf v chess-rook-value))
	     ((= piece ?B) (incf v chess-bishop-value))
	     ((= piece ?b) (decf v chess-bishop-value))
	     ((= piece ?N) (incf v chess-knight-value))
	     ((= piece ?n) (decf v chess-knight-value)))))))))

(defun chess-ai-eval (position depth alpha beta &optional line)
  (if (= depth 0)
      (cons (chess-eval-static position) line)
    (let ((plies (chess-legal-plies
		  position :color (chess-pos-side-to-move position)))
	  (ret (cons alpha line)))
      (if (= (length plies) 0)
	  (cons (chess-eval-static position) line)
	(while plies
	  (let* ((tmp1 (chess-ai-eval (chess-ply-next-pos (car plies))
				       (1- depth) (- beta) (- alpha)
				       (cons (car plies) line)))
		 (tmp (- (car tmp1))))
	    (if (> tmp alpha) (setq alpha tmp
				    ret (cons tmp (cdr tmp1))))
	    (if (>= alpha beta)
		(setq plies nil)
	      (setq plies (cdr plies)))))
	ret))))

(defun chess-ai-best-move (position depth &optional func)
  (let ((res (chess-ai-eval position  depth -100000 100000)))
    (cons (car res)
	  (if (functionp func)
	      (mapcar func (nreverse (cdr res)))
	    (nreverse (cdr res))))))

(defvar chess-ai-regexp-alist nil)

(defun chess-ai-handler (game event &rest args)
  (unless chess-engine-handling-event
    (cond
     ((eq event 'initialize)
      (setq chess-engine-process t)
      (setq chess-engine-opponent-name "Emacs AI")
      t)

     ((eq event 'setup-pos)
      t)

     ((eq event 'move)
      (when (= 1 (chess-game-index game))
	(chess-game-set-tag game "White" chess-full-name)
      (chess-game-set-tag game "Black" chess-engine-opponent-name))
      
      (if (chess-game-over-p game)
	  (chess-game-set-data game 'active nil))
      (let ((bm (chess-ai-best-move (chess-engine-position nil) 3)))
	(funcall chess-engine-response-handler 'move
		 (cadr bm))))

     (t
      (apply 'chess-common-handler game event args)))))


(provide 'chess-ai)
;;; chess-ai.el ends here