summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chess-announce.el76
-rw-r--r--chess.el13
2 files changed, 86 insertions, 3 deletions
diff --git a/chess-announce.el b/chess-announce.el
new file mode 100644
index 0000000..1d962d7
--- /dev/null
+++ b/chess-announce.el
@@ -0,0 +1,76 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Scheme to verbally announce moves
+;;
+;; $Revision$
+
+(require 'chess-game)
+
+(defvar chess-announce-names
+ '((?q . "queen")
+ (?k . "king")
+ (?b . "bishop")
+ (?n . "knight")
+ (?r . "rook")
+ (?p . "pawn")))
+
+(defvar chess-announce-function 'chess-announce-festival
+ "The function to call for announcing moves audially.
+It is passed the string of English text to announce.")
+
+(defun chess-announce-for-game (game perspective)
+ "Announce moves in GAME on behalf of PERSPECTIVE.
+This means that if PERSPECTIVE is t (for white), only black's moves
+will be announced."
+ (chess-game-add-hook game 'chess-announce-event-handler perspective))
+
+(defun chess-announce-change-perspective (game perspective)
+ "Change the announce perspective in GAME to PERSPECTIVE."
+ (let ((cell (assq 'chess-announce-event-handler (chess-game-hooks game))))
+ (if cell
+ (setcdr cell perspective))))
+
+(defun chess-announce-event-handler (game perspective event &rest args)
+ "This display module presents a standard chessboard.
+See `chess-display-type' for the different kinds of displays."
+ (cond
+ ((memq event '(move game-over))
+ (let* ((ply (chess-game-ply game (1- (chess-game-index game))))
+ (pos (chess-ply-pos ply)))
+ (unless (eq perspective (chess-pos-side-to-move pos))
+ (let* ((changes (chess-ply-changes ply))
+ (source (car changes))
+ (target (cadr changes))
+ (s-piece (chess-pos-piece pos source))
+ (t-piece (chess-pos-piece pos target))
+ text)
+ (cond
+ ((memq :castle changes)
+ (setq text "kingside castle"))
+ ((memq :long-castle changes)
+ (setq text "queenside castle"))
+ ((= t-piece ? )
+ (setq text (concat (cdr (assq (downcase s-piece)
+ chess-announce-names))
+ " to "
+ (chess-index-to-coord target))))
+ (t
+ (setq text (concat (cdr (assq (downcase s-piece)
+ chess-announce-names))
+ " takes at "
+ (chess-index-to-coord target)))))
+ (if (memq :check changes)
+ (setq text (concat text ", check")))
+ (if (memq :checkmate changes)
+ (setq text (concat text ", checkmate")))
+ (if (memq :stalemate changes)
+ (setq text (concat text ", stalemate")))
+
+ (funcall chess-announce-function text)))))))
+
+(defun chess-announce-festival (text)
+ "Announce the given text using festival."
+ (let ((proc (start-process "announce" nil "/usr/bin/festival" "--tts")))
+ (when (and proc (eq (process-status proc) 'run))
+ (process-send-string proc (concat text "\n"))
+ (process-send-eof proc))))
diff --git a/chess.el b/chess.el
index a5066cd..b557c65 100644
--- a/chess.el
+++ b/chess.el
@@ -98,6 +98,11 @@ a0 243
"Default engine to be used when starting a chess session."
:type 'sexp
:group 'chess)
+(defcustom chess-announce-moves (and (executable-find "festival") t)
+ "If non-nil, announce your opponent's moves verbally."
+minibuffer, which works well for Emacspeak users."
+ :type 'boolean
+ :group 'chess)
(defun chess (&optional arg)
"Start a game of chess."
@@ -112,9 +117,11 @@ a0 243
(intern (or (read-string "Engine module to play against: ")
"chess-none"))
chess-default-engine)))
- (if (and engine-module
- (require engine-module nil t))
- (chess-engine-set-game (chess-engine-create engine-module) game)))))
+ (when (and engine-module
+ (require engine-module nil t))
+ (chess-engine-set-game (chess-engine-create engine-module) game)
+ (if chess-announce-moves
+ (chess-announce-for-game game t))))))
(cons display engine)))
;;;###autoload