Mercurial > emacs
comparison lisp/play/gomoku.el @ 88155:d7ddb3e565de
sync with trunk
author | Henrik Enberg <henrik.enberg@telia.com> |
---|---|
date | Mon, 16 Jan 2006 00:03:54 +0000 |
parents | 0d8b17d428b5 |
children |
comparison
equal
deleted
inserted
replaced
88154:8ce476d3ba36 | 88155:d7ddb3e565de |
---|---|
1 ;;; gomoku.el --- Gomoku game between you and Emacs | 1 ;;; gomoku.el --- Gomoku game between you and Emacs |
2 | 2 |
3 ;; Copyright (C) 1988, 1994, 1996, 2001, 2003 Free Software Foundation, Inc. | 3 ;; Copyright (C) 1988, 1994, 1996, 2001, 2002, 2003, 2004, |
4 ;; 2005 Free Software Foundation, Inc. | |
4 | 5 |
5 ;; Author: Philippe Schnoebelen <phs@lsv.ens-cachan.fr> | 6 ;; Author: Philippe Schnoebelen <phs@lsv.ens-cachan.fr> |
6 ;; Maintainer: FSF | 7 ;; Maintainer: FSF |
7 ;; Adapted-By: ESR, Daniel Pfeiffer <occitan@esperanto.org> | 8 ;; Adapted-By: ESR, Daniel Pfeiffer <occitan@esperanto.org> |
8 ;; Keywords: games | 9 ;; Keywords: games |
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 ;; GNU General Public License for more details. | 21 ;; GNU General Public License for more details. |
21 | 22 |
22 ;; You should have received a copy of the GNU General Public License | 23 ;; You should have received a copy of the GNU General Public License |
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the | 24 ;; along with GNU Emacs; see the file COPYING. If not, write to the |
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 25 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
25 ;; Boston, MA 02111-1307, USA. | 26 ;; Boston, MA 02110-1301, USA. |
26 | 27 |
27 ;;; Commentary: | 28 ;;; Commentary: |
28 | 29 |
29 ;; RULES: | 30 ;; RULES: |
30 ;; | 31 ;; |
82 | 83 |
83 ;;; | 84 ;;; |
84 ;;; CONSTANTS FOR BOARD | 85 ;;; CONSTANTS FOR BOARD |
85 ;;; | 86 ;;; |
86 | 87 |
88 (defconst gomoku-buffer-name "*Gomoku*" | |
89 "Name of the Gomoku buffer.") | |
90 | |
87 ;; You may change these values if you have a small screen or if the squares | 91 ;; You may change these values if you have a small screen or if the squares |
88 ;; look rectangular, but spacings SHOULD be at least 2 (MUST BE at least 1). | 92 ;; look rectangular, but spacings SHOULD be at least 2 (MUST BE at least 1). |
89 | 93 |
90 (defconst gomoku-square-width 4 | 94 (defconst gomoku-square-width 4 |
91 "*Horizontal spacing between squares on the Gomoku board.") | 95 "*Horizontal spacing between squares on the Gomoku board.") |
155 (define-key gomoku-mode-map [remap advertised-undo] 'gomoku-human-takes-back)) | 159 (define-key gomoku-mode-map [remap advertised-undo] 'gomoku-human-takes-back)) |
156 | 160 |
157 (defvar gomoku-emacs-won () | 161 (defvar gomoku-emacs-won () |
158 "For making font-lock use the winner's face for the line.") | 162 "For making font-lock use the winner's face for the line.") |
159 | 163 |
160 (defface gomoku-font-lock-O-face | 164 (defface gomoku-O |
161 '((((class color)) (:foreground "red" :weight bold))) | 165 '((((class color)) (:foreground "red" :weight bold))) |
162 "Face to use for Emacs' O." | 166 "Face to use for Emacs' O." |
163 :group 'gomoku) | 167 :group 'gomoku) |
164 | 168 |
165 (defface gomoku-font-lock-X-face | 169 (defface gomoku-X |
166 '((((class color)) (:foreground "green" :weight bold))) | 170 '((((class color)) (:foreground "green" :weight bold))) |
167 "Face to use for your X." | 171 "Face to use for your X." |
168 :group 'gomoku) | 172 :group 'gomoku) |
169 | 173 |
170 (defvar gomoku-font-lock-keywords | 174 (defvar gomoku-font-lock-keywords |
171 '(("O" . 'gomoku-font-lock-O-face) | 175 '(("O" . 'gomoku-O) |
172 ("X" . 'gomoku-font-lock-X-face) | 176 ("X" . 'gomoku-X) |
173 ("[-|/\\]" 0 (if gomoku-emacs-won | 177 ("[-|/\\]" 0 (if gomoku-emacs-won 'gomoku-O 'gomoku-X))) |
174 'gomoku-font-lock-O-face | |
175 'gomoku-font-lock-X-face))) | |
176 "*Font lock rules for Gomoku.") | 178 "*Font lock rules for Gomoku.") |
177 | 179 |
178 (put 'gomoku-mode 'front-sticky | 180 (put 'gomoku-mode 'front-sticky |
179 (put 'gomoku-mode 'rear-nonsticky '(intangible))) | 181 (put 'gomoku-mode 'rear-nonsticky '(intangible))) |
180 (put 'gomoku-mode 'intangible 1) | 182 (put 'gomoku-mode 'intangible 1) |
191 You play by moving the cursor over the square you choose and hitting \\[gomoku-human-plays]. | 193 You play by moving the cursor over the square you choose and hitting \\[gomoku-human-plays]. |
192 | 194 |
193 Other useful commands: | 195 Other useful commands: |
194 \\{gomoku-mode-map} | 196 \\{gomoku-mode-map} |
195 Entry to this mode calls the value of `gomoku-mode-hook' if that value | 197 Entry to this mode calls the value of `gomoku-mode-hook' if that value |
196 is non-nil. One interesting value is `turn-on-font-lock'." | 198 is non-nil." |
197 (interactive) | 199 (interactive) |
200 (kill-all-local-variables) | |
198 (setq major-mode 'gomoku-mode | 201 (setq major-mode 'gomoku-mode |
199 mode-name "Gomoku") | 202 mode-name "Gomoku") |
200 (gomoku-display-statistics) | 203 (gomoku-display-statistics) |
201 (use-local-map gomoku-mode-map) | 204 (use-local-map gomoku-mode-map) |
202 (make-local-variable 'font-lock-defaults) | 205 (make-local-variable 'font-lock-defaults) |
203 (setq font-lock-defaults '(gomoku-font-lock-keywords t)) | 206 (setq font-lock-defaults '(gomoku-font-lock-keywords t)) |
204 (toggle-read-only t) | 207 (toggle-read-only t) |
205 (run-hooks 'gomoku-mode-hook)) | 208 (run-mode-hooks 'gomoku-mode-hook)) |
206 | 209 |
207 ;;; | 210 ;;; |
208 ;;; THE BOARD. | 211 ;;; THE BOARD. |
209 ;;; | 212 ;;; |
210 | 213 |
666 ((eq result 'emacs-won) | 669 ((eq result 'emacs-won) |
667 (setq gomoku-number-of-emacs-wins (1+ gomoku-number-of-emacs-wins)) | 670 (setq gomoku-number-of-emacs-wins (1+ gomoku-number-of-emacs-wins)) |
668 (cond ((< gomoku-number-of-moves 20) | 671 (cond ((< gomoku-number-of-moves 20) |
669 "This was a REALLY QUICK win.") | 672 "This was a REALLY QUICK win.") |
670 (gomoku-human-refused-draw | 673 (gomoku-human-refused-draw |
671 "I won... Too bad you refused my offer of a draw !") | 674 "I won... Too bad you refused my offer of a draw!") |
672 (gomoku-human-took-back | 675 (gomoku-human-took-back |
673 "I won... Taking moves back will not help you !") | 676 "I won... Taking moves back will not help you!") |
674 ((not gomoku-emacs-played-first) | 677 ((not gomoku-emacs-played-first) |
675 "I won... Playing first did not help you much !") | 678 "I won... Playing first did not help you much!") |
676 ((and (zerop gomoku-number-of-human-wins) | 679 ((and (zerop gomoku-number-of-human-wins) |
677 (zerop gomoku-number-of-draws) | 680 (zerop gomoku-number-of-draws) |
678 (> gomoku-number-of-emacs-wins 1)) | 681 (> gomoku-number-of-emacs-wins 1)) |
679 "I'm becoming tired of winning...") | 682 "I'm becoming tired of winning...") |
680 ("I won."))) | 683 ("I won."))) |
683 (concat "OK, you won this one." | 686 (concat "OK, you won this one." |
684 (cond | 687 (cond |
685 (gomoku-human-took-back | 688 (gomoku-human-took-back |
686 " I, for one, never take my moves back...") | 689 " I, for one, never take my moves back...") |
687 (gomoku-emacs-played-first | 690 (gomoku-emacs-played-first |
688 ".. so what ?") | 691 ".. so what?") |
689 (" Now, let me play first just once.")))) | 692 (" Now, let me play first just once.")))) |
690 ((eq result 'human-resigned) | 693 ((eq result 'human-resigned) |
691 (setq gomoku-number-of-emacs-wins (1+ gomoku-number-of-emacs-wins)) | 694 (setq gomoku-number-of-emacs-wins (1+ gomoku-number-of-emacs-wins)) |
692 "So you resign. That's just one more win for me.") | 695 "So you resign. That's just one more win for me.") |
693 ((eq result 'nobody-won) | 696 ((eq result 'nobody-won) |
745 | 748 |
746 Use \\[describe-mode] for more info." | 749 Use \\[describe-mode] for more info." |
747 (interactive (if current-prefix-arg | 750 (interactive (if current-prefix-arg |
748 (list (prefix-numeric-value current-prefix-arg) | 751 (list (prefix-numeric-value current-prefix-arg) |
749 (eval (read-minibuffer "Height: "))))) | 752 (eval (read-minibuffer "Height: "))))) |
750 (gomoku-switch-to-window) | 753 ;; gomoku-switch-to-window, but without the potential call to gomoku |
754 ;; from gomoku-prompt-for-other-game. | |
755 (if (get-buffer gomoku-buffer-name) | |
756 (switch-to-buffer gomoku-buffer-name) | |
757 (when gomoku-game-in-progress | |
758 (setq gomoku-emacs-is-computing nil) | |
759 (gomoku-terminate-game 'crash-game) | |
760 (sit-for 4) | |
761 (or (y-or-n-p "Another game? ") (error "Chicken!"))) | |
762 (switch-to-buffer gomoku-buffer-name) | |
763 (gomoku-mode)) | |
751 (cond | 764 (cond |
752 (gomoku-emacs-is-computing | 765 (gomoku-emacs-is-computing |
753 (gomoku-crash-game)) | 766 (gomoku-crash-game)) |
754 ((or (not gomoku-game-in-progress) | 767 ((or (not gomoku-game-in-progress) |
755 (<= gomoku-number-of-moves 2)) | 768 (<= gomoku-number-of-moves 2)) |
764 ((> n max-width) | 777 ((> n max-width) |
765 (error "I cannot display %d columns in that window" n))) | 778 (error "I cannot display %d columns in that window" n))) |
766 (if (and (> m max-height) | 779 (if (and (> m max-height) |
767 (not (eq m gomoku-saved-board-height)) | 780 (not (eq m gomoku-saved-board-height)) |
768 ;; Use EQ because SAVED-BOARD-HEIGHT may be nil | 781 ;; Use EQ because SAVED-BOARD-HEIGHT may be nil |
769 (not (y-or-n-p (format "Do you really want %d rows " m)))) | 782 (not (y-or-n-p (format "Do you really want %d rows? " m)))) |
770 (setq m max-height))) | 783 (setq m max-height))) |
771 (message "One moment, please...") | 784 (message "One moment, please...") |
772 (gomoku-start-game n m) | 785 (gomoku-start-game n m) |
773 (if (y-or-n-p "Do you allow me to play first ") | 786 (if (y-or-n-p "Do you allow me to play first? ") |
774 (gomoku-emacs-plays) | 787 (gomoku-emacs-plays) |
775 (gomoku-prompt-for-move))) | 788 (gomoku-prompt-for-move))) |
776 ((y-or-n-p "Shall we continue our game ") | 789 ((y-or-n-p "Shall we continue our game? ") |
777 (gomoku-prompt-for-move)) | 790 (gomoku-prompt-for-move)) |
778 (t | 791 (t |
779 (gomoku-human-resigns)))) | 792 (gomoku-human-resigns)))) |
780 | 793 |
781 (defun gomoku-emacs-plays () | 794 (defun gomoku-emacs-plays () |
860 (gomoku-prompt-for-other-game)) | 873 (gomoku-prompt-for-other-game)) |
861 (t | 874 (t |
862 (let (square score) | 875 (let (square score) |
863 (setq square (gomoku-point-square)) | 876 (setq square (gomoku-point-square)) |
864 (cond ((null square) | 877 (cond ((null square) |
865 (error "Your point is not on a square. Retry !")) | 878 (error "Your point is not on a square. Retry!")) |
866 ((not (zerop (aref gomoku-board square))) | 879 ((not (zerop (aref gomoku-board square))) |
867 (error "Your point is not on a free square. Retry !")) | 880 (error "Your point is not on a free square. Retry!")) |
868 (t | 881 (t |
869 (setq score (aref gomoku-score-table square)) | 882 (setq score (aref gomoku-score-table square)) |
870 (gomoku-play-move square 1) | 883 (gomoku-play-move square 1) |
871 (cond ((and (>= score gomoku-loosing-threshold) | 884 (cond ((and (>= score gomoku-loosing-threshold) |
872 ;; Just testing SCORE > THRESHOLD is not enough for | 885 ;; Just testing SCORE > THRESHOLD is not enough for |
887 ((not gomoku-game-in-progress) | 900 ((not gomoku-game-in-progress) |
888 (message "Too late for taking back...") | 901 (message "Too late for taking back...") |
889 (sit-for 4) | 902 (sit-for 4) |
890 (gomoku-prompt-for-other-game)) | 903 (gomoku-prompt-for-other-game)) |
891 ((zerop gomoku-number-of-human-moves) | 904 ((zerop gomoku-number-of-human-moves) |
892 (message "You have not played yet... Your move ?")) | 905 (message "You have not played yet... Your move?")) |
893 (t | 906 (t |
894 (message "One moment, please...") | 907 (message "One moment, please...") |
895 ;; It is possible for the user to let Emacs play several consecutive | 908 ;; It is possible for the user to let Emacs play several consecutive |
896 ;; moves, so that the best way to know when to stop taking back moves is | 909 ;; moves, so that the best way to know when to stop taking back moves is |
897 ;; to count the number of human moves: | 910 ;; to count the number of human moves: |
908 (cond | 921 (cond |
909 (gomoku-emacs-is-computing | 922 (gomoku-emacs-is-computing |
910 (gomoku-crash-game)) | 923 (gomoku-crash-game)) |
911 ((not gomoku-game-in-progress) | 924 ((not gomoku-game-in-progress) |
912 (message "There is no game in progress")) | 925 (message "There is no game in progress")) |
913 ((y-or-n-p "You mean, you resign ") | 926 ((y-or-n-p "You mean, you resign? ") |
914 (gomoku-terminate-game 'human-resigned)) | 927 (gomoku-terminate-game 'human-resigned)) |
915 ((y-or-n-p "You mean, we continue ") | 928 ((y-or-n-p "You mean, we continue? ") |
916 (gomoku-prompt-for-move)) | 929 (gomoku-prompt-for-move)) |
917 (t | 930 (t |
918 (gomoku-terminate-game 'human-resigned)))) ; OK. Accept it | 931 (gomoku-terminate-game 'human-resigned)))) ; OK. Accept it |
919 | 932 |
920 ;;; | 933 ;;; |
922 ;;; | 935 ;;; |
923 | 936 |
924 (defun gomoku-prompt-for-move () | 937 (defun gomoku-prompt-for-move () |
925 "Display a message asking for Human's move." | 938 "Display a message asking for Human's move." |
926 (message (if (zerop gomoku-number-of-human-moves) | 939 (message (if (zerop gomoku-number-of-human-moves) |
927 "Your move ? (move to a free square and hit X, RET ...)" | 940 "Your move? (move to a free square and hit X, RET ...)" |
928 "Your move ?")) | 941 "Your move?")) |
929 ;; This may seem silly, but if one omits the following line (or a similar | 942 ;; This may seem silly, but if one omits the following line (or a similar |
930 ;; one), the cursor may very well go to some place where POINT is not. | 943 ;; one), the cursor may very well go to some place where POINT is not. |
931 (save-excursion (set-buffer (other-buffer)))) | 944 (save-excursion (set-buffer (other-buffer)))) |
932 | 945 |
933 (defun gomoku-prompt-for-other-game () | 946 (defun gomoku-prompt-for-other-game () |
934 "Ask for another game, and start it." | 947 "Ask for another game, and start it." |
935 (if (y-or-n-p "Another game ") | 948 (if (y-or-n-p "Another game? ") |
936 (gomoku gomoku-board-width gomoku-board-height) | 949 (gomoku gomoku-board-width gomoku-board-height) |
937 (message "Chicken !"))) | 950 (error "Chicken!"))) |
938 | 951 |
939 (defun gomoku-offer-a-draw () | 952 (defun gomoku-offer-a-draw () |
940 "Offer a draw and return t if Human accepted it." | 953 "Offer a draw and return t if Human accepted it." |
941 (or (y-or-n-p "I offer you a draw. Do you accept it ") | 954 (or (y-or-n-p "I offer you a draw. Do you accept it? ") |
942 (not (setq gomoku-human-refused-draw t)))) | 955 (not (setq gomoku-human-refused-draw t)))) |
943 | 956 |
944 ;;; | 957 ;;; |
945 ;;; DISPLAYING THE BOARD. | 958 ;;; DISPLAYING THE BOARD. |
946 ;;; | 959 ;;; |
1065 (force-mode-line-update)) | 1078 (force-mode-line-update)) |
1066 | 1079 |
1067 (defun gomoku-switch-to-window () | 1080 (defun gomoku-switch-to-window () |
1068 "Find or create the Gomoku buffer, and display it." | 1081 "Find or create the Gomoku buffer, and display it." |
1069 (interactive) | 1082 (interactive) |
1070 (let ((buff (get-buffer "*Gomoku*"))) | 1083 (if (get-buffer gomoku-buffer-name) ; Buffer exists: |
1071 (if buff ; Buffer exists: | 1084 (switch-to-buffer gomoku-buffer-name) ; no problem. |
1072 (switch-to-buffer buff) ; no problem. | 1085 (if gomoku-game-in-progress |
1073 (if gomoku-game-in-progress | 1086 (gomoku-crash-game)) ; buffer has been killed or something |
1074 (gomoku-crash-game)) ; buffer has been killed or something | 1087 (switch-to-buffer gomoku-buffer-name) ; Anyway, start anew. |
1075 (switch-to-buffer "*Gomoku*") ; Anyway, start anew. | 1088 (gomoku-mode))) |
1076 (gomoku-mode)))) | |
1077 | 1089 |
1078 ;;; | 1090 ;;; |
1079 ;;; CROSSING WINNING QTUPLES. | 1091 ;;; CROSSING WINNING QTUPLES. |
1080 ;;; | 1092 ;;; |
1081 | 1093 |
1197 (move-to-column (+ gomoku-x-offset | 1209 (move-to-column (+ gomoku-x-offset |
1198 (* gomoku-square-width (1- gomoku-board-width))))) | 1210 (* gomoku-square-width (1- gomoku-board-width))))) |
1199 | 1211 |
1200 (provide 'gomoku) | 1212 (provide 'gomoku) |
1201 | 1213 |
1214 ;;; arch-tag: b1b8205e-77fc-4597-b373-3ea2c04311eb | |
1202 ;;; gomoku.el ends here | 1215 ;;; gomoku.el ends here |