gnugo-devel
[Top][All Lists]
Advanced

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

[gnugo-devel] Patch to gnugo.el


From: bump
Subject: [gnugo-devel] Patch to gnugo.el
Date: Sun, 14 Nov 2004 19:58:37 -0800

This is a patch against Thi's gnugo.el version 2.2.7 available
at http://www.glug.org/people/ttn/software/ttn-pers-elisp/standalone/.
Except for copyright notices this is the same as the gnugo.el
in the current cvs (though NOT 3.6-pre4).

This patch requires a patch to the engine:

http://match.stanford.edu/gnugo/patches/move_history_3_6.1b

The patch adds some functionality that I find very useful
though it probably conflicts a little with Thi's vision
of how gnugo.el is to develop, so I'm not proposing to
add it in this form to GNU Go 3.6, though I hope at least
the bug fixes can go in.

A couple of bugs are fixed: the sgf tree and move
history are made correct after loading an sgf file
(which was a fixme), and gnugo-goto-pos doesn't attempt
to go to PASS.

After this patch, you can scroll forward and backward in the
game using the keystrokes `f' and `b', or undo and redo two
moves at a time with `u' and `r'. You can also jump to the
beginning or end of the game with `<' and `>' or to an
arbitrary move number with `j'. If you go to an
arbitrary move then enter a move at that point, the future
game record is discarded, and the engine will counter
with a move. Potentially you can switch colors this
way. But if you don't do play a move, you can browse an
sgf file, just as you could with any sgf editor.

The move number is added to the mode line.

Dan

--- gnugo.el-2.2.7      2004-11-11 08:41:31.712789416 -0800
+++ gnugo.el    2004-11-14 06:52:22.369051536 -0800
@@ -205,12 +205,13 @@
 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 :~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
   ~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.
@@ -304,7 +305,7 @@
  :move-history -- strictly speaking this is redundant since we have the
                   :sgf-tree, but this list is simple to understand and use;
                   see function `gnugo-push-move'
