gnugo-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnugo-devel] Regressions in Emacs


From: bump
Subject: [gnugo-devel] Regressions in Emacs
Date: Tue, 7 Dec 2004 20:36:11 -0800

Here is another revision of my patch to gnugo.el.

This fixes the bug that I've mentioned before, causing Emacs
to hang when loading an sgf file with no B or W properties, in
connection with the patch to play_gtp.c, which is already in
the CVS:

http://lists.gnu.org/archive/html/gnugo-devel/2004-12/msg00045.html

More interestingly, the patch also includes a regression view
which I think is extremely handy. The function
gnugo-view-regression is bound to `v'. You just type `v', and then
you will be prompted for the name of a test to run, such as
nngs1:40.

With the first test you run you will also be prompted for the
path to the regression/ directory. Once you've entered that
you won't need to again. Here's a screenshot:

http://sporadic.stanford.edu/bump/emacs-regression.jpg

Since the test must be run, it takes that long to finish
the screen. The entire sgf file loads, so you can use
`b' and `f' to scroll around in the game to get the context
of the test. Of course you can enter other gtp commands.

This is a patch against gnugo.el-2.2.8. It applies without
change to the version of gnugo.el that is in the CVS and
also in gnugo-3.6. However if you are running gnugo-3.6
you will also benefit from patching play_gtp.c as above.

Dan

Index: gnugo.el
===================================================================
RCS file: /home/bump/cvsroot/gnugoels/gnugo.el,v
retrieving revision 1.3.2.10
diff -u -r1.3.2.10 gnugo.el
--- gnugo.el    25 Nov 2004 12:42:45 -0000      1.3.2.10
+++ gnugo.el    8 Dec 2004 04:03:38 -0000
@@ -147,10 +147,21 @@
 (require 'cl)                           ; use the source luke!
 (ignore-errors (require 'time-date))    ; for `time-subtract'
 
+
+;;; ==========================================================================
+
+; Modifications to gnugo.el-2.2.8:
+;
+; * Grid display implemented
+; * SGF handling improved
+; * Undo and Redo related enhancements
+; * Primitive edit mode
+; * Regression view mode
+
 ;;;---------------------------------------------------------------------------
 ;;; Political arts
 
-(defconst gnugo-version "2.2.8"
+(defconst gnugo-version "2.2.8.b5"
   "Version of gnugo.el currently loaded.
 Note that more than two dots in the value indicates \"pre-release\",
 or \"alpha\" or \"hackers-invited-all-else-beware\"; use at your own risk!
@@ -205,12 +216,14 @@
 character in the string, then the next, and so on until the string (and/or
 the viewer) is exhausted.")
 
-(defvar gnugo-mode-line "~b ~w :~u"
+(defvar gnugo-mode-line "~b ~w :~m ~n :~u"
   "*A `mode-line-format'-compliant value for GNUGO Board mode.
 If a single string, the following special escape sequences are
 replaced with their associated information:
   ~b,~w  black,white captures (a number)
   ~p     current player (black or white)
+  ~m     move number
+  ~n     size of undo stack
   ~t     time waiting for the current move
   ~u     time taken for the Ultimate (most recent) move
 The times are in seconds, or \"-\" if that information is not available.
@@ -236,6 +249,8 @@
                          ;                    gnugo-state)
                          ;           (reverse acc))))))
 
+(defvar gnugo-regression-directory nil)
+
 (eval-when-compile
   (defvar gnugo-xpms nil))
 
@@ -295,6 +310,7 @@
  :sgf-tree -- the (very simple) list of nodes, each node a list of
               properties of the form `(:XY . VALUE)'; see functions
               `gnugo-push-move', `gnugo-note' and `gnugo-write-sgf-file'
+ :future-history -- an undo stack (so moves undone may be redone)
 
  :gnugo-color -- either \"black\" or \"white\"
  :user-color
@@ -312,6 +328,7 @@
  :display-using-images -- XPMs, to be precise; see functions `gnugo-yy',
                           `gnugo-toggle-image-display' and `gnugo-refresh',
                           as well as gnugo-xpms.el (available elsewhere)
+ :show-grid -- display the grid
 
  :all-yy -- list of 46 keywords used as the `category' text property
             (so that their plists, typically w/ property `display' or
@@ -402,16 +419,17 @@
 
 (defun gnugo-goto-pos (pos)
   "Move point to board position POS, a letter-number string."
-  (goto-char (point-min))
-  (forward-line (- (1+ (gnugo-get :board-size))
-                   (string-to-number (substring pos 1))))
-  (forward-char 1)
-  (forward-char (+ (if (= 32 (following-char)) 1 2)
-                   (* 2 (- (let ((letter (aref pos 0)))
-                             (if (> ?I letter)
-                                 letter
-                               (1- letter)))
-                           ?A)))))
+  (unless (string= pos "PASS")
+    (goto-char (point-min))
+    (forward-line (- (+ 2 (gnugo-get :board-size))
+                    (string-to-number (substring pos 1))))
+    (forward-char 2)
+    (forward-char (+ (if (= 32 (following-char)) 1 2)
+                    (* 2 (- (let ((letter (aref pos 0)))
+                              (if (> ?I letter)
+                                  letter
+                                (1- letter)))
+                            ?A))))))
 
 (defun gnugo-f (frag)
   (intern (format ":gnugo-%s%s-props" (gnugo-get :diamond) frag)))
