1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;; Keyboard entry of algebraic notation, using shortcut notation
5 ;; This scheme was adapted from the way SCID
6 ;; (http://scid.sourceforge.net), by Shane Hudson, behaves. It's the
7 ;; only way to move your pieces around!
10 (defvar chess-input-move-string "")
11 (defvar chess-input-moves-pos nil)
12 (defvar chess-input-moves nil)
13 (defvar chess-input-position-function nil)
14 (defvar chess-input-move-function nil)
16 (make-variable-buffer-local 'chess-input-move-string)
17 (make-variable-buffer-local 'chess-input-moves-pos)
18 (make-variable-buffer-local 'chess-input-moves)
19 (make-variable-buffer-local 'chess-input-position-function)
20 (make-variable-buffer-local 'chess-input-move-function)
22 (defun chess-input-test-move (move-ply)
23 "Return the given MOVE if it matches the user's current input."
24 (let* ((move (cdr move-ply))
25 (i 0) (x 0) (l (length move))
26 (xl (length chess-input-move-string))
28 (unless (or (and (equal (downcase chess-input-move-string) "ok")
29 (string-match "\\`O-O[+#]?\\'" move))
30 (and (equal (downcase chess-input-move-string) "oq")
31 (string-match "\\`O-O-O[+#]?\\'" move)))
32 (while (and (< i l) (< x xl))
33 (let ((move-char (aref move i))
34 (entry-char (aref chess-input-move-string x)))
35 (if (and (= move-char ?x)
38 (if (/= entry-char (if (< entry-char ?a)
40 (downcase move-char)))
42 (setq i (1+ i) x (1+ x)))))))
46 (defsubst chess-input-display-moves (&optional move-list)
47 (if (> (length chess-input-move-string) 0)
48 (message "[%s] %s" chess-input-move-string
51 (delq nil (mapcar 'chess-input-test-move
52 (cdr chess-input-moves))))
55 (defun chess-input-shortcut-delete ()
57 (when (and chess-input-move-string
58 (stringp chess-input-move-string)
59 (> (length chess-input-move-string) 0))
60 (setq chess-input-move-string
61 (substring chess-input-move-string 0 (1- (length chess-input-move-string))))
62 (chess-input-display-moves)))
64 (defun chess-input-shortcut (&optional display-only)
66 (let* ((position (funcall chess-input-position-function))
67 (color (chess-pos-side-to-move position))
69 (unless (memq last-command '(chess-input-shortcut
70 chess-input-shortcut-delete))
71 (setq chess-input-move-string nil))
73 (setq chess-input-move-string
74 (concat chess-input-move-string (char-to-string last-command-char))))
75 (unless (and chess-input-moves
76 (eq position chess-input-moves-pos)
77 (or (> (length chess-input-move-string) 1)
78 (eq (car chess-input-moves) last-command-char)))
79 (setq char (if (eq (downcase last-command-char) ?o) ?k
81 chess-input-moves-pos position
88 (cons ply (chess-ply-to-algebraic ply))))
90 (append (chess-legal-plies
91 position :piece (if color ?P ?p) :file 1)
93 position :piece (if color ?B ?b)))
96 (chess-legal-plies position
97 :piece (if color ?P ?p)
99 (chess-legal-plies position
105 (string-lessp (cdr left) (cdr right)))))))))
106 (let ((moves (delq nil (mapcar 'chess-input-test-move
107 (cdr chess-input-moves)))))
109 ((or (= (length moves) 1)
110 ;; if there is an exact match except for case, it must be an
111 ;; abiguity between a bishop and a b-pawn move. In this
112 ;; case, always take the b-pawn move; to select the bishop
113 ;; move, use B to begin the keyboard shortcut
114 (and (= (length moves) 2)
115 (string= (downcase (cdr (car moves)))
116 (downcase (cdr (cadr moves))))
117 (setq moves (cdr moves))))
118 (funcall chess-input-move-function nil (caar moves))
119 (setq chess-input-move-string nil
120 chess-input-moves nil
121 chess-input-moves-pos nil))
123 (chess-input-shortcut-delete))
125 (chess-input-display-moves moves)))))
127 (provide 'chess-input)
129 ;;; chess-input.el ends here