1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;; Convert a ply to/from standard chess algebraic notation
5 ;; A thing to deal with in chess is algebraic move notation, such as
6 ;; Nxf3+. (I leave description of this notation to better manuals
7 ;; than this). This notation is a shorthand way of representing where
8 ;; a piece is moving from and to, by specifying the piece is involved,
9 ;; where it's going, and whether or not a capture or check is
12 ;; You can convert from algebraic notation to a ply (one pair in most
13 ;; cases, but two for a castle) using the following function (NOTE:
14 ;; POSITION determines which side is on move (by calling
15 ;; `chess-pos-side-to-move')):
17 ;; (chess-algebraic-to-ply POSITION STRING)
19 ;; The function also checks if a move is legal, and will raise an
22 ;; To convert from a ply to algebraic notation, use:
24 ;; (chess-ply-to-algebraic PLY)
26 ;; Castling is determined by the movement of both a king and a rook.
28 ;; Lastly, there is a regexp for quickly checking if a string is in
29 ;; algebraic notation or not, or searching out algebraic strings in a
32 ;; chess-algebraic-regexp
38 (defconst chess-algebraic-pieces-regexp "[RNBKQ]")
40 (defconst chess-algebraic-regexp
43 "\\(%s?\\(\\([a-h]\\|[1-8]\\)?\\|[a-h][1-8]\\)\\)?"
49 chess-algebraic-pieces-regexp
50 chess-algebraic-pieces-regexp)
51 "A regular expression that matches all possible algebraic moves.
52 This regexp handles both long and short form.")
54 (defun chess-algebraic-to-ply (position move &optional search-func)
55 "Convert the algebraic notation MOVE for POSITION to a ply."
56 (when (string-match chess-algebraic-regexp move)
57 (let* ((color (chess-pos-side-to-move position))
58 (mate (match-string 10 move))
62 (let ((rank (if color 7 0))
63 (long (= (length (match-string 1 move)) 5)))
64 (list (chess-rf-to-index rank 4)
65 (chess-rf-to-index rank (if long 2 6))
66 (chess-rf-to-index rank (if long 0 7))
67 (chess-rf-to-index rank (if long 3 5))))
68 (let ((source (match-string 4 move))
69 (target (chess-coord-to-index (match-string 7 move))))
70 (if (and source (= (length source) 2))
71 (list (chess-coord-to-index source) target)
72 (let (candidates which)
75 ;; we must use our knowledge of how pieces can
76 ;; move, to determine which piece is meant by the
78 (when (setq candidates
79 (funcall (or search-func
80 'chess-standard-search-position)
81 position target (if color piece
83 (if (= (length candidates) 1)
84 (list (car candidates) target)
86 (error "Clarify piece to move by rank or file")
88 (if (if (>= source ?a)
89 (eq (cdar candidates) (- source ?a))
90 (eq (caar candidates) (- 7 (- source ?1))))
91 (setq which (car candidates) candidates nil)
92 (setq candidates (cdr candidates))))
94 (error "Could not determine which piece to use")
95 (list which target)))))))))))
98 (list (if (equal mate "#")
102 (apply 'chess-ply-create position changes))))
104 (defun chess-ply-to-algebraic (ply &optional long search-func)
105 "Convert the given PLY to algebraic notation.
106 If LONG is non-nil, render the move into long notation."
107 (if (null (car (chess-ply-changes ply)))
109 (let* ((pos (chess-ply-pos ply))
110 (changes (chess-ply-changes ply))
113 (from-piece (chess-pos-piece pos from))
114 (color (chess-pos-side-to-move pos)) str
117 (and (= (upcase from-piece) ?K)
118 (= from (chess-rf-to-index (if color 7 0) 4))
119 (if (= to (chess-rf-to-index (if color 7 0) 6))
121 (if (= to (chess-rf-to-index (if color 7 0) 2))
124 (let ((candidates (funcall (or search-func
125 'chess-standard-search-position)
128 (from-rank (/ from 8))
129 (from-file (mod from 8))
130 differentiator notation)
131 (when (> (length candidates) 1)
132 (dolist (candidate candidates)
133 (if (= (/ candidate 8) from-rank)
134 (setq rank (1+ rank)))
135 (if (= (mod candidate 8) from-file)
136 (setq file (1+ file))))
139 (setq differentiator (+ from-file ?a)))
141 (setq differentiator (+ (- 7 from-rank) ?1)))
142 (t (error "Could not differentiate piece"))))
144 (unless (= (upcase from-piece) ?P)
145 (char-to-string (upcase from-piece)))
147 (chess-index-to-coord from)
149 (char-to-string differentiator)
150 (if (and (not long) (= (upcase from-piece) ?P)
151 (/= (chess-index-file from)
152 (chess-index-file to)))
153 (char-to-string (+ (chess-index-file from) ?a)))))
154 (if (/= ? (chess-pos-piece pos to))
156 (chess-index-to-coord to)
157 (let ((promote (memq ':promote changes)))
159 (concat "=" (char-to-string (cadr promote))))))))))
161 (if (memq ':check changes) "+"
162 (if (memq ':checkmate changes) "#"))))))
164 (provide 'chess-algebraic)
166 ;;; chess-algebraic.el ends here