1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;; An engine for interacting with Internet Chess Servers
7 (require 'chess-network)
10 (defgroup chess-ics nil
11 "Engine for interacting with Internet Chess Servers."
14 (defvar chess-ics-ensure-ics12 nil)
15 (make-variable-buffer-local 'chess-ics-ensure-ics12)
17 ;; ICS12 format (with artificial line breaks):
19 ;; <12> rnbqkbnr pppppppp -------- -------- \
20 ;; -------- -------- PPPPPPPP RNBQKBNR W \
21 ;; -1 1 1 1 1 0 65 jwiegley GuestZYNJ \
22 ;; 1 5 0 39 39 300 300 1 P/e2-e4 (0:00) e4 0 0 0
24 (defun chess-ics12-parse (string)
25 "Parse an ICS12 format string, and return a list of its info.
26 The list is comprised of: the ply the string represents, who is white,
28 (let ((parts (split-string string " "))
29 (position (chess-pos-create t))
32 (assert (= (length parts) 31))
34 ;; first, handle the layout of the position
37 (let ((piece (aref (car parts) j)))
39 (chess-pos-set-piece position (chess-rf-to-index i j)
41 (setq parts (cdr parts)))
43 ;; next, the "side to move
44 (chess-pos-set-side-to-move position (string= (car parts) "W"))
45 (setq parts (cdr parts))
48 (setq parts (cdr parts))
51 (if (string= (car parts) "1")
52 (chess-pos-set-can-castle position ?K t))
53 (setq parts (cdr parts))
54 (if (string= (car parts) "1")
55 (chess-pos-set-can-castle position ?Q t))
56 (setq parts (cdr parts))
57 (if (string= (car parts) "1")
58 (chess-pos-set-can-castle position ?k t))
59 (setq parts (cdr parts))
60 (if (string= (car parts) "1")
61 (chess-pos-set-can-castle position ?q t))
62 (setq parts (cdr parts))
65 (setq parts (cdr parts))
66 (setq parts (cdr parts))
68 ;; white player, black player
69 (setq white (car parts))
70 (setq parts (cdr parts))
71 (setq black (car parts))
72 (setq parts (cdr parts))
75 (setq parts (cdr parts))
76 (setq parts (cdr parts))
77 (setq parts (cdr parts))
79 ;; material values for each side
80 (setq parts (cdr parts))
81 (setq parts (cdr parts))
83 ;; starting time each side
84 (setq parts (cdr parts))
85 (setq parts (cdr parts))
88 (setq parts (cdr parts))
90 ;; move in elaborated notation
91 (setq parts (cdr parts))
94 (setq parts (cdr parts))
96 ;; move in algebraic notation
97 (setq ply (if (string= (car parts) "none")
98 (chess-ply-create position)
99 (chess-algebraic-to-ply position (car parts))))
100 (setq parts (cdr parts))
103 (setq parts (cdr parts))
104 (setq parts (cdr parts))
105 (setq parts (cdr parts))
107 (list ply white black)))
109 (defun chess-ics-handle-move ()
110 (let ((begin (match-beginning 1))
112 (info (chess-ics12-parse (match-string 2))))
113 (if (> (chess-game-index (chess-engine-game nil)) 0)
114 (if (eq (chess-pos-side-to-move (chess-ply-pos (car info)))
115 (chess-pos-side-to-move (chess-engine-position nil)))
116 (chess-engine-do-move (car info)))
117 (chess-game-set-plies (chess-engine-game nil)
119 (unless (string= (cadr info) ics-handle)
120 (chess-game-run-hooks (chess-engine-game nil) 'pass)))
121 (delete-region begin end)
124 (defvar chess-ics-regexp-alist
125 (list (cons "\\(<12> \\(.+\\)\\)" 'chess-ics-handle-move)
126 (cons "You accept the match offer from \\([^\\.]+\\)."
129 (funcall chess-engine-response-handler 'connect
130 (match-string 1)))))))
132 (defun chess-ics-handler (event &rest args)
134 ((eq event 'initialize)
135 (let* ((old-buffer (current-buffer))
136 (address-or-alias (read-from-minibuffer
137 "ICS Server address or alias: "))
138 (server-info-list (cdr (assoc address-or-alias
140 (ics-address (or (car (cdr server-info-list))
142 (ics-connect-method (or (car (nthcdr 3 server-info-list))
143 ics-default-connect-method))
144 (server-name (or (car server-info-list)
146 (ics-port (or (car (nthcdr 2 server-info-list))
147 (read-from-minibuffer "ICS port: "
149 (handle (read-from-minibuffer "ICS Handle: "
151 (proc (concat server-name ":" handle))
152 (buffer (concat "*" proc "*")))
154 (setq ics-handle handle)
156 (if (comint-check-proc buffer)
158 (run-hooks 'ics-pre-connect-hook)
159 (set-buffer (make-comint proc (cons ics-address ics-port)))
160 (run-hooks 'ics-post-connect-hook)
163 (set (make-variable-buffer-local 'ics-last-command-time)
165 (set (make-variable-buffer-local 'ics-idle-p) nil)
166 (set (make-variable-buffer-local 'ics-interface-variable-set) nil)
167 (set (make-variable-buffer-local 'ics-wakeup-last-alarm-time)
169 (set (make-variable-buffer-local 'ics-last-highlight-end) nil)
170 (set (make-variable-buffer-local 'ics-last-add-buttons-end) nil)
172 (add-hook 'comint-output-filter-functions 'chess-ics-filter t t)
173 (set (make-local-variable 'comint-preoutput-filter-functions)
174 '(chess-ics-strip-cr))
176 (display-buffer buffer)
177 (kill-buffer old-buffer)
181 ((eq event 'shutdown)
183 (chess-engine-send nil "quit\n")))
186 (unless chess-ics-ensure-ics12
187 (comint-send-string (get-buffer-process (current-buffer))
189 (setq chess-ics-ensure-ics12 t))
190 (chess-engine-send nil (concat (chess-ply-to-algebraic (car args))
194 (comint-send-string (get-buffer-process (current-buffer)) (car args)))))
196 (defun chess-ics-filter (string)
198 (if chess-engine-last-pos
199 (goto-char chess-engine-last-pos)
200 (goto-char (point-min)))
203 (let ((triggers chess-ics-regexp-alist))
205 ;; this could be accelerated by joining together the
207 (if (and (looking-at (concat "[^\n\r]*" (caar triggers)))
208 (funcall (cdar triggers)))
210 (setq triggers (cdr triggers)))))
212 (setq chess-engine-last-pos (point))))
214 (defun chess-ics-strip-cr (string)
215 (while (string-match "\r" string)
216 (setq string (replace-match "" t t string)))
221 ;;; chess-ics.el ends here