]> code.delx.au - gnu-emacs/blobdiff - lisp/play/gomoku.el
(gnus-newsrc-file-version): Add defvar.
[gnu-emacs] / lisp / play / gomoku.el
index 7b2a9bd42d9e2f5f17330336414fc0090eacb8cb..e9f7a07abe9d349ef8da9687ea6ecbbbf04d122c 100644 (file)
@@ -1,6 +1,7 @@
 ;;; gomoku.el --- Gomoku game between you and Emacs
 
-;; Copyright (C) 1988, 1994, 1996, 2001 Free Software Foundation, Inc.
+;; Copyright (C) 1988, 1994, 1996, 2001, 2002, 2003, 2004,
+;;   2005 Free Software Foundation, Inc.
 
 ;; Author: Philippe Schnoebelen <phs@lsv.ens-cachan.fr>
 ;; Maintainer: FSF
@@ -21,8 +22,8 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
@@ -80,10 +81,13 @@ One useful value to include is `turn-on-font-lock' to highlight the pieces."
   :type 'hook
   :group 'gomoku)
 
-;;; 
+;;;
 ;;; CONSTANTS FOR BOARD
 ;;;
 
+(defconst gomoku-buffer-name "*Gomoku*"
+  "Name of the Gomoku buffer.")
+
 ;; You may change these values if you have a small screen or if the squares
 ;; look rectangular, but spacings SHOULD be at least 2 (MUST BE at least 1).
 
@@ -147,49 +151,40 @@ One useful value to include is `turn-on-font-lock' to highlight the pieces."
   (define-key gomoku-mode-map [mouse-2] 'gomoku-mouse-play)
   (define-key gomoku-mode-map [drag-mouse-2] 'gomoku-mouse-play)
 
-  (substitute-key-definition 'previous-line 'gomoku-move-up
-                            gomoku-mode-map (current-global-map))
-  (substitute-key-definition 'next-line 'gomoku-move-down
-                            gomoku-mode-map (current-global-map))
-  (substitute-key-definition 'beginning-of-line 'gomoku-beginning-of-line
-                            gomoku-mode-map (current-global-map))
-  (substitute-key-definition 'end-of-line 'gomoku-end-of-line
-                            gomoku-mode-map (current-global-map))
-  (substitute-key-definition 'undo 'gomoku-human-takes-back
-                            gomoku-mode-map (current-global-map))
-  (substitute-key-definition 'advertised-undo 'gomoku-human-takes-back
-                            gomoku-mode-map (current-global-map)))
+  (define-key gomoku-mode-map [remap previous-line] 'gomoku-move-up)
+  (define-key gomoku-mode-map [remap next-line] 'gomoku-move-down)
+  (define-key gomoku-mode-map [remap beginning-of-line] 'gomoku-beginning-of-line)
+  (define-key gomoku-mode-map [remap end-of-line] 'gomoku-end-of-line)
+  (define-key gomoku-mode-map [remap undo] 'gomoku-human-takes-back)
+  (define-key gomoku-mode-map [remap advertised-undo] 'gomoku-human-takes-back))
 
 (defvar gomoku-emacs-won ()
   "For making font-lock use the winner's face for the line.")
 
-(defcustom gomoku-font-lock-O-face
-  (if (display-color-p)
-      (list (facemenu-get-face 'fg:red) 'bold))
-  "*Face to use for Emacs' O."
-  :type '(repeat face)
+(defface gomoku-O
+    '((((class color)) (:foreground "red" :weight bold)))
+  "Face to use for Emacs' O."
   :group 'gomoku)
 
-(defcustom gomoku-font-lock-X-face
-  (if (display-color-p)
-      (list (facemenu-get-face 'fg:green) 'bold))
-  "*Face to use for your X."
-  :type '(repeat face)
+(defface gomoku-X
+    '((((class color)) (:foreground "green" :weight bold)))
+  "Face to use for your X."
   :group 'gomoku)
 
 (defvar gomoku-font-lock-keywords
-  '(("O" . gomoku-font-lock-O-face)
-    ("X" . gomoku-font-lock-X-face)
-    ("[-|/\\]" 0 (if gomoku-emacs-won
-                    gomoku-font-lock-O-face
-                  gomoku-font-lock-X-face)))
+  '(("O" . 'gomoku-O)
+    ("X" . 'gomoku-X)
+    ("[-|/\\]" 0 (if gomoku-emacs-won 'gomoku-O 'gomoku-X)))
   "*Font lock rules for Gomoku.")
 
 (put 'gomoku-mode 'front-sticky
      (put 'gomoku-mode 'rear-nonsticky '(intangible)))
 (put 'gomoku-mode 'intangible 1)
+;; This one is for when they set view-read-only to t: Gomoku cannot
+;; allow View Mode to be activated in its buffer.
+(put 'gomoku-mode 'mode-class 'special)
 
-(define-derived-mode gomoku-mode nil "Gomoku"
+(defun gomoku-mode ()
   "Major mode for playing Gomoku against Emacs.
 You and Emacs play in turn by marking a free square.  You mark it with X
 and Emacs marks it with O.  The winner is the first to get five contiguous
@@ -200,11 +195,17 @@ You play by moving the cursor over the square you choose and hitting \\[gomoku-h
 Other useful commands:
 \\{gomoku-mode-map}
 Entry to this mode calls the value of `gomoku-mode-hook' if that value
-is non-nil.  One interesting value is `turn-on-font-lock'."
+is non-nil."
+  (interactive)
+  (kill-all-local-variables)
+  (setq major-mode 'gomoku-mode
+       mode-name "Gomoku")
   (gomoku-display-statistics)
-  (set (make-local-variable 'font-lock-defaults)
-       '(gomoku-font-lock-keywords t))
-  (toggle-read-only t))
+  (use-local-map gomoku-mode-map)
+  (make-local-variable 'font-lock-defaults)
+  (setq font-lock-defaults '(gomoku-font-lock-keywords t))
+  (toggle-read-only t)
+  (run-mode-hooks 'gomoku-mode-hook))
 \f
 ;;;
 ;;; THE BOARD.
@@ -749,7 +750,17 @@ Use \\[describe-mode] for more info."
   (interactive (if current-prefix-arg
                   (list (prefix-numeric-value current-prefix-arg)
                         (eval (read-minibuffer "Height: ")))))
-  (gomoku-switch-to-window)
+  ;; gomoku-switch-to-window, but without the potential call to gomoku
+  ;; from gomoku-prompt-for-other-game.
+  (if (get-buffer gomoku-buffer-name)
+      (switch-to-buffer gomoku-buffer-name)
+    (when gomoku-game-in-progress
+      (setq gomoku-emacs-is-computing nil)
+      (gomoku-terminate-game 'crash-game)
+      (sit-for 4)
+      (or (y-or-n-p "Another game ") (error "Chicken !")))
+    (switch-to-buffer gomoku-buffer-name)
+    (gomoku-mode))
   (cond
    (gomoku-emacs-is-computing
     (gomoku-crash-game))
@@ -842,7 +853,7 @@ Use \\[describe-mode] for more info."
                     gomoku-square-height)
                  1)
             gomoku-board-height))))
-  
+
 (defun gomoku-mouse-play (click)
   "Play at the square where you click."
   (interactive "e")
@@ -936,10 +947,10 @@ If the game is finished, this command requests for another game."
   "Ask for another game, and start it."
   (if (y-or-n-p "Another game ")
       (gomoku gomoku-board-width gomoku-board-height)
-    (message "Chicken !")))
+    (error "Chicken !")))
 
 (defun gomoku-offer-a-draw ()
-  "Offer a draw and return T if Human accepted it."
+  "Offer a draw and return t if Human accepted it."
   (or (y-or-n-p "I offer you a draw. Do you accept it ")
       (not (setq gomoku-human-refused-draw t))))
 \f
@@ -1069,13 +1080,12 @@ If the game is finished, this command requests for another game."
 (defun gomoku-switch-to-window ()
   "Find or create the Gomoku buffer, and display it."
   (interactive)
-  (let ((buff (get-buffer "*Gomoku*")))
-    (if buff                           ; Buffer exists:
-       (switch-to-buffer buff)         ;   no problem.
-      (if gomoku-game-in-progress
-         (gomoku-crash-game))          ;   buffer has been killed or something
-      (switch-to-buffer "*Gomoku*")    ; Anyway, start anew.
-      (gomoku-mode))))
+  (if (get-buffer gomoku-buffer-name)       ; Buffer exists:
+      (switch-to-buffer gomoku-buffer-name) ;   no problem.
+    (if gomoku-game-in-progress
+        (gomoku-crash-game))            ;   buffer has been killed or something
+    (switch-to-buffer gomoku-buffer-name)   ; Anyway, start anew.
+    (gomoku-mode)))
 \f
 ;;;
 ;;; CROSSING WINNING QTUPLES.
@@ -1087,14 +1097,14 @@ If the game is finished, this command requests for another game."
 ;; who won. The solution is to scan the board along all four directions.
 
 (defun gomoku-find-filled-qtuple (square value)
-  "Return T if SQUARE belongs to a qtuple filled with VALUEs."
+  "Return t if SQUARE belongs to a qtuple filled with VALUEs."
   (or (gomoku-check-filled-qtuple square value 1 0)
       (gomoku-check-filled-qtuple square value 0 1)
       (gomoku-check-filled-qtuple square value 1 1)
       (gomoku-check-filled-qtuple square value -1 1)))
 
 (defun gomoku-check-filled-qtuple (square value dx dy)
-  "Return T if SQUARE belongs to a qtuple filled  with VALUEs along DX, DY."
+  "Return t if SQUARE belongs to a qtuple filled  with VALUEs along DX, DY."
   (let ((a 0) (b 0)
        (left square) (right square)
        (depl (gomoku-xy-to-index dx dy)))
@@ -1152,13 +1162,17 @@ If the game is finished, this command requests for another game."
   "Move point down one row on the Gomoku board."
   (interactive)
   (if (< (gomoku-point-y) gomoku-board-height)
-      (next-line gomoku-square-height)))
+      (let ((column (current-column)))
+       (forward-line gomoku-square-height)
+       (move-to-column column))))
 
 (defun gomoku-move-up ()
   "Move point up one row on the Gomoku board."
   (interactive)
   (if (> (gomoku-point-y) 1)
-      (previous-line gomoku-square-height)))
+      (let ((column (current-column)))
+       (forward-line (- 1 gomoku-square-height))
+       (move-to-column column))))
 
 (defun gomoku-move-ne ()
   "Move point North East on the Gomoku board."
@@ -1197,4 +1211,5 @@ If the game is finished, this command requests for another game."
 
 (provide 'gomoku)
 
+;;; arch-tag: b1b8205e-77fc-4597-b373-3ea2c04311eb
 ;;; gomoku.el ends here