aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard M. Stallman1996-04-05 19:38:42 +0000
committerRichard M. Stallman1996-04-05 19:38:42 +0000
commitd7ab27189363acf15d7676085d552474435d7571 (patch)
tree816cbab0954c4ec8d5a932601366a6c9da595859
parentcb2e51f84b4bc68f1493da1b9883143409058140 (diff)
downloademacs-d7ab27189363acf15d7676085d552474435d7571.tar.gz
emacs-d7ab27189363acf15d7676085d552474435d7571.zip
(gomoku-click): Position on nearest square. Adapt keymap accordingly.
(gomoku-mouse-play): Use it to play nearest to mouse click. (gomoku-terminate-game): Factorize messages. (gomoku): Allow interactive passing of board size. Don't make a fuss about restarting a game that hasn't progressed. (gomoku-offer-a-draw): Give user the choice it pretended to give. (gomoku-point-x): Deleted function. (gomoku-point-y, gomoku-point-square): Simplified because point is always on a square. (gomoku-goto-xy, gomoku-plot-square): Fix line count due to intangible newlines. (gomoku-init-display): Once again fairly fast due to minimization of characters in buffer and text-property operations. Cursor cannot be be off a square. (gomoku-display-statistics): Simplified equivalently. (gomoku-winning-qtuple-beg, gomoku-winning-qtuple-end) (gomoku-winning-qtuple-dx, gomoku-winning-qtuple-dy): Pseudo variables only used for non-functional argument passing deleted. (gomoku-cross-winning-qtuple): Accordingly deleted function and (gomoku-check-filled-qtuple): Accordingly adapted. (gomoku-cross-qtuple): Don't be confused by tabs. (gomoku-move-down, gomoku-move-up): Simplified because point is always on square. (gomoku-beginning-of-line, gomoku-end-of-line): New commands necessary because intangible newlines perverted these.
-rw-r--r--lisp/play/gomoku.el392
1 files changed, 206 insertions, 186 deletions
diff --git a/lisp/play/gomoku.el b/lisp/play/gomoku.el
index 104f3989a40..332d1cedd9c 100644
--- a/lisp/play/gomoku.el
+++ b/lisp/play/gomoku.el
@@ -3,7 +3,7 @@
3;; Copyright (C) 1988, 1994, 1996 Free Software Foundation, Inc. 3;; Copyright (C) 1988, 1994, 1996 Free Software Foundation, Inc.
4 4
5;; Author: Philippe Schnoebelen <phs@lifia.imag.fr> 5;; Author: Philippe Schnoebelen <phs@lifia.imag.fr>
6;; Adapted-By: ESR 6;; Adapted-By: ESR, Daniel.Pfeiffer@Informatik.START.dbp.de
7;; Keywords: games 7;; Keywords: games
8 8
9;; This file is part of GNU Emacs. 9;; This file is part of GNU Emacs.
@@ -101,7 +101,6 @@
101 (define-key gomoku-mode-map "\C-p" 'gomoku-move-up) ; C-p 101 (define-key gomoku-mode-map "\C-p" 'gomoku-move-up) ; C-p
102 102
103 ;; Key bindings for entering Human moves. 103 ;; Key bindings for entering Human moves.
104 ;; If you have a mouse, you may also bind some mouse click ...
105 (define-key gomoku-mode-map "X" 'gomoku-human-plays) ; X 104 (define-key gomoku-mode-map "X" 'gomoku-human-plays) ; X
106 (define-key gomoku-mode-map "x" 'gomoku-human-plays) ; x 105 (define-key gomoku-mode-map "x" 'gomoku-human-plays) ; x
107 (define-key gomoku-mode-map " " 'gomoku-human-plays) ; SPC 106 (define-key gomoku-mode-map " " 'gomoku-human-plays) ; SPC
@@ -112,13 +111,22 @@
112 (define-key gomoku-mode-map "\C-c\C-e" 'gomoku-emacs-plays) ; C-c C-e 111 (define-key gomoku-mode-map "\C-c\C-e" 'gomoku-emacs-plays) ; C-c C-e
113 112
114 (define-key gomoku-mode-map [kp-enter] 'gomoku-human-plays) 113 (define-key gomoku-mode-map [kp-enter] 'gomoku-human-plays)
115 (define-key gomoku-mode-map [mouse-2] 'gomoku-click)
116 (define-key gomoku-mode-map [insert] 'gomoku-human-plays) 114 (define-key gomoku-mode-map [insert] 'gomoku-human-plays)
115 (define-key gomoku-mode-map [down-mouse-1] 'gomoku-click)
116 (define-key gomoku-mode-map [drag-mouse-1] 'gomoku-click)
117 (define-key gomoku-mode-map [mouse-1] 'gomoku-click)
118 (define-key gomoku-mode-map [down-mouse-2] 'gomoku-click)
119 (define-key gomoku-mode-map [mouse-2] 'gomoku-mouse-play)
120 (define-key gomoku-mode-map [drag-mouse-2] 'gomoku-mouse-play)
117 121
118 (substitute-key-definition 'previous-line 'gomoku-move-up 122 (substitute-key-definition 'previous-line 'gomoku-move-up
119 gomoku-mode-map (current-global-map)) 123 gomoku-mode-map (current-global-map))
120 (substitute-key-definition 'next-line 'gomoku-move-down 124 (substitute-key-definition 'next-line 'gomoku-move-down
121 gomoku-mode-map (current-global-map)) 125 gomoku-mode-map (current-global-map))
126 (substitute-key-definition 'beginning-of-line 'gomoku-beginning-of-line
127 gomoku-mode-map (current-global-map))
128 (substitute-key-definition 'end-of-line 'gomoku-end-of-line
129 gomoku-mode-map (current-global-map))
122 (substitute-key-definition 'undo 'gomoku-human-takes-back 130 (substitute-key-definition 'undo 'gomoku-human-takes-back
123 gomoku-mode-map (current-global-map)) 131 gomoku-mode-map (current-global-map))
124 (substitute-key-definition 'advertised-undo 'gomoku-human-takes-back 132 (substitute-key-definition 'advertised-undo 'gomoku-human-takes-back
@@ -147,6 +155,7 @@
147 155
148(put 'gomoku-mode 'front-sticky 156(put 'gomoku-mode 'front-sticky
149 (put 'gomoku-mode 'rear-nonsticky '(intangible))) 157 (put 'gomoku-mode 'rear-nonsticky '(intangible)))
158(put 'gomoku-mode 'intangible 1)
150 159
151(defun gomoku-mode () 160(defun gomoku-mode ()
152 "Major mode for playing Gomoku against Emacs. 161 "Major mode for playing Gomoku against Emacs.
@@ -627,66 +636,58 @@ that DVAL has been added on SQUARE."
627 636
628(defun gomoku-terminate-game (result) 637(defun gomoku-terminate-game (result)
629 "Terminate the current game with RESULT." 638 "Terminate the current game with RESULT."
630 (let (message) 639 (message
631 (cond 640 (cond
632 ((eq result 'emacs-won) 641 ((eq result 'emacs-won)
633 (setq gomoku-number-of-emacs-wins (1+ gomoku-number-of-emacs-wins)) 642 (setq gomoku-number-of-emacs-wins (1+ gomoku-number-of-emacs-wins))
634 (setq message 643 (cond ((< gomoku-number-of-moves 20)
635 (cond ((< gomoku-number-of-moves 20) 644 "This was a REALLY QUICK win.")
636 "This was a REALLY QUICK win.") 645 (gomoku-human-refused-draw
637 (gomoku-human-refused-draw 646 "I won... Too bad you refused my offer of a draw !")
638 "I won... Too bad you refused my offer of a draw !") 647 (gomoku-human-took-back
639 (gomoku-human-took-back 648 "I won... Taking moves back will not help you !")
640 "I won... Taking moves back will not help you !") 649 ((not gomoku-emacs-played-first)
641 ((not gomoku-emacs-played-first) 650 "I won... Playing first did not help you much !")
642 "I won... Playing first did not help you much !") 651 ((and (zerop gomoku-number-of-human-wins)
643 ((and (zerop gomoku-number-of-human-wins) 652 (zerop gomoku-number-of-draws)
644 (zerop gomoku-number-of-draws) 653 (> gomoku-number-of-emacs-wins 1))
645 (> gomoku-number-of-emacs-wins 1)) 654 "I'm becoming tired of winning...")
646 "I'm becoming tired of winning...") 655 ("I won.")))
647 (t 656 ((eq result 'human-won)
648 "I won.")))) 657 (setq gomoku-number-of-human-wins (1+ gomoku-number-of-human-wins))
649 ((eq result 'human-won) 658 (concat "OK, you won this one."
650 (setq gomoku-number-of-human-wins (1+ gomoku-number-of-human-wins)) 659 (cond
651 (setq message 660 (gomoku-human-took-back
652 (cond 661 " I, for one, never take my moves back...")
653 (gomoku-human-took-back 662 (gomoku-emacs-played-first
654 "OK, you won this one. I, for one, never take my moves back...") 663 ".. so what ?")
655 (gomoku-emacs-played-first 664 (" Now, let me play first just once."))))
656 "OK, you won this one... so what ?") 665 ((eq result 'human-resigned)
657 (t 666 (setq gomoku-number-of-emacs-wins (1+ gomoku-number-of-emacs-wins))
658 "OK, you won this one. Now, let me play first just once.")))) 667 "So you resign. That's just one more win for me.")
659 ((eq result 'human-resigned) 668 ((eq result 'nobody-won)
660 (setq gomoku-number-of-emacs-wins (1+ gomoku-number-of-emacs-wins)) 669 (setq gomoku-number-of-draws (1+ gomoku-number-of-draws))
661 (setq message "So you resign. That's just one more win for me.")) 670 (concat "This is a draw. "
662 ((eq result 'nobody-won) 671 (cond
663 (setq gomoku-number-of-draws (1+ gomoku-number-of-draws)) 672 (gomoku-human-took-back
664 (setq message 673 "I, for one, never take my moves back...")
665 (cond 674 (gomoku-emacs-played-first
666 (gomoku-human-took-back 675 "Just chance, I guess.")
667 "This is a draw. I, for one, never take my moves back...") 676 ("Now, let me play first just once."))))
668 (gomoku-emacs-played-first 677 ((eq result 'draw-agreed)
669 "This is a draw. Just chance, I guess.") 678 (setq gomoku-number-of-draws (1+ gomoku-number-of-draws))
670 (t 679 (concat "Draw agreed. "
671 "This is a draw. Now, let me play first just once.")))) 680 (cond
672 ((eq result 'draw-agreed) 681 (gomoku-human-took-back
673 (setq gomoku-number-of-draws (1+ gomoku-number-of-draws)) 682 "I, for one, never take my moves back...")
674 (setq message 683 (gomoku-emacs-played-first
675 (cond 684 "You were lucky.")
676 (gomoku-human-took-back 685 ("Now, let me play first just once."))))
677 "Draw agreed. I, for one, never take my moves back...") 686 ((eq result 'crash-game)
678 (gomoku-emacs-played-first 687 "Sorry, I have been interrupted and cannot resume that game...")))
679 "Draw agreed. You were lucky.") 688 (gomoku-display-statistics)
680 (t 689 ;;(ding)
681 "Draw agreed. Now, let me play first just once.")))) 690 (setq gomoku-game-in-progress nil))
682 ((eq result 'crash-game)
683 (setq message
684 "Sorry, I have been interrupted and cannot resume that game...")))
685
686 (gomoku-display-statistics)
687 (if message (message message))
688 ;;(ding)
689 (setq gomoku-game-in-progress nil)))
690 691
691(defun gomoku-crash-game () 692(defun gomoku-crash-game ()
692 "What to do when Emacs detects it has been interrupted." 693 "What to do when Emacs detects it has been interrupted."
@@ -704,6 +705,7 @@ that DVAL has been added on SQUARE."
704 "Start a Gomoku game between you and Emacs. 705 "Start a Gomoku game between you and Emacs.
705If a game is in progress, this command allow you to resume it. 706If a game is in progress, this command allow you to resume it.
706If optional arguments N and M are given, an N by M board is used. 707If optional arguments N and M are given, an N by M board is used.
708If prefix arg is given for N, M is prompted for.
707 709
708You and Emacs play in turn by marking a free square. You mark it with X 710You and Emacs play in turn by marking a free square. You mark it with X
709and Emacs marks it with O. The winner is the first to get five contiguous 711and Emacs marks it with O. The winner is the first to get five contiguous
@@ -712,12 +714,15 @@ marks horizontally, vertically or in diagonal.
712You play by moving the cursor over the square you choose and hitting 714You play by moving the cursor over the square you choose and hitting
713\\<gomoku-mode-map>\\[gomoku-human-plays]. 715\\<gomoku-mode-map>\\[gomoku-human-plays].
714Use \\[describe-mode] for more info." 716Use \\[describe-mode] for more info."
715 (interactive) 717 (interactive (if current-prefix-arg
718 (list (prefix-numeric-value current-prefix-arg)
719 (eval (read-minibuffer "Height: ")))))
716 (gomoku-switch-to-window) 720 (gomoku-switch-to-window)
717 (cond 721 (cond
718 (gomoku-emacs-is-computing 722 (gomoku-emacs-is-computing
719 (gomoku-crash-game)) 723 (gomoku-crash-game))
720 ((not gomoku-game-in-progress) 724 ((or (not gomoku-game-in-progress)
725 (<= gomoku-number-of-moves 2))
721 (let ((max-width (gomoku-max-width)) 726 (let ((max-width (gomoku-max-width))
722 (max-height (gomoku-max-height))) 727 (max-height (gomoku-max-height)))
723 (or n (setq n max-width)) 728 (or n (setq n max-width))
@@ -729,8 +734,8 @@ Use \\[describe-mode] for more info."
729 ((> n max-width) 734 ((> n max-width)
730 (error "I cannot display %d columns in that window" n))) 735 (error "I cannot display %d columns in that window" n)))
731 (if (and (> m max-height) 736 (if (and (> m max-height)
732 (not (equal m gomoku-saved-board-height)) 737 (not (eq m gomoku-saved-board-height))
733 ;; Use EQUAL because SAVED-BOARD-HEIGHT may be nil 738 ;; Use EQ because SAVED-BOARD-HEIGHT may be nil
734 (not (y-or-n-p (format "Do you really want %d rows " m)))) 739 (not (y-or-n-p (format "Do you really want %d rows " m))))
735 (setq m max-height))) 740 (setq m max-height)))
736 (message "One moment, please...") 741 (message "One moment, please...")
@@ -762,9 +767,8 @@ Use \\[describe-mode] for more info."
762 (setq score (aref gomoku-score-table square)) 767 (setq score (aref gomoku-score-table square))
763 (gomoku-play-move square 6) 768 (gomoku-play-move square 6)
764 (cond ((>= score gomoku-winning-threshold) 769 (cond ((>= score gomoku-winning-threshold)
765 (gomoku-find-filled-qtuple square 6)
766 (setq gomoku-emacs-won t) ; for font-lock 770 (setq gomoku-emacs-won t) ; for font-lock
767 (gomoku-cross-winning-qtuple) 771 (gomoku-find-filled-qtuple square 6)
768 (gomoku-terminate-game 'emacs-won)) 772 (gomoku-terminate-game 'emacs-won))
769 ((zerop score) 773 ((zerop score)
770 (gomoku-terminate-game 'nobody-won)) 774 (gomoku-terminate-game 'nobody-won))
@@ -775,11 +779,43 @@ Use \\[describe-mode] for more info."
775 (t 779 (t
776 (gomoku-prompt-for-move))))))))) 780 (gomoku-prompt-for-move)))))))))
777 781
782;; For small square dimensions this is approximate, since though measured in
783;; pixels, event's (X . Y) is a character's top-left corner.
778(defun gomoku-click (click) 784(defun gomoku-click (click)
785 "Position at the square where you click."
786 (interactive "e")
787 (and (windowp (posn-window (setq click (event-end click))))
788 (numberp (posn-point click))
789 (select-window (posn-window click))
790 (setq click (posn-col-row click))
791 (gomoku-goto-xy
792 (min (max (/ (+ (- (car click)
793 gomoku-x-offset
794 1)
795 (window-hscroll)
796 gomoku-square-width
797 (% gomoku-square-width 2)
798 (/ gomoku-square-width 2))
799 gomoku-square-width)
800 1)
801 gomoku-board-width)
802 (min (max (/ (+ (- (cdr click)
803 gomoku-y-offset
804 1)
805 (let ((inhibit-point-motion-hooks t))
806 (count-lines 1 (window-start)))
807 gomoku-square-height
808 (% gomoku-square-height 2)
809 (/ gomoku-square-height 2))
810 gomoku-square-height)
811 1)
812 gomoku-board-height))))
813
814(defun gomoku-mouse-play (click)
779 "Play at the square where you click." 815 "Play at the square where you click."
780 (interactive "e") 816 (interactive "e")
781 (mouse-set-point click) 817 (if (gomoku-click click)
782 (gomoku-human-plays)) 818 (gomoku-human-plays)))
783 819
784(defun gomoku-human-plays () 820(defun gomoku-human-plays ()
785 "Signal to the Gomoku program that you have played. 821 "Signal to the Gomoku program that you have played.
@@ -807,7 +843,6 @@ If the game is finished, this command requests for another game."
807 ;; detecting wins, it just gives an indication that 843 ;; detecting wins, it just gives an indication that
808 ;; we confirm with GOMOKU-FIND-FILLED-QTUPLE. 844 ;; we confirm with GOMOKU-FIND-FILLED-QTUPLE.
809 (gomoku-find-filled-qtuple square 1)) 845 (gomoku-find-filled-qtuple square 1))
810 (gomoku-cross-winning-qtuple)
811 (gomoku-terminate-game 'human-won)) 846 (gomoku-terminate-game 'human-won))
812 (t 847 (t
813 (gomoku-emacs-plays))))))))) 848 (gomoku-emacs-plays)))))))))
@@ -869,13 +904,12 @@ If the game is finished, this command requests for another game."
869 "Ask for another game, and start it." 904 "Ask for another game, and start it."
870 (if (y-or-n-p "Another game ") 905 (if (y-or-n-p "Another game ")
871 (gomoku gomoku-board-width gomoku-board-height) 906 (gomoku gomoku-board-width gomoku-board-height)
872 (message "Chicken !"))) 907 (message "Chicken !")))
873 908
874(defun gomoku-offer-a-draw () 909(defun gomoku-offer-a-draw ()
875 "Offer a draw and return T if Human accepted it." 910 "Offer a draw and return T if Human accepted it."
876 (or (y-or-n-p "I offer you a draw. Do you accept it ") 911 (or (y-or-n-p "I offer you a draw. Do you accept it ")
877 (prog1 (setq gomoku-human-refused-draw t) 912 (not (setq gomoku-human-refused-draw t))))
878 nil)))
879 913
880;;; 914;;;
881;;; DISPLAYING THE BOARD. 915;;; DISPLAYING THE BOARD.
@@ -910,30 +944,18 @@ If the game is finished, this command requests for another game."
910 ;; 2 instead of 1 because WINDOW-HEIGHT includes the mode line ! 944 ;; 2 instead of 1 because WINDOW-HEIGHT includes the mode line !
911 gomoku-square-height))) 945 gomoku-square-height)))
912 946
913(defun gomoku-point-x ()
914 "Return the board column where point is, or nil if it is not a board column."
915 (let ((col (- (current-column) gomoku-x-offset)))
916 (if (and (>= col 0)
917 (zerop (% col gomoku-square-width))
918 (<= (setq col (1+ (/ col gomoku-square-width)))
919 gomoku-board-width))
920 col)))
921
922(defun gomoku-point-y () 947(defun gomoku-point-y ()
923 "Return the board row where point is, or nil if it is not a board row." 948 "Return the board row where point is."
924 (let ((row (- (count-lines 1 (point)) gomoku-y-offset 1))) 949 (let ((inhibit-point-motion-hooks t))
925 (if (and (>= row 0) 950 (1+ (/ (- (count-lines 1 (point)) gomoku-y-offset (if (bolp) 0 1))
926 (zerop (% row gomoku-square-height)) 951 gomoku-square-height))))
927 (<= (setq row (1+ (/ row gomoku-square-height)))
928 gomoku-board-height))
929 row)))
930 952
931(defun gomoku-point-square () 953(defun gomoku-point-square ()
932 "Return the index of the square point is on, or nil if not on the board." 954 "Return the index of the square point is on."
933 (let (x y) 955 (let ((inhibit-point-motion-hooks t))
934 (and (setq x (gomoku-point-x)) 956 (gomoku-xy-to-index (1+ (/ (- (current-column) gomoku-x-offset)
935 (setq y (gomoku-point-y)) 957 gomoku-square-width))
936 (gomoku-xy-to-index x y)))) 958 (gomoku-point-y))))
937 959
938(defun gomoku-goto-square (index) 960(defun gomoku-goto-square (index)
939 "Move point to square number INDEX." 961 "Move point to square number INDEX."
@@ -941,56 +963,76 @@ If the game is finished, this command requests for another game."
941 963
942(defun gomoku-goto-xy (x y) 964(defun gomoku-goto-xy (x y)
943 "Move point to square at X, Y coords." 965 "Move point to square at X, Y coords."
944 (goto-line (+ 1 gomoku-y-offset (* gomoku-square-height (1- y)))) 966 (let ((inhibit-point-motion-hooks t))
967 (goto-line (+ 1 gomoku-y-offset (* gomoku-square-height (1- y)))))
945 (move-to-column (+ gomoku-x-offset (* gomoku-square-width (1- x))))) 968 (move-to-column (+ gomoku-x-offset (* gomoku-square-width (1- x)))))
946 969
947(defun gomoku-plot-square (square value) 970(defun gomoku-plot-square (square value)
948 "Draw 'X', 'O' or '.' on SQUARE (depending on VALUE), leave point there." 971 "Draw 'X', 'O' or '.' on SQUARE depending on VALUE, leave point there."
949 (gomoku-goto-square square) 972 (or (= value 1)
950 (gomoku-put-char (cond ((= value 1) ?X) 973 (gomoku-goto-square square))
951 ((= value 6) ?O)
952 (t ?.)))
953 (sit-for 0)) ; Display NOW
954
955(defun gomoku-put-char (char)
956 "Draw CHAR on the Gomoku screen."
957 (let ((inhibit-read-only t) 974 (let ((inhibit-read-only t)
958 (inhibit-point-motion-hooks t)) 975 (inhibit-point-motion-hooks t))
959 (insert-and-inherit char) 976 (insert-and-inherit (cond ((= value 1) ?X)
977 ((= value 6) ?O)
978 (?.)))
960 (and window-system 979 (and window-system
961 (eq char ?.) 980 (zerop value)
962 (put-text-property (1- (point)) (point) 'mouse-face 'highlight)) 981 (put-text-property (1- (point)) (point) 'mouse-face 'highlight))
963 (delete-char 1) 982 (delete-char 1)
964 (backward-char 1))) 983 (backward-char 1))
984 (sit-for 0)) ; Display NOW
965 985
966(defun gomoku-init-display (n m) 986(defun gomoku-init-display (n m)
967 "Display an N by M Gomoku board." 987 "Display an N by M Gomoku board."
968 (buffer-disable-undo (current-buffer)) 988 (buffer-disable-undo (current-buffer))
969 (let ((inhibit-read-only t) 989 (let ((inhibit-read-only t)
970 (string1 (make-string gomoku-x-offset ? )) 990 (point 1) opoint
971 (string2 (make-string (1- gomoku-square-width) ? )) 991 (intangible t)
972 (point 1) 992 (i m) j x)
973 (i m) j) 993 ;; Try to minimize number of chars (because of text properties)
994 (setq tab-width
995 (if (zerop (% gomoku-x-offset gomoku-square-width))
996 gomoku-square-width
997 (max (/ (+ (% gomoku-x-offset gomoku-square-width)
998 gomoku-square-width 1) 2) 2)))
974 (erase-buffer) 999 (erase-buffer)
975 ;; We do not use gomoku-plot-square which would be too slow for
976 ;; initializing the display.
977 (newline gomoku-y-offset) 1000 (newline gomoku-y-offset)
978 (while (progn 1001 (while (progn
979 (indent-to gomoku-x-offset) 1002 (setq j n
980 (setq j n) 1003 x (- gomoku-x-offset gomoku-square-width))
981 (while (progn 1004 (while (>= (setq j (1- j)) 0)
982 (put-text-property point (point) 'category 'gomoku-mode) 1005 (insert-char ?\t (/ (- (setq x (+ x gomoku-square-width))
983 (put-text-property point (point) 'intangible (point)) 1006 (current-column))
984 (setq point (point)) 1007 tab-width))
985 (insert ?.) 1008 (insert-char ? (- x (current-column)))
986 (if window-system 1009 (if (setq intangible (not intangible))
987 (put-text-property point (point) 1010 (put-text-property point (point) 'intangible 2))
988 'mouse-face 'highlight)) 1011 (and (zerop j)
989 (> (setq j (1- j)) 0)) 1012 (= i (- m 2))
990 (insert string2)) 1013 (progn
1014 (while (>= i 3)
1015 (append-to-buffer (current-buffer) opoint (point))
1016 (setq i (- i 2)))
1017 (goto-char (point-max))))
1018 (setq point (point))
1019 (insert ?.)
1020 (if window-system
1021 (put-text-property point (point)
1022 'mouse-face 'highlight)))
991 (> (setq i (1- i)) 0)) 1023 (> (setq i (1- i)) 0))
1024 (if (= i (1- m))
1025 (setq opoint point))
992 (insert-char ?\n gomoku-square-height)) 1026 (insert-char ?\n gomoku-square-height))
993 (gomoku-goto-xy (/ (1+ n) 2) (/ (1+ m) 2))) ; center of the board 1027 (or (eq (char-after 1) ?.)
1028 (put-text-property 1 2 'point-entered
1029 (lambda (x x) (if (bobp) (forward-char)))))
1030 (or intangible
1031 (put-text-property point (point) 'intangible 2))
1032 (put-text-property point (point) 'point-entered
1033 (lambda (x x) (if (eobp) (backward-char))))
1034 (put-text-property (point-min) (point) 'category 'gomoku-mode))
1035 (gomoku-goto-xy (/ (1+ n) 2) (/ (1+ m) 2)) ; center of the board
994 (sit-for 0)) ; Display NOW 1036 (sit-for 0)) ; Display NOW
995 1037
996(defun gomoku-display-statistics () 1038(defun gomoku-display-statistics ()
@@ -998,16 +1040,12 @@ If the game is finished, this command requests for another game."
998 ;; We store this string in the mode-line-process local variable. 1040 ;; We store this string in the mode-line-process local variable.
999 ;; This is certainly not the cleanest way out ... 1041 ;; This is certainly not the cleanest way out ...
1000 (setq mode-line-process 1042 (setq mode-line-process
1001 (cond 1043 (format ": Won %d, lost %d%s"
1002 ((not (zerop gomoku-number-of-draws)) 1044 gomoku-number-of-human-wins
1003 (format ": Won %d, lost %d, drew %d" 1045 gomoku-number-of-emacs-wins
1004 gomoku-number-of-human-wins 1046 (if (zerop gomoku-number-of-draws)
1005 gomoku-number-of-emacs-wins 1047 ""
1006 gomoku-number-of-draws)) 1048 (format ", drew %d" gomoku-number-of-draws))))
1007 (t
1008 (format ": Won %d, lost %d"
1009 gomoku-number-of-human-wins
1010 gomoku-number-of-emacs-wins))))
1011 (force-mode-line-update)) 1049 (force-mode-line-update))
1012 1050
1013(defun gomoku-switch-to-window () 1051(defun gomoku-switch-to-window ()
@@ -1015,11 +1053,11 @@ If the game is finished, this command requests for another game."
1015 (interactive) 1053 (interactive)
1016 (let ((buff (get-buffer "*Gomoku*"))) 1054 (let ((buff (get-buffer "*Gomoku*")))
1017 (if buff ; Buffer exists: 1055 (if buff ; Buffer exists:
1018 (switch-to-buffer buff) ; no problem. 1056 (switch-to-buffer buff) ; no problem.
1019 (if gomoku-game-in-progress 1057 (if gomoku-game-in-progress
1020 (gomoku-crash-game)) ; buffer has been killed or something 1058 (gomoku-crash-game)) ; buffer has been killed or something
1021 (switch-to-buffer "*Gomoku*") ; Anyway, start anew. 1059 (switch-to-buffer "*Gomoku*") ; Anyway, start anew.
1022 (gomoku-mode)))) 1060 (gomoku-mode))))
1023 1061
1024;;; 1062;;;
1025;;; CROSSING WINNING QTUPLES. 1063;;; CROSSING WINNING QTUPLES.
@@ -1030,19 +1068,6 @@ If the game is finished, this command requests for another game."
1030;; squares ! It only knows the square where the last move has been played and 1068;; squares ! It only knows the square where the last move has been played and
1031;; who won. The solution is to scan the board along all four directions. 1069;; who won. The solution is to scan the board along all four directions.
1032 1070
1033(defvar gomoku-winning-qtuple-beg nil
1034 "First square of the winning qtuple.")
1035
1036(defvar gomoku-winning-qtuple-end nil
1037 "Last square of the winning qtuple.")
1038
1039(defvar gomoku-winning-qtuple-dx nil
1040 "Direction of the winning qtuple (along the X axis).")
1041
1042(defvar gomoku-winning-qtuple-dy nil
1043 "Direction of the winning qtuple (along the Y axis).")
1044
1045
1046(defun gomoku-find-filled-qtuple (square value) 1071(defun gomoku-find-filled-qtuple (square value)
1047 "Return T if SQUARE belongs to a qtuple filled with VALUEs." 1072 "Return T if SQUARE belongs to a qtuple filled with VALUEs."
1048 (or (gomoku-check-filled-qtuple square value 1 0) 1073 (or (gomoku-check-filled-qtuple square value 1 0)
@@ -1052,32 +1077,20 @@ If the game is finished, this command requests for another game."
1052 1077
1053(defun gomoku-check-filled-qtuple (square value dx dy) 1078(defun gomoku-check-filled-qtuple (square value dx dy)
1054 "Return T if SQUARE belongs to a qtuple filled with VALUEs along DX, DY." 1079 "Return T if SQUARE belongs to a qtuple filled with VALUEs along DX, DY."
1055 ;; And record it in the WINNING-QTUPLE-... variables.
1056 (let ((a 0) (b 0) 1080 (let ((a 0) (b 0)
1057 (left square) (right square) 1081 (left square) (right square)
1058 (depl (gomoku-xy-to-index dx dy)) 1082 (depl (gomoku-xy-to-index dx dy)))
1059 a+4)
1060 (while (and (> a -4) ; stretch tuple left 1083 (while (and (> a -4) ; stretch tuple left
1061 (= value (aref gomoku-board (setq left (- left depl))))) 1084 (= value (aref gomoku-board (setq left (- left depl)))))
1062 (setq a (1- a))) 1085 (setq a (1- a)))
1063 (setq a+4 (+ a 4)) 1086 (while (and (< b (+ a 4)) ; stretch tuple right
1064 (while (and (< b a+4) ; stretch tuple right
1065 (= value (aref gomoku-board (setq right (+ right depl))))) 1087 (= value (aref gomoku-board (setq right (+ right depl)))))
1066 (setq b (1+ b))) 1088 (setq b (1+ b)))
1067 (cond ((= b a+4) ; tuple length = 5 ? 1089 (cond ((= b (+ a 4)) ; tuple length = 5 ?
1068 (setq gomoku-winning-qtuple-beg (+ square (* a depl)) 1090 (gomoku-cross-qtuple (+ square (* a depl)) (+ square (* b depl))
1069 gomoku-winning-qtuple-end (+ square (* b depl)) 1091 dx dy)
1070 gomoku-winning-qtuple-dx dx
1071 gomoku-winning-qtuple-dy dy)
1072 t)))) 1092 t))))
1073 1093
1074(defun gomoku-cross-winning-qtuple ()
1075 "Cross winning qtuple, as found by `gomoku-find-filled-qtuple'."
1076 (gomoku-cross-qtuple gomoku-winning-qtuple-beg
1077 gomoku-winning-qtuple-end
1078 gomoku-winning-qtuple-dx
1079 gomoku-winning-qtuple-dy))
1080
1081(defun gomoku-cross-qtuple (square1 square2 dx dy) 1094(defun gomoku-cross-qtuple (square1 square2 dx dy)
1082 "Cross every square between SQUARE1 and SQUARE2 in the DX, DY direction." 1095 "Cross every square between SQUARE1 and SQUARE2 in the DX, DY direction."
1083 (save-excursion ; Not moving point from last square 1096 (save-excursion ; Not moving point from last square
@@ -1092,7 +1105,9 @@ If the game is finished, this command requests for another game."
1092 ((= dy 0) ; Horizontal 1105 ((= dy 0) ; Horizontal
1093 (forward-char 1) 1106 (forward-char 1)
1094 (insert-char ?- (1- gomoku-square-width) t) 1107 (insert-char ?- (1- gomoku-square-width) t)
1095 (delete-char (1- gomoku-square-width))) 1108 (delete-region (point) (progn
1109 (skip-chars-forward " \t")
1110 (point))))
1096 ((= dx 0) ; Vertical 1111 ((= dx 0) ; Vertical
1097 (let ((n 1) 1112 (let ((n 1)
1098 (column (current-column))) 1113 (column (current-column)))
@@ -1102,13 +1117,11 @@ If the game is finished, this command requests for another game."
1102 (indent-to column) 1117 (indent-to column)
1103 (insert-and-inherit ?|)))) 1118 (insert-and-inherit ?|))))
1104 ((= dx -1) ; 1st Diagonal 1119 ((= dx -1) ; 1st Diagonal
1105 (backward-char (/ gomoku-square-width 2)) 1120 (indent-to (prog1 (- (current-column) (/ gomoku-square-width 2))
1106 (indent-to (prog1 (current-column)
1107 (forward-line (/ gomoku-square-height 2)))) 1121 (forward-line (/ gomoku-square-height 2))))
1108 (insert-and-inherit ?/)) 1122 (insert-and-inherit ?/))
1109 (t ; 2nd Diagonal 1123 (t ; 2nd Diagonal
1110 (forward-char (/ gomoku-square-width 2)) 1124 (indent-to (prog1 (+ (current-column) (/ gomoku-square-width 2))
1111 (indent-to (prog1 (current-column)
1112 (forward-line (/ gomoku-square-height 2)))) 1125 (forward-line (/ gomoku-square-height 2))))
1113 (insert-and-inherit ?\\)))))) 1126 (insert-and-inherit ?\\))))))
1114 (sit-for 0)) ; Display NOW 1127 (sit-for 0)) ; Display NOW
@@ -1120,18 +1133,14 @@ If the game is finished, this command requests for another game."
1120(defun gomoku-move-down () 1133(defun gomoku-move-down ()
1121 "Move point down one row on the Gomoku board." 1134 "Move point down one row on the Gomoku board."
1122 (interactive) 1135 (interactive)
1123 (let ((y (gomoku-point-y))) 1136 (if (< (gomoku-point-y) gomoku-board-height)
1124 (next-line (cond ((null y) 1) 1137 (next-line gomoku-square-height)))
1125 ((< y gomoku-board-height) gomoku-square-height)
1126 (t 0)))))
1127 1138
1128(defun gomoku-move-up () 1139(defun gomoku-move-up ()
1129 "Move point up one row on the Gomoku board." 1140 "Move point up one row on the Gomoku board."
1130 (interactive) 1141 (interactive)
1131 (let ((y (gomoku-point-y))) 1142 (if (> (gomoku-point-y) 1)
1132 (previous-line (cond ((null y) 1) 1143 (previous-line gomoku-square-height)))
1133 ((> y 1) gomoku-square-height)
1134 (t 0)))))
1135 1144
1136(defun gomoku-move-ne () 1145(defun gomoku-move-ne ()
1137 "Move point North East on the Gomoku board." 1146 "Move point North East on the Gomoku board."
@@ -1157,6 +1166,17 @@ If the game is finished, this command requests for another game."
1157 (gomoku-move-down) 1166 (gomoku-move-down)
1158 (backward-char)) 1167 (backward-char))
1159 1168
1169(defun gomoku-beginning-of-line ()
1170 "Move point to first square on the Gomoku board row."
1171 (interactive)
1172 (move-to-column gomoku-x-offset))
1173
1174(defun gomoku-end-of-line ()
1175 "Move point to last square on the Gomoku board row."
1176 (interactive)
1177 (move-to-column (+ gomoku-x-offset
1178 (* gomoku-square-width (1- gomoku-board-width)))))
1179
1160(provide 'gomoku) 1180(provide 'gomoku)
1161 1181
1162;;; gomoku.el ends here 1182;;; gomoku.el ends here