1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;; Obtain movements and other information from an engine
11 (defgroup chess-engine nil
12 "Code for reading movements and other commands from an engine."
15 (defvar chess-engine-regexp-alist nil)
16 (defvar chess-engine-event-handler nil)
17 (defvar chess-engine-response-handler nil)
18 (defvar chess-engine-current-marker nil)
19 (defvar chess-engine-position nil)
20 (defvar chess-engine-game nil)
22 (make-variable-buffer-local 'chess-engine-regexp-alist)
23 (make-variable-buffer-local 'chess-engine-event-handler)
24 (make-variable-buffer-local 'chess-engine-response-handler)
25 (make-variable-buffer-local 'chess-engine-current-marker)
26 (make-variable-buffer-local 'chess-engine-position)
27 (make-variable-buffer-local 'chess-engine-game)
29 (defvar chess-engine-process nil)
30 (defvar chess-engine-last-pos nil)
31 (defvar chess-engine-working nil)
33 (make-variable-buffer-local 'chess-engine-process)
34 (make-variable-buffer-local 'chess-engine-last-pos)
35 (make-variable-buffer-local 'chess-engine-working)
39 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
44 (defmacro chess-with-current-buffer (buffer &rest body)
47 (with-current-buffer buf
51 (defun chess-engine-do-move (ply)
54 (chess-game-move chess-engine-game ply))
55 (chess-engine-position
56 (setq chess-engine-position (chess-ply-next-pos ply)))))
58 (defun chess-engine-default-handler (event &rest args)
61 (chess-engine-do-move (car args)))
64 (message "Your opponent has passed the first move to you"))
67 (message "Your opponent, %s, is now ready to play" (car args)))
70 (message "Your opponent has quit playing"))
73 (chess-game-set-start-position (chess-engine-game nil)
74 (chess-fen-to-pos (car args))))))
76 (defun chess-engine-create (module &optional user-handler &rest args)
77 (let ((regexp-alist (intern-soft (concat (symbol-name module)
79 (handler (intern-soft (concat (symbol-name module) "-handler"))))
80 (with-current-buffer (generate-new-buffer " *chess-engine*")
81 (setq chess-engine-regexp-alist (symbol-value regexp-alist)
82 chess-engine-event-handler handler
83 chess-engine-response-handler (or user-handler
84 'chess-engine-default-handler))
85 (let ((proc (apply handler 'initialize args)))
87 (unless (memq (process-status proc) '(run open))
88 (error "Failed to start chess engine process"))
89 (setq chess-engine-process proc)
90 (set-process-buffer proc (current-buffer))
91 (set-process-filter proc 'chess-engine-filter))
92 (setq chess-engine-current-marker (point-marker)))
95 (defun chess-engine-destroy (engine)
96 (let ((buf (or engine (current-buffer))))
97 (if (buffer-live-p buf)
100 (defun chess-engine-command (engine event &rest args)
101 (chess-with-current-buffer engine
102 (apply chess-engine-event-handler event args)))
108 (defun chess-engine-set-option (engine option value)
109 (chess-with-current-buffer engine
112 (defun chess-engine-option (engine option) 'ponder 'search-depth 'wall-clock
113 (chess-with-current-buffer engine
116 (defun chess-engine-set-position (engine position)
117 (chess-with-current-buffer engine
118 (if chess-engine-game
119 (chess-engine-detach-game nil))
120 (setq chess-engine-game nil
121 chess-engine-position position)
122 (chess-engine-command nil 'setup position)))
124 (defun chess-engine-position (engine)
125 (chess-with-current-buffer engine
126 (or (and chess-engine-game
127 (chess-game-pos chess-engine-game))
128 chess-engine-position)))
130 (defun chess-engine-set-game (engine game)
131 (chess-with-current-buffer engine
132 (if chess-engine-game
133 (chess-engine-detach-game nil))
134 (setq chess-engine-game game
135 chess-engine-position nil)
136 (chess-game-add-hook game 'chess-engine-event-handler engine)
137 (chess-engine-command nil 'setup (chess-game-pos game))))
139 (defun chess-engine-detach-game (engine)
140 (chess-with-current-buffer engine
141 (if chess-engine-game
142 (chess-game-remove-hook chess-engine-game
143 'chess-engine-event-handler))))
145 (defun chess-engine-game (engine)
146 (chess-with-current-buffer engine
149 (defun chess-engine-index (engine)
150 (chess-with-current-buffer engine
151 (if chess-engine-game
152 (chess-game-index chess-engine-game))))
154 (defun chess-engine-move (engine ply)
155 (chess-with-current-buffer engine
156 (chess-engine-do-move ply)
157 (chess-engine-command engine 'move ply)))
159 (defun chess-engine-pass (engine)
160 (chess-with-current-buffer engine
161 (chess-engine-command engine 'pass)))
163 (defun chess-engine-send (engine string)
164 "Send the given STRING to ENGINE."
165 (chess-with-current-buffer engine
166 (let ((proc chess-engine-process))
168 (if (memq (process-status proc) '(run open))
169 (process-send-string proc string)
170 (error "The engine you were using is no longer running"))
171 (chess-engine-command nil 'send string)))))
173 (defun chess-engine-submit (engine string)
174 "Submit the given STRING, so ENGINE sees it in its input stream."
175 (chess-with-current-buffer engine
176 (let ((proc chess-engine-process))
177 (if (and (processp proc)
178 (not (memq (process-status proc) '(run open))))
179 (error "The engine you were using is no longer running"))
180 (chess-engine-filter nil string))))
182 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
184 ;; Primary event handler
187 (defun chess-engine-event-handler (game engine event &rest args)
188 "Handle any commands being sent to this instance of this module."
189 (with-current-buffer engine
190 (assert (eq game (chess-engine-game nil)))
191 (apply chess-engine-event-handler event args)
193 ((eq event 'shutdown)
194 (chess-engine-destroy engine)))))
196 (defun chess-engine-filter (proc string)
197 "Filter for receiving text for an engine from an outside source."
198 (let ((buf (if (processp proc)
199 (process-buffer proc)
201 (when (buffer-live-p buf)
202 (with-current-buffer buf
203 (let ((moving (= (point) chess-engine-current-marker)))
205 ;; Insert the text, advancing the marker.
206 (goto-char chess-engine-current-marker)
208 (set-marker chess-engine-current-marker (point)))
209 (if moving (goto-char chess-engine-current-marker)))
210 (unless chess-engine-working
211 (setq chess-engine-working t)
214 (if chess-engine-last-pos
215 (goto-char chess-engine-last-pos)
216 (goto-char (point-min)))
220 (let ((triggers chess-engine-regexp-alist))
222 ;; this could be accelerated by joining
223 ;; together the regexps
224 (if (looking-at (caar triggers))
226 (funcall (cdar triggers))
228 (setq triggers (cdr triggers)))))
229 (chess-illegal (error-message-string err)))
231 (setq chess-engine-last-pos (point)
232 chess-engine-working nil)))))))
234 (provide 'chess-engine)
236 ;;; chess-engine.el ends here