@@ -460,6 +478,8 @@
                                    ;; `(display (space :width 0))'
                                    ;; works as well, for newer emacs
                                    '(invisible t)))
+    (setplist (gnugo-f 'jspc) 
+             `(display (space :width ,(- (gnugo-get :w-imul) 1))))
     (gnugo-put :highlight-last-move-spec
       (if new
           '((lambda (p)
@@ -477,22 +497,52 @@
     (gnugo-put :hmul (if new (gnugo-get :h-imul) 1))
     (gnugo-put :display-using-images new)))
 
+(defun gnugo-toggle-grid ()
+  "Turn the grid around the board on or off."
+  (interactive)
+  (gnugo-put :show-grid (not (gnugo-get :show-grid)))
+  (gnugo-refresh t))
+
+(defun gnugo-propertize-grid-line (size)
+  (put-text-property (point) (+ 1 (point)) 
+                    'category (gnugo-f 'lpad))
+  (do ((p (+ 4 (point)) (+ 2 p)) (ival 'even (if (eq 'even ival) 'odd 'even)))
+      ((< (+ (* 2 size) 3 (point)) p))
+    (add-text-properties p (1+ p)
+                        `(gnugo-yin
+                          ,5
+                          gnugo-yang
+                          ,'empty
+                          front-sticky
+                          (gnugo-position gnugo-yin)))
+    (add-text-properties (- p 1) p
+                        `(category
+                          ,(gnugo-f 'jspc)
+                          rear-nonsticky
+                          t))
+    (put-text-property (- p 2) p 'intangible ival)))
+
 (defun gnugo-propertize-board-buffer ()
   (erase-buffer)
   (insert (substring (cdr (gnugo-synchronous-send/return "showboard")) 3))
   (let* ((size (gnugo-get :board-size))
          (size-string (number-to-string size)))
-    (goto-char (point-min))
-    (put-text-property (point) (1+ (point)) 'category (gnugo-f 'tpad))
+    (beginning-of-buffer)
+    (insert " \n")
+    (put-text-property (point-min) (+ 1 (point-min)) 'category (gnugo-f 'tpad))
+    (insert " ")
+    (beginning-of-line)
+    (gnugo-propertize-grid-line size)
     (forward-line 1)
-    (put-text-property (point-min) (point) 'invisible t)
+    (insert " ")
+    (beginning-of-line)
     (while (looking-at "\\s-*\\([0-9]+\\)[ ]")
       (let* ((row (match-string-no-properties 1))
              (edge (match-end 0))
              (other-edge (+ edge (* 2 size) -1))
              (top-p (string= size-string row))
              (bot-p (string= "1" row)))
-        (put-text-property (point) (1- edge) 'category (gnugo-f 'lpad))
+        (put-text-property (point) (1+ (point)) 'category (gnugo-f 'lpad))
         (do ((p edge (+ 2 p)) (ival 'even (if (eq 'even ival) 'odd 'even)))
             ((< other-edge p))
           (let* ((position (format "%c%s" (aref [?A ?B ?C ?D ?E ?F ?G ?H
@@ -532,15 +582,27 @@
             (put-text-property p (+ 2 p) 'intangible ival)))
         (goto-char (+ other-edge (length row) 1))
         (when (looking-at "\\s-+\\(WH\\|BL\\).*capt.* \\([0-9]+\\).*$")
-          (let ((prop (if (string= "WH" (match-string 1))
-                          :white-captures
-                        :black-captures)))
-            (put-text-property (match-beginning 2) (match-end 2) 'field prop)
-            (gnugo-put prop (match-string-no-properties 2))))
+         (kill-line))
+       (unless (gnugo-get :show-grid)
+           (save-excursion
+             (put-text-property (line-beginning-position)
+                                (+ 3 (line-beginning-position))
+                                'invisible t)
+             (put-text-property (+ 3 (* 2 size) (line-beginning-position))
+                                (line-end-position)
+                                'invisible t)
+             (beginning-of-buffer)
+             (forward-line 1)
+             (put-text-property (point) (line-end-position) 'invisible t)
+             (end-of-buffer)
+             (put-text-property 
+              (line-beginning-position) (point) 'invisible t)))
         (end-of-line)
-        (put-text-property other-edge (point) 'category (gnugo-f 'rpad))
-        (forward-char 1)))
-    (put-text-property (1- (point)) (point-max) 'invisible t)))
+        ;(put-text-property other-edge (point) 'category (gnugo-f 'rpad))
+        (forward-char 1)
+       (insert " ")
+       (beginning-of-line)))
+      (gnugo-propertize-grid-line size)))
 
 (defun gnugo-merge-showboard-results ()
   (let ((aft (substring (cdr (gnugo-synchronous-send/return "showboard")) 3))
@@ -598,6 +660,27 @@
         (when (setq very-strange (get-text-property (1+ cut) 'intangible))
           (put-text-property cut (1+ cut) 'intangible very-strange))))))
 
+(defun gnugo-sgf-to-gtp (cc) 
+  "Convert board locations from the format used by sgf to the format used by 
gtp."
+  (interactive)
+  (if (string= "tt" cc)
+      "PASS"
+    (setq col (aref cc 0))
+    (format "%c%d"
+           (+ ?A (- (if (> ?i col) col (1+ col)) ?a))
+           (- (gnugo-get :board-size) (- (aref cc 1) ?a)))))
+
+(defun gnugo-gtp-to-sgf (value)
+  "Convert board locations from the format used by gtp to the format used by 
sgf."
+  (interactive)
+  (if (string= "PASS" value)
+      "tt"
+    (let* ((col (aref value 0))
+          (one (+ ?a (- (if (< ?H col) (1- col) col) ?A)))
+          (two (+ ?a (- (gnugo-get :board-size) 
+                        (string-to-number (substring value 1))))))
+      (format "%c%c" one two))))
+
 (defun gnugo-move-history (&optional rsel)
   "Determine and return the game's move history.
 Optional arg RSEL controls side effects and return value.
@@ -683,11 +766,12 @@
          (head (gnugo-move-history 'car))
          (onep (and head (string= "PASS" head)))
          (donep (or resignp (and onep passp))))
-    (unless passp
-      (gnugo-merge-showboard-results))
+;    (unless passp
+;      (gnugo-merge-showboard-results))
     (gnugo-put :last-mover color)
     (when userp
       (gnugo-put :last-user-bpos (and (not passp) (not resignp) move)))
+    (gnugo-put :future-history nil)
     (gnugo-note (if (string= "black" color) :B :W) move t (not resignp))
     (when resignp
       (gnugo-note :EV "resignation"))
@@ -730,8 +814,20 @@
             `((live ,@live)
               (dead ,@dead))))))
     (gnugo-put :waiting-start (and (not donep) now))
+    (gnugo-put :black-captures (gnugo-query "captures black"))
+    (gnugo-put :white-captures (gnugo-query "captures white"))
+    (gnugo-refresh t)
     donep))
 
+(defun gnugo-toggle-edit-mode ()
+  "Toggle :edit-mode. When true, GNU Go is not called to generate moves."
+  (interactive)
+  (gnugo-put :edit-mode (not (gnugo-get :edit-mode)))
+  (if (gnugo-get :edit-mode)
+      (setq mode-name "Editing SGF File")
+    (setq mode-name "Playing GNU Go"))
+  (gnugo-refresh))
+
 (defun gnugo-venerate (yin yang)
   (let* ((fg-yy (gnugo-yy yin yang))
          (fg-disp (or (get fg-yy 'display)
@@ -856,7 +952,7 @@
              (h (ash (- (window-height window)
                         (round (* size (gnugo-get :hmul)))
                         1)
-                     -1))
+                     -5))
              (edges (window-edges window))
              (right-w-edge (nth 2 edges))
              (avail-width (- right-w-edge (nth 0 edges)))
@@ -865,7 +961,7 @@
                          (if (symbol-plist (gnugo-f 'ispc))
                              0
                            (1- size)))
-                      2)
+                      8)
                    2.0)))
         (dolist (pair `((tpad . ,(if (and h (< 0 h))
                                      `(display ,(make-string h 10))
@@ -885,7 +981,7 @@
           (cond ((stringp cur)
                  (setq cur (copy-sequence cur))
                  (let (acc cut c)
-                   (while (setq cut (string-match "~[bwptu]" cur))
+                   (while (setq cut (string-match "~[bwmnptu]" cur))
                      (aset cur cut ?%)
                      (setq cut (1+ cut) c (aref cur cut))
                      (aset cur cut ?s)
@@ -894,6 +990,8 @@
                         ,(case c
                            (?b '(or (gnugo-get :black-captures) 0))
                            (?w '(or (gnugo-get :white-captures) 0))
+                           (?m '(length (cdr (gnugo-get :sgf-tree))))
+                           (?n '(length (gnugo-get :future-history)))
                            (?p '(gnugo-other (gnugo-get :last-mover)))
                            (?t '(let ((ws (gnugo-get :waiting-start)))
                                   (if ws
@@ -954,7 +1052,8 @@
                             tpad
                             lpad
                             rpad
-                            ispc))))
+                            ispc
+                            jspc))))
     (setq gnugo-state nil)))
 
 (defun gnugo-position ()
@@ -980,8 +1079,12 @@
       (unless inhibit-gnugo-refresh
         (with-current-buffer buf
           (gnugo-refresh))))
-    (with-current-buffer buf
-      (gnugo-get-move (gnugo-get :gnugo-color)))))
+    (if (not (gnugo-get :edit-mode))
+       (with-current-buffer buf
+         (gnugo-get-move (gnugo-get :gnugo-color)))
+      (progn
+       (gnugo-put :user-color (gnugo-other (gnugo-get :user-color)))
+       (gnugo-put :gnugo-color (gnugo-other (gnugo-get :gnugo-color)))))))
 
 (defun gnugo-mouse-move (e)
   "Do `gnugo-move' at mouse location."
@@ -1186,10 +1289,11 @@
              (not (y-or-n-p "File exists. Continue? ")))
     (error "Not writing %s" filename))
   ;; todo: write sgf.el; call to it here
-  (let ((bef-newline-appreciated '(:C :B :W :PB :PW))           ;;; aesthetic
-        (aft-newline-appreciated '(:C :B :W :SZ :PB :PW))       ;;;  license
+  (let ((bef-newline-appreciated '(:C :PB :PW :AB :AW))
+        (aft-newline-appreciated '(:C :B :AB :AW :W :PB :PW :SZ))
         (sz (gnugo-get :board-size))
-        (tree (gnugo-get :sgf-tree)))
+        (tree (gnugo-get :sgf-tree))
+       newline-just-printed)
     (with-temp-buffer
       (insert "(")
       (dolist (node (reverse tree))
@@ -1197,18 +1301,153 @@
         (dolist (prop (reverse node))
           (let ((name (car prop))
                 (v (cdr prop)))
-            (insert
-             (if (memq name bef-newline-appreciated) "\n" "")
-             (substring (symbol-name name) 1)
-             "[" (format "%s" v) "]"
-             (if (memq name aft-newline-appreciated) "\n" "")))))
+           (insert
+            (if (and (memq name bef-newline-appreciated) 
+                     (not newline-just-printed)) "\n" "")
+            (substring (symbol-name name) 1)
+            (if (not (memq name '(:AB :AW))) "[" "")
+            (format "%s" v)
+            (if (not (memq name '(:AB :AW))) "]" "")
+            (if (or (memq name aft-newline-appreciated)
+                    (> (current-column) 60)) "\n" ""))
+           (setq newline-just-printed
+                 (memq name aft-newline-appreciated)))))
       (insert ")\n")
       (write-file filename))))
 
+(defun gnugo-warp-point ()
+  "Move the cursor to the next-to-last move."
+  (interactive)
+  (let ((moves (cdr (gnugo-get :sgf-tree))))
+    (if (memq (car (car (car moves))) '(:B :W))
+       (gnugo-goto-pos (gnugo-sgf-to-gtp (cdr (car (car moves))))))))
+
+(defun gnugo-initialize-sgf-tree ()
+  "Start a new sgf tree"
+  (gnugo-put :sgf-tree (list (list)))
+  (let ((g-blackp (string= "black" (gnugo-get :gnugo-color)))
+       (black-stones (split-string (gnugo-query "list_stones black") " "))
+       (white-stones (split-string (gnugo-query "list_stones white") " ")))
+    (mapc (lambda (x) (apply 'gnugo-note x))
+          `((:GM 1)
+            (:FF 4)                     ; hmm maybe better: 3
+            (:DT ,(format-time-string "%Y-%m-%d"))
+            (:RU ,(gnugo-get :rules))
+            (:HA ,(gnugo-get :handicap))
+            (:SZ ,(gnugo-get :board-size))
+            (:KM ,(gnugo-get :komi))
+            (:AP ,(format "gnugo.el:%s" gnugo-version))
+            (,(if g-blackp :PW :PB) ,(user-full-name))
+            (,(if g-blackp :PB :PW) ,(concat "GNU Go "
+                                             (gnugo-query "version")))))
+    (if black-stones
+       (gnugo-note :AB
+                   (apply 'concat
+                          (mapcar 
+                           (lambda (x) (format "[%s]" (gnugo-gtp-to-sgf x)))
+                           black-stones))))
+    (if white-stones
+       (gnugo-note :AW
+                   (apply 'concat
+                          (mapcar 
+                           (lambda (x) (format "[%s]" (gnugo-gtp-to-sgf x)))
+                           white-stones))))))
+
 (defun gnugo-read-sgf-file (filename)
   "Load a game tree from FILENAME, a file in SGF format."
   (interactive "fSGF file to load: ")
-  (gnugo-command (format "loadsgf %s" (expand-file-name filename))))
+  (gnugo-command (format "loadsgf %s 1" (expand-file-name filename)))
+  (gnugo-put :board-size 
+    (string-to-number (gnugo-query "query_boardsize")))
+  (gnugo-put :handicap 
+    (string-to-number (gnugo-query "get_handicap")))
+  (gnugo-put :komi 
+    (string-to-number (gnugo-query "get_komi")))
+  (gnugo-put :future-history nil)
+  (gnugo-initialize-sgf-tree)
+  (gnugo-command (format "loadsgf %s" (expand-file-name filename)))
+  (let* ((colorhistory 
+         (mapcar 
+          (lambda (x) (split-string x " ")) 
+          (split-string 
+           (cdr (gnugo-synchronous-send/return "move_history")) "[=\n]")))
+        (k (length colorhistory)))
+    (unless (equal colorhistory '(nil)) ; empty move history gives this
+      (gnugo-put :last-mover
+       (car (car colorhistory)))
+      (let ((half (ash (1+ (gnugo-get :board-size)) -1)))
+       (gnugo-goto-pos (format "A%d" half))
+       (forward-char (* 2 (1- half)))
+       (gnugo-put :last-user-bpos
+         (gnugo-put :center-position
+           (get-text-property (point) 'gnugo-position))))
+      (while (> k 0)
+       (decf k)
+       (gnugo-note (if (string= (car (nth k colorhistory)) "black") :B :W)
+                   (nth 1 (nth k colorhistory)) t t))))
+  (gnugo-refresh t)
+  (gnugo-warp-point))
+
+(defun gnugo-undo (&optional norefresh)
+  "Undo one move. Interchange the colors of the two players."
+  (interactive)
+  (gnugo-gate)
+  (unless (and (gnugo-get :game-over) ; engine should undo pass but not resign
+              (not
+               (string= "PASS" 
+                        (nth 1 
+                             (split-string (gnugo-query "last_move") " ")))))
+    (if (equal
+        (car
+         (split-string 
+          (cdr (gnugo-synchronous-send/return "undo")) " ")) "?")
+       (error "cannot undo")
+      (gnugo-put :future-history
+       (cons (car (gnugo-get :sgf-tree)) (gnugo-get :future-history)))))
+  (gnugo-put :sgf-tree (cdr (gnugo-get :sgf-tree)))
+  (gnugo-put :user-color (gnugo-get :last-mover))
+  (gnugo-put :gnugo-color (gnugo-other (gnugo-get :last-mover)))
+  (gnugo-put :last-mover (gnugo-get :gnugo-color))
+  (gnugo-put :game-over nil)
+; (gnugo-merge-showboard-results)
+  (unless norefresh
+    (gnugo-refresh t)
+    (gnugo-warp-point)))
+
+(defun gnugo-redo (&optional norefresh)
+  "Redo one move from the undo-stack (future-history).
+   Interchange the colors of the two players."
+  (interactive)
+  (gnugo-gate)
+  (if (equal (gnugo-get :future-history) nil)
+      (error "no more undone moves left to redo!"))
+  (let* ((buf (current-buffer))
+        (pos (gnugo-sgf-to-gtp (cdr (car (car (gnugo-get :future-history))))))
+       (color (if (equal (car (car (car (gnugo-get :future-history)))) :B) 
+                  "black" "white"))
+       (move (format "play %s %s" color pos))
+       (accept (cdr (gnugo-synchronous-send/return move))))
+    (gnugo-note (if (string= "black" color) :B :W) pos t t)
+    (gnugo-put :future-history (cdr (gnugo-get :future-history)))
+    (gnugo-put :user-color (gnugo-other color))
+    (gnugo-put :gnugo-color color)
+    (gnugo-put :last-mover color)
+;    (gnugo-merge-showboard-results)
+    (unless norefresh
+      (gnugo-refresh t)
+      (gnugo-warp-point))))
+
+(defun gnugo-redo-two-moves ()
+  "Redo a pair of moves (yours and GNU Go's).
+If two moves cannot be found, do nothing. (If there is
+exactly one move in the undo stack, you can still redo
+it using gnugo-redo.)"
+  (interactive)
+  (gnugo-gate)
+  (if (cdr (gnugo-get :future-history))
+      (gnugo-redo)
+    (error "can't redo two moves\n"))
+  (gnugo-redo))
 
 (defun gnugo-magic-undo (spec &optional noalt)
   "Undo moves on the GNUGO Board, based on SPEC, a string or number.
@@ -1231,9 +1470,9 @@
            (setq n spec done (lambda () (= 0 n))))
           ((string-match "^[a-z]" spec)
            (let ((pos (upcase spec)))
-             (setq done `(lambda ()
-                           (gnugo-goto-pos ,pos)
-                           (memq (char-after) '(?. ?+))))
+             (setq done `(lambda () 
+                          (equal 
+                           (gnugo-query ,(concat "color " pos)) "empty")))
              (when (funcall done)
                (error "%s already clear" pos))
              (let ((u (gnugo-get :user-color)))
@@ -1245,21 +1484,24 @@
                           ?X))
                  (error "%s not occupied by %s" pos u)))))
           (t (error "bad spec: %S" spec)))
-    (when (gnugo-get :game-over)
-      ;; fixme: clean up :sgf-tree here.
-      (gnugo-put :game-over nil))
     (while (not (funcall done))
-      (setq ans (cdr (gnugo-synchronous-send/return "undo")))
-      (unless (= ?= (aref ans 0))
-        (error ans))
+      (if (gnugo-get :game-over)
+         (gnugo-put :game-over nil)
+       (progn
+         (setq ans (cdr (gnugo-synchronous-send/return "undo")))
+         (unless (= ?= (aref ans 0))
+           (gnugo-refresh t)
+           (error ans))
+         (gnugo-put :future-history
+           (cons (car (gnugo-get :sgf-tree)) (gnugo-get :future-history)))))
       (gnugo-put :sgf-tree (cdr (gnugo-get :sgf-tree)))
       (gnugo-put :last-mover (gnugo-other (gnugo-get :last-mover)))
-      (gnugo-merge-showboard-results)   ; all
-      (gnugo-refresh)                   ; this
+;     (gnugo-merge-showboard-results)   ; all
+;     (gnugo-refresh t)                 ; this
       (decf n)                          ; is
       (sit-for 0)))                     ; eye candy
   (let* ((ulastp (string= (gnugo-get :last-mover) (gnugo-get :user-color)))
-
+        
          (ubpos (gnugo-move-history (if ulastp 'car 'cadr))))
     (gnugo-put :last-user-bpos (if (and ubpos (not (string= "PASS" ubpos)))
                                    ubpos
@@ -1287,6 +1529,95 @@
                         1
                       2)))
 
+(defun gnugo-jump-to-move (movenum)
+  "Jump to move number MOVENUM."
+  (interactive)
+  (unless 
+      (and
+       (>= movenum 0)
+       (<= movenum (+ (length (cdr (gnugo-get :sgf-tree)))
+                     (length (gnugo-get :future-history)))))
+    (error "invalid move number"))
+  (while (not (= movenum (length (cdr (gnugo-get :sgf-tree)))))
+    (if (< movenum (length (cdr (gnugo-get :sgf-tree))))
+       (gnugo-undo t)
+      (gnugo-redo t)))
+  (gnugo-refresh t)
+  (gnugo-warp-point))
+
+(defun gnugo-jump-to-beginning ()
+  "Jump to the beginning of the game."
+  (interactive)
+  (gnugo-jump-to-move 0))
+
+(defun gnugo-jump-to-end ()
+  "Jump to the end of the game"
+  (interactive)
+  (gnugo-jump-to-move (+ (length (cdr (gnugo-get :sgf-tree)))
+        (length (gnugo-get :future-history)))))
+
+(defun gnugo-get-regression-directory (filename)
+  "Prompt the user for the regression directory."
+  (interactive "fRegression directory: ")
+  (setq gnugo-regression-directory (expand-file-name filename)))
+
+(defun gnugo-view-regression (test)
+  (interactive "sTest: ")
+  (let* ((file (car (split-string test ":")))
+       (testnumber (nth 1 (split-string test ":")))
+       (gnugo-buffer (current-buffer))
+       (file-already-open nil))
+    (unless gnugo-regression-directory
+      (call-interactively 'gnugo-get-regression-directory))
+    (unless gnugo-regression-directory
+      (error "directory not found"))
+    (let ((filename
+          (concat gnugo-regression-directory file ".tst")))
+      (if (find-buffer-visiting filename)
+         (setq file-already-open t))
+      (find-file filename))
+    (beginning-of-buffer)
+    (unless
+       (re-search-forward (concat "^" testnumber " ") nil t)
+      (unless file-already-open (kill-buffer (current-buffer)))
+      (switch-to-buffer gnugo-buffer)
+      (error "test not found"))
+    (beginning-of-line)
+    (let* ((second-line (buffer-substring
+                        (line-beginning-position)
+                        (line-end-position)))
+          (third-line (progn
+                        (forward-line)
+                        (buffer-substring
+                        (line-beginning-position)
+                        (line-end-position))))
+          (first-line (progn (re-search-backward "loadsgf")
+                             (buffer-substring
+                              (line-beginning-position)
+                              (line-end-position))))
+          (first-line-split (split-string first-line)))
+      ; don't close the file if the user was visiting it
+      (unless file-already-open (kill-buffer (current-buffer)))
+      (switch-to-buffer gnugo-buffer)
+      (gnugo-read-sgf-file
+       (concat gnugo-regression-directory (nth 1 first-line-split)))
+      (if (> (length first-line-split) 2)
+         (gnugo-jump-to-move (1- (string-to-number 
+                                  (nth 2 first-line-split)))))
+      (setq mode-name "running test ...")
+      (gnugo-put :show-grid t)
+      (gnugo-refresh t)
+      (end-of-buffer)
+      (insert "\n\n ")
+      (insert first-line)
+      (insert "\n ")
+      (insert (format "%s:%s" file second-line))
+      (insert "\n ")
+      (insert third-line)
+      (insert "\n ")
+      (setq mode-name (format "%s" test))
+      (insert (cdr (gnugo-synchronous-send/return second-line))))))
+
 (defun gnugo-display-final-score ()
   "Display final score and other info in another buffer (when game over).
 If the game is still ongoing, Emacs asks if you wish to stop play (by
@@ -1481,13 +1812,28 @@
 
   u             Run `gnugo-undo-two-moves'.
 
+  r             Redo two moves.
+
   U             Pass to `gnugo-magic-undo' either the board position
                 at point (if no prefix arg), or the prefix arg converted
                 to a number.  E.g., to undo 16 moves: `C-u C-u U' (see
                 `universal-argument'); to undo 42 moves: `M-4 M-2 U'.
 
-  C-l           Run `gnugo-refresh'.
+  f             Scroll forward (redo one undone move); 
+                potentially switch colors.
+
+  b             Scroll backward (undo one move); potentially switch colors.
+
+  <             Go to the beginning of the game
+
+  >             Go to the end of the game
 
+  j <n> RET     Jump to move number <n>
+
+  g             toggle the grid on or off.
+
+  C-l           Run `gnugo-refresh' to redraw the board.
+ 
   _ or M-_      Bury the Board buffer (when the boss is near).
 
   P             Run `gnugo-pass'.
@@ -1525,7 +1871,7 @@
   (set (make-local-variable 'font-lock-defaults)
        '(gnugo-font-lock-keywords t))
   (setq major-mode 'gnugo-board-mode)
-  (setq mode-name "GNUGO Board")
+  (setq mode-name "Playing GNU Go")
   (add-hook 'kill-buffer-hook 'gnugo-cleanup nil t)
   (make-local-variable 'gnugo-state)
   (setq gnugo-state (make-hash-table :size (1- 42) :test 'eq))
@@ -1538,7 +1884,9 @@
           :white-captures
           :mode-line
           :mode-line-form
+          :edit-mode
           :display-using-images
+          :show-grid
           :xpms
           :local-xpms
           :all-yy))
@@ -1602,28 +1950,9 @@
   (gnugo-put :rparen-ov (let ((ov (make-overlay 1 1)))
                           (overlay-put ov 'display ")")
                           ov))
-  (gnugo-put :sgf-tree (list (list)))
-  (let ((g-blackp (string= "black" (gnugo-get :gnugo-color))))
-    (mapc (lambda (x) (apply 'gnugo-note x))
-          `((:GM 1)
-            (:FF 4)                     ; hmm maybe better: 3
-            (:DT ,(format-time-string "%Y-%m-%d"))
-            (:RU ,(gnugo-get :rules))
-            (:SZ ,(gnugo-get :board-size))
-            (:KM ,(gnugo-get :komi))
-            (,(if g-blackp :PW :PB) ,(user-full-name))
-            (,(if g-blackp :PB :PW) ,(concat "GNU Go "
-                                             (gnugo-query "version")))
-            ,@(let ((h (gnugo-get :handicap)))
-                (when (not (= 0 h))
-                  `((:HA ,h)
-                    ,@(mapcar
-                       ;; AB can be a list, but we stay simple so that
-                       ;; `gnugo-write-sgf-file' can also remain simple
-                       (lambda (stone)
-                         `(:AB ,stone nil t))
-                       (split-string
-                        (gnugo-query "fixed_handicap %d" h)))))))))
+  (if (< 0 (gnugo-get :handicap))
+        (gnugo-query (format "fixed_handicap %d" (gnugo-get :handicap))))
+  (gnugo-initialize-sgf-tree)
   (set-process-sentinel (gnugo-get :proc) 'gnugo-sentinel)
   (set-process-buffer (gnugo-get :proc) (current-buffer))
   (gnugo-put :waiting-start (current-time))
@@ -1679,6 +2008,10 @@
           (gnugo-put :center-position
             (get-text-property (point) 'gnugo-position))))
       ;; first move
+      (if (and (fboundp 'display-images-p) (display-images-p))
+         (progn
+           (gnugo-toggle-image-display)
+           (gnugo-refresh t)))
       (gnugo-put :game-start-time (current-time))
       (let ((g (gnugo-get :gnugo-color))
             (n (gnugo-get :handicap))
@@ -1716,6 +2049,13 @@
                                    ((consp x) (car x))
                                    (t (gnugo-position))))))
             ("u"        . gnugo-undo-two-moves)
+            ("r"        . gnugo-redo-two-moves)
+            ("f"        . gnugo-redo)
+            ("b"        . gnugo-undo)
+            ("j"        . (lambda (x) (interactive "nJump to move number: ")
+                           (gnugo-jump-to-move x)))
+            ("<"        . gnugo-jump-to-beginning)
+           (">"        . gnugo-jump-to-end)
             ("\C-l"     . gnugo-refresh)
             ("\M-_"     . bury-buffer)
             ("_"        . bury-buffer)
@@ -1723,11 +2063,14 @@
             ("i"        . (lambda () (interactive)
                             (gnugo-toggle-image-display)
                             (save-excursion (gnugo-refresh))))
+           ("e"        . gnugo-toggle-edit-mode)
             ("w"        . gnugo-worm-stones)
             ("W"        . gnugo-worm-data)
             ("d"        . gnugo-dragon-stones)
             ("D"        . gnugo-dragon-data)
             ("t"        . gnugo-toggle-dead-group)
+            ("g"        . gnugo-toggle-grid)
+            ("v"        . gnugo-view-regression)
             ("!"        . gnugo-estimate-score)
             (":"        . gnugo-command)
             (";"        . gnugo-command)
@@ -1799,7 +2142,7 @@
     (defgtp '(boardsize
               clear_board
               fixed_handicap
-              loadsgf)
+             loadsgf)
       :output :discard
       :post-hook (lambda ()
                    (dolist (prop '(:game-over





reply via email to

[Prev in Thread] Current Thread [Next in Thread]