1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;; Convert a chess position to/from FEN notation
5 ;; FEN notation encodes a chess position using a simple string. The
10 ;; The POSITION gives all eight ranks, by specifying a letter for each
11 ;; piece on the position, and a number for any intervening spaces.
12 ;; Trailing spaces need not be counted. Uppercase letters signify
13 ;; white, and lowercase black. For example, if your position only had
14 ;; a black king on d8, your POSITION string would be:
18 ;; For the three spaces (a, b and c file), the black king, and then
19 ;; all the remaining ranks (which are all empty, so their spaces can
22 ;; The SIDE is w or b, to indicate whose move it is.
24 ;; The FLAGS can contain K, Q, k or q, to signify whether the white or
25 ;; black king can still castle on the king or queen side. You can
26 ;; also have coordinates, such as e4, a5, to specify which pawns may
27 ;; be captured by en passant.
29 ;; The starting chess position always looks like this:
31 ;; rnbqkbnr/pppppppp/////PPPPPPPP/RNBQKBNR/ w KQkq -
33 ;; And in "full" mode (where all spaces are accounted for):
35 ;; rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -
37 ;; It may also have the current game sequence appended, but this
38 ;; relate to the game, not the position.
41 (defun chess-fen-to-pos (fen)
42 "Convert a FEN-like notation string to a chess position."
43 (assert (stringp fen))
44 (let ((i 0) (l (length fen))
45 (rank 0) (file 0) (c ?0)
46 (position (chess-pos-create t))
47 error (space-count 0))
49 (while (and (null error)
53 (setq file 0 rank (1+ rank)))
54 ((and (>= c ?1) (<= c ?9))
55 (setq file (+ file (- c ?0))))
56 ((memq (upcase c) '(?K ?Q ?B ?N ?R ?P))
57 (chess-pos-set-piece position (chess-rf-to-index rank file) c)
58 (setq file (1+ file)))
61 (setq i (1+ i) c (aref fen i)))
62 (if (= (aref fen i) ? )
64 (if (memq (aref fen i) '(?b ?w))
66 (chess-pos-set-side-to-move position (= (aref fen i) ?w))
70 (while (and (null error)
71 (< space-count 2) (< i l))
74 ((= c ? ) (setq space-count (1+ space-count)))
75 ((= c ?K) (chess-pos-set-can-castle position ?K t))
76 ((= c ?Q) (chess-pos-set-can-castle position ?Q t))
77 ((= c ?k) (chess-pos-set-can-castle position ?k t))
78 ((= c ?q) (chess-pos-set-can-castle position ?q t))
79 ((and (>= c ?a) (<= c ?h))
80 (chess-pos-set-en-passant position (chess-coord-to-index
81 (substring fen i (+ i 2))))
85 (setq i (1+ i) c (and (< i l) (aref fen i))))
89 (defun chess-pos-to-fen (position &optional full)
90 "Convert a chess POSITION to FEN-like notation.
91 If FULL is non-nil, represent trailing spaces as well."
92 (assert (vectorp position))
93 (let ((blank 0) (str "") output)
96 (let ((p (chess-pos-piece position (chess-rf-to-index rank file))))
98 (setq blank (1+ blank))
100 (setq str (concat str (int-to-string blank)) blank 0))
101 (setq str (concat str (char-to-string p))))))
102 (if (and full (> blank 0))
103 (setq str (concat str (int-to-string blank))))
104 (setq blank 0 str (concat str "/")))
105 (setq str (if (chess-pos-side-to-move position)
108 (if (chess-pos-can-castle position ?K)
109 (setq str (concat str "K") output t))
110 (if (chess-pos-can-castle position ?Q)
111 (setq str (concat str "Q") output t))
112 (if (chess-pos-can-castle position ?k)
113 (setq str (concat str "k") output t))
114 (if (chess-pos-can-castle position ?q)
115 (setq str (concat str "q") output t))
117 (setq str (concat str " "))
118 (setq str (concat str "- ")))
119 (let ((index (chess-pos-en-passant position)))
121 (concat str (chess-index-to-coord index))
126 ;;; chess-fen.el ends here