-
+ :future-history -- an undo stack. Undone moves are pushed here.
  :last-waiting  -- seconds and time value, respectively; see `gnugo-push-move'
  :waiting-start
 
@@ -407,16 +408,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 (- (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))))))
 
 (defun gnugo-f (frag)
   (intern (format ":gnugo-%s%s-props" (gnugo-get :diamond) frag)))
@@ -637,6 +639,7 @@
     (when userp
       (gnugo-put :last-user-bpos (and (not passp) (not resignp) move)))
     (gnugo-put :move-history (cons move history))
+    (gnugo-put :future-history nil)
     (gnugo-note (if (string= "black" color) :B :W) move t (not resignp))
     (when resignp
       (gnugo-note :EV "resignation"))
@@ -834,7 +837,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 "~[bwmptu]" cur))
                      (aset cur cut ?%)
                      (setq cut (1+ cut) c (aref cur cut))
                      (aset cur cut ?s)
@@ -843,6 +846,7 @@
                         ,(case c
                            (?b '(or (gnugo-get :black-captures) 0))
                            (?w '(or (gnugo-get :white-captures) 0))
+                           (?m '(length (gnugo-get :move-history)))
                            (?p '(gnugo-other (gnugo-get :last-mover)))
                            (?t '(let ((ws (gnugo-get :waiting-start)))
                                   (if ws
@@ -1154,10 +1158,101 @@
       (insert ")\n")
       (write-file filename))))
 
+(defun gnugo-warp-point ()
+  "Move the cursor to the next-to-last move in the history."
+  (if (cdr (gnugo-get :move-history))
+      (gnugo-goto-pos (car (cdr (gnugo-get :move-history))))))
+
 (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" (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)))
+    (gnugo-put :move-history
+              (mapcar (lambda (x) (nth 1 x)) colorhistory))
+    (gnugo-put :last-mover
+              (car (car colorhistory)))
+    (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")))
+    (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))))
+    (gnugo-note :SZ (gnugo-get :board-size))
+    (gnugo-note :HA (gnugo-get :handicap))
+    (gnugo-note :KM (gnugo-get :komi))
+    (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)
+  (if (equal 
+       (car 
+       (split-string (cdr (gnugo-synchronous-send/return "undo")) " ")) "?")
+      (error "cannot undo"))
+  (gnugo-put :future-history
+    (cons (car (gnugo-get :move-history)) (gnugo-get :future-history)))
+  (if (gnugo-get :move-history)
+      (gnugo-put :move-history (cdr (gnugo-get :move-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-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 (car (gnugo-get :future-history)))
+         (move (format "play %s %s" (gnugo-get :user-color) pos))
+        (accept (cdr (gnugo-synchronous-send/return move))))
+    (gnugo-note (if (string= "black" (gnugo-get :user-color)) :B :W) pos t t)
+    (gnugo-put :future-history (cdr (gnugo-get :future-history)))
+    (gnugo-put :move-history (cons pos (gnugo-get :move-history)))
+    (gnugo-put :user-color (gnugo-get :last-mover))
+    (gnugo-put :gnugo-color (gnugo-other (gnugo-get :last-mover)))
+    (gnugo-put :last-mover (gnugo-other (gnugo-get :last-mover)))
+    (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)
   "Undo moves on the GNUGO Board, based on SPEC, a string.
@@ -1168,7 +1263,9 @@
 moves from the history, signaling an error if the history is exhausted
 before finishing.  Otherwise, signal \"bad spec\" error.
 
-Refresh the board for each move undone.  If (in the case where SPEC is
+Refresh the board for each move undone. Warp the cursor to the next
+to the next-to-last move (which will be the next move undone if
+the command is executed again). If (in the case where SPEC is
 a number) after finishing, the color to play is not the user's color,
 schedule a move by GNU Go."
   (gnugo-gate)
@@ -1198,6 +1295,8 @@
       (setq ans (cdr (gnugo-synchronous-send/return "undo")))
       (unless (= ?= (aref ans 0))
         (error ans))
+      (gnugo-put :future-history
+       (cons (car (gnugo-get :move-history)) (gnugo-get :future-history)))
       (gnugo-put :move-history (cdr (gnugo-get :move-history)))
       (gnugo-put :sgf-tree (cdr (gnugo-get :sgf-tree)))
       (gnugo-put :last-mover (gnugo-other (gnugo-get :last-mover)))
@@ -1225,6 +1324,32 @@
                         "1"
                       "2")))
 
+(defun gnugo-jump-to-move (movenum)
+  "scroll forward or backward in the game to the given move."
+  (interactive)
+  (unless 
+      (and
+       (>= movenum 0)
+       (<= movenum (+ (length (gnugo-get :move-history))
+                     (length (gnugo-get :future-history)))))
+    (error "invalid move number"))
+  (while (not (= movenum (length (gnugo-get :move-history))))
+    (if (< movenum (length (gnugo-get :move-history)))
+       (gnugo-undo t)
+      (gnugo-redo t)))
+  (gnugo-refresh t))
+
+(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 (gnugo-get :move-history))
+                        (length (gnugo-get :future-history)))))
+
 (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
@@ -1398,7 +1523,8 @@
             (let ((hook
                    ;; do not elide this binding; `run-hooks' needs it
                    (plist-get spec :post-hook)))
-              (run-hooks 'hook))))))))
+              (run-hooks 'hook))))
+       (gnugo-refresh t)))))
 
 ;;;---------------------------------------------------------------------------
 ;;; Major mode for interacting with a GNUGO subprocess
@@ -1419,12 +1545,23 @@
 
   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
+
+  C-l           Run `gnugo-refresh' to redraw the board.
 
   _ or M-_      Bury the Board buffer (when the boss is near).
 
@@ -1442,7 +1579,9 @@
 
   !             Run `gnugo-estimate-score'.
 
-  : or ;        Run `gnugo-command' (for GTP commands to GNU Go).
+  : or ;        Run `gnugo-command' (for GTP commands to GNU Go). For
+                example, `showboard' will draw the board in ascii with
+                a coordinate grid, useful for reference.
 
   =             Display board position under point (if valid).
 
@@ -1479,6 +1618,7 @@
           :mode-line
           :mode-line-form
           :move-history
+          :future-history
           :display-using-images
           :xpms
           :local-xpms
@@ -1657,6 +1797,13 @@
                                    ((consp x) (number-to-string (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)





reply via email to

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