/usr/share/emacs/site-lisp/chess/chess-fen.el is in emacs-chess 2.0b6-1.1ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Convert a chess position to/from FEN notation
;;
;; FEN notation encodes a chess position using a simple string. The
;; format is:
;;
;; POSITION SIDE CASTLING EN-PASSANT
;;
;; The POSITION gives all eight ranks, by specifying a letter for each
;; piece on the position, and a number for any intervening spaces.
;; Trailing spaces need not be counted. Uppercase letters signify
;; white, and lowercase black. For example, if your position only had
;; a black king on d8, your POSITION string would be:
;;
;; 3k////////
;;
;; For the three spaces (a, b and c file), the black king, and then
;; all the remaining ranks (which are all empty, so their spaces can
;; be ignored).
;;
;; The SIDE is w or b, to indicate whose move it is.
;;
;; CASTLING can contain K, Q, k or q, to signify whether the white or
;; black king can still castle on the king or queen side. EN-PASSANT
;; signifies the target sqaure of an en passant capture, such as "e3" or "a6".
;;
;; The starting chess position always looks like this:
;;
;; rnbqkbnr/pppppppp/////PPPPPPPP/RNBQKBNR/ w KQkq -
;;
;; And in "full" mode (where all spaces are accounted for):
;;
;; rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -
;;
;; It may also have the current game sequence appended, but this
;; relate to the game, not the position.
;;
(defconst chess-fen-regexp
"^\\([bnrqkpBNRQKP1-8]*/?\\)+ [bw] \\(-\\|[KQkq]+\\) \\(-\\|[1-8]\\)")
(defun chess-fen-to-pos (fen)
"Convert a FEN-like notation string to a chess position."
(assert (stringp fen))
(let ((i 0) (l (length fen))
(rank 0) (file 0) (c ?0)
(position (chess-pos-create t))
error (space-count 0))
(setq c (aref fen i))
(while (and (null error)
(/= c ? ) (< i l))
(cond
((= c ?/)
(setq file 0 rank (1+ rank)))
((and (>= c ?1) (<= c ?9))
(setq file (+ file (- c ?0))))
((memq (upcase c) '(?K ?Q ?B ?N ?R ?P))
(chess-pos-set-piece position (chess-rf-to-index rank file) c)
(setq file (1+ file)))
(t
(setq error t)))
(setq i (1+ i) c (aref fen i)))
(if (= (aref fen i) ? )
(setq i (1+ i)))
(if (memq (aref fen i) '(?b ?w))
(progn
(chess-pos-set-side-to-move position (= (aref fen i) ?w))
(setq i (+ i 2)))
(setq error t))
(setq c (aref fen i))
(while (and (null error)
(< space-count 2) (< i l))
(cond
((= c ?-))
((= c ? ) (setq space-count (1+ space-count)))
((= c ?K) (chess-pos-set-can-castle position ?K t))
((= c ?Q) (chess-pos-set-can-castle position ?Q t))
((= c ?k) (chess-pos-set-can-castle position ?k t))
((= c ?q) (chess-pos-set-can-castle position ?q t))
((and (>= c ?a) (<= c ?h))
(chess-pos-set-en-passant
position
(let ((target (chess-coord-to-index (substring fen i (+ i 2)))))
(chess-incr-index target (if (= (chess-index-rank target) 2)
1 (if (= (chess-index-rank target) 5)
-1 (setq error t) 0)) 0)))
(setq i (1+ i)))
(t
(setq error t)))
(setq i (1+ i) c (and (< i l) (aref fen i))))
(unless error
position)))
(defun chess-pos-to-fen (position &optional full)
"Convert a chess POSITION to FEN-like notation.
If FULL is non-nil, represent trailing spaces as well."
(assert (vectorp position))
(let ((blank 0) (str "") output)
(dotimes (rank 8)
(dotimes (file 8)
(let ((p (chess-pos-piece position (chess-rf-to-index rank file))))
(if (= p ? )
(setq blank (1+ blank))
(if (> blank 0)
(setq str (concat str (int-to-string blank)) blank 0))
(setq str (concat str (char-to-string p))))))
(if (and full (> blank 0))
(setq str (concat str (int-to-string blank))))
(if (< rank 7) (setq blank 0 str (concat str "/"))))
(setq str (if (chess-pos-side-to-move position)
(concat str " w ")
(concat str " b ")))
(mapc (lambda (castle)
(if (chess-pos-can-castle position castle)
(setq str (concat str (string castle)) output t)))
'(?K ?Q ?k ?q))
(if output
(setq str (concat str " "))
(setq str (concat str "- ")))
(let ((index (chess-pos-en-passant position)))
(if (and index
(let ((pawn (if (chess-pos-side-to-move position) ?P ?p)))
(or (and (chess-incr-index index 0 -1)
(eq (chess-pos-piece position (chess-incr-index
index 0 -1)) pawn))
(and (chess-incr-index index 0 1)
(eq (chess-pos-piece position (chess-incr-index
index 0 1)) pawn)))))
(concat str (chess-index-to-coord
(if (chess-pos-side-to-move position)
(chess-incr-index index -1 0)
(chess-incr-index index 1 0))))
(concat str "-")))))
(provide 'chess-fen)
;;; chess-fen.el ends here
|