Commits

Anonymous committed 86c4d83

sokoban.el: Added `undo' feature.
sokoban.el: Added number of blocks done/total to score and modeline

Comments (0)

Files changed (2)

+1998-06-04  Glynn Clements  <glynn@sensei.co.uk>
+
+	* sokoban.el:	Added `undo' feature.
+	Added number of blocks done/total to score and modeline
+
 1998-04-07  SL Baur  <steve@altair.xemacs.org>
 
 	* Makefile (binkit): Use TAR/EXCLUDES variables from XEmacs.rules.
 ;; Copyright (C) 1997 Glynn Clements <glynn@sensei.co.uk>
 
 ;; Author: Glynn Clements <glynn@sensei.co.uk>
-;; Version: 1.02
+;; Version: 1.03
 ;; Created: 1997-09-11
 ;; Keywords: games
 
 ;;   added bounds check to sokoban-goto-level
 ;;   added popup menu
 ;;   display level and score in modeline
+;; Modified: 1998-06-04, added `undo' feature
+;;   added number of blocks done/total to score and modeline
 
 ;; URL: ftp://sensei.co.uk/misc/elisp-games.tar.gz
 ;; Tested with XEmacs 20.3/4/5 and Emacs 19.34
 (defvar sokoban-done 0)
 (defvar sokoban-mouse-x 0)
 (defvar sokoban-mouse-y 0)
+(defvar sokoban-undo-list nil)
 
 (make-variable-buffer-local 'sokoban-level)
 (make-variable-buffer-local 'sokoban-level-map)
 (make-variable-buffer-local 'sokoban-done)
 (make-variable-buffer-local 'sokoban-mouse-x)
 (make-variable-buffer-local 'sokoban-mouse-y)
+(make-variable-buffer-local 'sokoban-undo-list)
 
 ;; ;;;;;;;;;;;;; keymaps ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (define-key sokoban-mode-map [down-mouse-2]	'sokoban-mouse-event-start)
 (define-key sokoban-mode-map [mouse-2] 'sokoban-mouse-event-end)
 
+(define-key sokoban-mode-map [(control ?/)]	'sokoban-undo)
+
 (defvar sokoban-null-map
   (make-sparse-keymap 'sokoban-null-map))
 
 
 (defun sokoban-draw-score ()
   (let ((strings (vector (format "Moves:  %05d" sokoban-moves)
-			 (format "Pushes: %05d" sokoban-pushes))))
+			 (format "Pushes: %05d" sokoban-pushes)
+			 (format "Done:   %d/%d"
+				 sokoban-done
+				 sokoban-targets))))
     (loop for y from 0 to 1 do
 	  (let* ((string (aref strings y))
 		 (len (length string)))
 				     (+ sokoban-score-y y)
 				     (aref string x))))))
   (setq mode-line-format
-	(format "Sokoban:   Level: %3d   Moves: %05d   Pushes: %05d"
-		sokoban-level sokoban-moves sokoban-pushes))
+	(format "Sokoban:   Level: %3d   Moves: %05d   Pushes: %05d   Done: %d/%d"
+		sokoban-level sokoban-moves sokoban-pushes
+		sokoban-done sokoban-targets))
   (force-mode-line-update))
 
+(defun sokoban-add-move (dx dy)
+  (setq sokoban-undo-list
+	(cons (list 'move dx dy) sokoban-undo-list))
+  (incf sokoban-moves)
+  (sokoban-draw-score))
+
+(defun sokoban-add-push (dx dy)
+  (setq sokoban-undo-list
+	(cons (list 'push dx dy) sokoban-undo-list))
+  (incf sokoban-moves)
+  (incf sokoban-pushes)
+  (sokoban-draw-score))
+
+(defun sokoban-undo ()
+  (interactive)
+  (if (null sokoban-undo-list)
+      (message "Nothing to undo")
+    (let* ((entry (car sokoban-undo-list))
+	   (type (car entry))
+	   (dx (cadr entry))
+	   (dy (caddr entry)))
+      (setq sokoban-undo-list (cdr sokoban-undo-list))
+      (cond ((eq type 'push)
+	     (let* ((x (+ sokoban-x dx))
+		    (y (+ sokoban-y dy))
+		    (c (sokoban-get-floor x y)))
+	       (gamegrid-set-cell x y c)
+	       (if (eq c sokoban-target)
+		   (decf sokoban-done))
+	       (gamegrid-set-cell sokoban-x sokoban-y sokoban-block)
+	       (setq c (sokoban-get-floor sokoban-x sokoban-y))
+	       (if (eq c sokoban-target)
+		   (incf sokoban-done)))
+	     (setq sokoban-x (- sokoban-x dx))
+	     (setq sokoban-y (- sokoban-y dy))
+	     (gamegrid-set-cell sokoban-x sokoban-y sokoban-player)
+	     (decf sokoban-pushes)
+	     (decf sokoban-moves))
+	    ((eq type 'move)
+	     (let ((c (sokoban-get-floor sokoban-x sokoban-y)))
+	       (gamegrid-set-cell sokoban-x sokoban-y c))
+	     (setq sokoban-x (- sokoban-x dx))
+	     (setq sokoban-y (- sokoban-y dy))
+	     (gamegrid-set-cell sokoban-x sokoban-y sokoban-player)
+	     (decf sokoban-moves))
+	    (t
+	     (message "Invalid entry in sokoban-undo-list")))
+      (sokoban-draw-score))))
+
 (defun sokoban-move (dx dy)
   (let* ((x (+ sokoban-x dx))
 	 (y (+ sokoban-y dy))
 	   (gamegrid-set-cell sokoban-x
 			      sokoban-y
 			      sokoban-player)
-	   (incf sokoban-moves)
-	   (sokoban-draw-score))
+	   (sokoban-add-move dx dy))
 	  ((eq c sokoban-block)
 	   (let* ((xx (+ x dx))
 		  (yy (+ y dy))
 							  sokoban-y))
 		    (setq sokoban-x x
 			  sokoban-y y)
-		    (incf sokoban-moves)
-		    (incf sokoban-pushes)
-		    (cond ((eq cc sokoban-target)
-			   (incf sokoban-done)
-			   (cond ((= sokoban-done sokoban-targets)
-				  (sit-for 3)
-				  (sokoban-next-level)))))
-		    (sokoban-draw-score))))))))
+		    (if (eq cc sokoban-target)
+			(incf sokoban-done))
+		    (sokoban-add-push dx dy)
+		    (cond ((= sokoban-done sokoban-targets)
+			   (sit-for 3)
+			   (sokoban-next-level))))))))))
 
 (defun sokoban-mouse-event-start (event)
   (interactive "e")
   (interactive)
   (setq sokoban-moves 0
 	sokoban-pushes 0
-	sokoban-done 0)
+	sokoban-done 0
+	sokoban-undo-list nil)
   (sokoban-get-level-data)
   (sokoban-init-buffer)
   (sokoban-draw-score))