]> code.delx.au - gnu-emacs-elpa/blob - chess-uci.el
Parse UCI long algebraic moves correctly.
[gnu-emacs-elpa] / chess-uci.el
1 ;;; chess-uci.el --- Universal chess interface protocol for emacs-chess
2
3 ;; Copyright (C) 2014 Free Software Foundation, Inc.
4
5 ;; Author: Mario Lang <mlang@delysid.org>
6 ;; Keywords: games
7
8 ;; This file is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 2, or (at your option)
11 ;; any later version.
12
13 ;; This file is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
17
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GNU Emacs; see the file COPYING. If not, write to
20 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 ;; Boston, MA 02111-1307, USA.
22
23 ;;; Code:
24
25 (require 'chess-common)
26
27 (defvar chess-uci-long-algebraic-regexp "\\([a-h][1-8]\\)\\([a-h][1-8]\\)\\([nbrq]\\)?"
28 "A regular expression matching a UCI move.")
29
30 (defun chess-uci-long-algebraic-to-ply (position move)
31 "Convert the long algebraic notation MOVE for POSITION to a ply."
32 (assert (vectorp position))
33 (assert (stringp move))
34 (let ((case-fold-search nil))
35 (when (string-match chess-uci-long-algebraic-regexp move)
36 (let ((color (chess-pos-side-to-move position))
37 (from (chess-coord-to-index (match-string 1 move)))
38 (to (chess-coord-to-index (match-string 2 move)))
39 (promotion (match-string 3 move)))
40 (apply #'chess-ply-create position nil
41 (if (and (= from (chess-pos-king-index position color))
42 (= (chess-index-rank from) (chess-index-rank to))
43 (> (abs (- (chess-index-file from)
44 (chess-index-file to))) 1))
45 (chess-ply-castling-changes
46 position
47 (< (- (chess-index-file to) (chess-index-file from)) 0))
48 (nconc (list from to)
49 (when promotion
50 (list :promote (upcase (aref promotion 0)))))))))))
51
52 (defsubst chess-uci-convert-long-algebraic (move)
53 "Convert long algebraic MOVE to a ply in reference to the engine position.
54 If conversion fails, this function fired an 'illegal event."
55 (or (chess-uci-long-algebraic-to-ply (chess-engine-position nil) move)
56 (chess-engine-command nil 'illegal)))
57
58 (defvar chess-uci-regexp-alist
59 (list
60 (cons "^id\\s-+name\\s-+\\(.+\\)$"
61 (function
62 (lambda ()
63 (setq-local chess-engine-opponent-name (match-string 1))
64 'once)))
65 (cons (concat "^bestmove\\s-+\\(" chess-uci-long-algebraic-regexp "\\)")
66 (function
67 (lambda ()
68 (funcall chess-engine-response-handler 'move
69 (chess-uci-convert-long-algebraic (match-string 1)))))))
70 "Patterns matching responses of a standard UCI chess engine.")
71
72 (defun chess-uci-position (game)
73 (concat "position fen " (chess-pos-to-fen (chess-game-pos game 0) t)
74 " moves " (mapconcat (lambda (ply)
75 (let ((source (chess-ply-source ply))
76 (target (chess-ply-target ply)))
77 (if (and source target)
78 (concat (chess-index-to-coord source)
79 (chess-index-to-coord target)
80 (if (chess-ply-keyword ply :promote)
81 (string (downcase (chess-ply-keyword ply :promote)))
82 ""))
83 "")))
84 (chess-game-plies game) " ")
85 "\n"))
86
87 (defun chess-uci-handler (game event &rest args)
88 (unless chess-engine-handling-event
89 (cond
90 ((eq event 'move)
91 (when (= 1 (chess-game-index game))
92 (chess-game-set-tag game "White" chess-full-name)
93 (chess-game-set-tag game "Black" chess-engine-opponent-name))
94
95 (chess-engine-send nil (concat (chess-uci-position game) "go\n"))
96 (if (chess-game-over-p game)
97 (chess-game-set-data game 'active nil)))
98
99 (t
100 (apply 'chess-common-handler game event args)))))
101
102 (provide 'chess-uci)
103
104 ;;; chess-uci.el ends here