Mercurial > emacs
changeset 25259:9f7a9dceb11b
Mostly rewritten. Customized. To support an s2G
doomsday clock, speed control is added and changes are made to
allow large numbers of rings: rings now show the whole ring
number, not just the last digit; consecutive rings are allowed to
be the same size when necessary to fit all the rings in the
window; and poles can be oriented horizontally. Face support is
thrown in gratuitously.
(hanoi): Changed default number of rings back to 3.
(hanoi-unix, hanoi-unix-64): New commands
(hanoi-horizontal-flag, hanoi-move-period, hanoi-use-faces,
hanoi-pole-face, hanoi-base-face, hanoi-even-ring-face,
hanoi-odd-ring-face): New variables.
(hanoi-internal, hanoi-current-time-float, hanoi-put-face,
hanoi-n, hanoi-insert-ring, hanoi-goto-char, hanoi-sit-for,
hanoi-ring-to-pos, hanoi-pos-on-tower-p): New functions.
(hanoi-0): Renamed from hanoi0, for symmetry with hanoi-n.
(hanoi-topos, hanoi-draw-ring): Removed.
author | Karl Heuer <kwzh@gnu.org> |
---|---|
date | Sat, 14 Aug 1999 03:24:48 +0000 |
parents | 8eefac3ecebf |
children | 0c8c07d1d12f |
files | lisp/play/hanoi.el |
diffstat | 1 files changed, 385 insertions(+), 171 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/play/hanoi.el Sat Aug 14 03:13:35 1999 +0000 +++ b/lisp/play/hanoi.el Sat Aug 14 03:24:48 1999 +0000 @@ -1,4 +1,4 @@ -;;; hanoi.el --- towers of hanoi in GNUmacs +;;; hanoi.el --- towers of hanoi in Emacs ;; Author: Damon Anton Permezel ;; Maintainer: FSF @@ -7,6 +7,10 @@ ; Author (a) 1985, Damon Anton Permezel ; This is in the public domain ; since he distributed it without copyright notice in 1985. +; +; Support for horizontal poles, large numbers of rings, real-time, +; faces, defcustom, and Towers of Unix added in 1999 by Alakazam +; Petrofsky <Alakazam@Petrofsky.Berkeley.CA.US>. ;;; Commentary: @@ -32,195 +36,405 @@ ;; posts in it surrounded by 21 golden discs. Monks, acting out the ;; command of an ancient prophecy, have been moving these disks, in ;; accordance with the rules of the puzzle, once every day since the -;; monastery was founded over a thousand years ago. They are said +;; monastery was founded over a thousand years ago. They are said to ;; believe that when the last move of the puzzle is completed, the ;; world will end in a clap of thunder. Fortunately, they are nowhere ;; even close to being done... +;; +;; 1999 addition: The `Towers of Unix' command (hanoi-unix) stems from +;; the never-disproven legend of a Eunuch monastery at Princeton that +;; contains a large air-conditioned room with three time-worn posts in +;; it surrounded by 32 silicon discs. Nimble monks, acting out the +;; command of an ancient prophecy, have been moving these disks, in +;; accordance with the rules of the puzzle, once every second since +;; the monastery was founded almost a billion seconds ago. They are +;; said to believe that when the last move of the puzzle is completed, +;; the world will reboot in a clap of thunder. Actually, because the +;; bottom disc is blocked by the "Do not feed the monks" sign, it is +;; believed the End will come at the time that disc is to be moved... ;;; Code: -;;; -;;; hanoi-topos - direct cursor addressing -;;; -(defun hanoi-topos (row col) - (goto-line row) - (beginning-of-line) - (forward-char col)) +(eval-when-compile + (require 'cl)) + +(defgroup hanoi nil + "The Towers of Hanoi." + :group 'games) + +(defcustom hanoi-horizontal-flag nil + "*If non-nil, hanoi poles are oriented horizontally." + :group 'hanoi :type 'boolean) + +(defcustom hanoi-move-period 1.0 + "*Time, in seconds, for each pole-to-pole move of a ring. +If nil, move rings as fast as possible while displaying all +intermediate positions." + :group 'hanoi :type '(restricted-sexp :match-alternatives (numberp 'nil))) + +(defcustom hanoi-use-faces nil + "*If nil, all hanoi-*-face variables are ignored." + :group 'hanoi :type 'boolean) + +(defcustom hanoi-pole-face 'highlight + "*Face for poles. Ignored if hanoi-use-faces is nil." + :group 'hanoi :type 'face) + +(defcustom hanoi-base-face 'highlight + "*Face for base. Ignored if hanoi-use-faces is nil." + :group 'hanoi :type 'face) + +(defcustom hanoi-even-ring-face 'region + "*Face for even-numbered rings. Ignored if hanoi-use-faces is nil." + :group 'hanoi :type 'face) + +(defcustom hanoi-odd-ring-face 'secondary-selection + "*Face for odd-numbered rings. Ignored if hanoi-use-faces is nil." + :group 'hanoi :type 'face) + ;;; ;;; hanoi - user callable Towers of Hanoi ;;; ;;;###autoload (defun hanoi (nrings) - "Towers of Hanoi diversion. Argument is number of rings." - (interactive "p") - (if (<= nrings 1) (setq nrings 7)) - (let* (floor-row - fly-row - (window-height (1- (window-height (selected-window)))) - (window-width (window-width (selected-window))) + "Towers of Hanoi diversion. Use NRINGS rings." + (interactive + (list (if (null current-prefix-arg) + 3 + (prefix-numeric-value current-prefix-arg)))) + (if (< nrings 0) + (error "Negative number of rings")) + (hanoi-internal nrings (make-list nrings 0) (hanoi-current-time-float))) + +;;;###autoload +(defun hanoi-unix () + "Towers of Hanoi, UNIX doomsday version. +Displays 32-ring towers that have been progressing at one move per +second since 1970-01-01 00:00:00 GMT. + +Repent before ring 31 moves." + (interactive) + (let* ((start (ftruncate (hanoi-current-time-float))) + (bits (loop repeat 32 + for x = (/ start (expt 2.0 31)) then (* x 2.0) + collect (truncate (mod x 2.0)))) + (hanoi-move-period 1.0)) + (hanoi-internal 32 bits start))) + +;;;###autoload +(defun hanoi-unix-64 () + "Like hanoi-unix, but pretend to have a 64-bit clock. +This is, necessarily (as of emacs 20.3), a crock. When the +current-time interface is made s2G-compliant, hanoi.el will need +to be updated." + (interactive) + (let* ((start (ftruncate (hanoi-current-time-float))) + (bits (loop repeat 64 + for x = (/ start (expt 2.0 63)) then (* x 2.0) + collect (truncate (mod x 2.0)))) + (hanoi-move-period 1.0)) + (hanoi-internal 64 bits start))) + +(defun hanoi-internal (nrings bits start-time) + "Towers of Hanoi internal interface. Use NRINGS rings. +Start after n steps, where BITS is a big-endian list of the bits of n. +BITS must be of length nrings. Start at START-TIME." + (switch-to-buffer "*Hanoi*") + (buffer-disable-undo (current-buffer)) + (unwind-protect + (let* + (;; These lines can cause emacs to crash if you ask for too + ;; many rings. If you uncomment them, on most systems you + ;; can get 10,000+ rings. + ;;(max-specpdl-size (max max-specpdl-size (* nrings 15))) + ;;(max-lisp-eval-depth (max max-lisp-eval-depth (+ nrings 20))) + (vert (not hanoi-horizontal-flag)) + (pole-width (length (format "%d" (max 0 (1- nrings))))) + (pole-char (if vert ?\| ?\-)) + (base-char (if vert ?\= ?\|)) + (base-len (max (+ 8 (* pole-width 3)) + (1- (if vert (window-width) (window-height))))) + (max-ring-diameter (/ (- base-len 2) 3)) + (pole1-coord (/ max-ring-diameter 2)) + (pole2-coord (/ base-len 2)) + (pole3-coord (- base-len (/ (1+ max-ring-diameter) 2))) + (pole-coords (list pole1-coord pole2-coord pole3-coord)) + ;; Number of lines displayed below the bottom-most rings. + (base-lines + (min 3 (max 0 (- (1- (if vert (window-height) (window-width))) + (+ 2 nrings))))) + + ;; These variables will be set according to hanoi-horizontal-flag: - ;; This is half the spacing to use between poles. - (pole-spacing (/ window-width 6))) - (if (not (and (> window-height (1+ nrings)) - (> pole-spacing nrings))) - (progn - (delete-other-windows) - (if (not (and (> (setq window-height - (1- (window-height (selected-window)))) - (1+ nrings)) - (> (setq pole-spacing (/ window-width 6)) - nrings))) - (error "Window is too small (need at least %dx%d)" - (* 6 (1+ nrings)) (+ 2 nrings))))) - (setq floor-row (if (> (- window-height 3) (1+ nrings)) - (- window-height 3) window-height)) - (let ((fly-row (- floor-row nrings 1)) - ;; pole: column . fill height - (pole-1 (cons (1- pole-spacing) floor-row)) - (pole-2 (cons (1- (* 3 pole-spacing)) floor-row)) - (pole-3 (cons (1- (* 5 pole-spacing)) floor-row)) - (rings (make-vector nrings nil))) - ;; construct the ring list - (let ((i 0)) - (while (< i nrings) - ;; ring: [pole-number string empty-string] - (aset rings i (vector nil - (make-string (+ i i 3) (+ ?0 (% i 10))) - (make-string (+ i i 3) ?\ ))) - (setq i (1+ i)))) - ;; - ;; init the screen - ;; - (switch-to-buffer "*Hanoi*") - (setq buffer-read-only nil) - (buffer-disable-undo (current-buffer)) - (erase-buffer) - (let ((i 0)) - (while (< i floor-row) - (setq i (1+ i)) - (insert-char ?\ (1- window-width)) - (insert ?\n))) - (insert-char ?= (1- window-width)) + ;; line-offset is the number of characters per line in the buffer. + line-offset + ;; fly-row-start is the buffer position of the leftmost or + ;; uppermost position in the fly row. + fly-row-start + ;; Adding fly-step to a buffer position moves you one step + ;; along the fly row in the direction from pole1 to pole2. + fly-step + ;; Adding baseward-step to a buffer position moves you one step + ;; toward the base. + baseward-step + ) + (setq buffer-read-only nil) + (erase-buffer) + (setq truncate-lines t) + (if hanoi-horizontal-flag + (progn + (setq line-offset (+ base-lines nrings 3)) + (setq fly-row-start (1- line-offset)) + (setq fly-step line-offset) + (setq baseward-step -1) + (loop repeat base-len do + (unless (zerop base-lines) + (insert-char ?\ (1- base-lines)) + (insert base-char) + (hanoi-put-face (1- (point)) (point) hanoi-base-face)) + (insert-char ?\ (+ 2 nrings)) + (insert ?\n)) + (delete-char -1) + (loop for coord in pole-coords do + (loop for row from (- coord (/ pole-width 2)) + for start = (+ (* row line-offset) base-lines 1) + repeat pole-width do + (subst-char-in-region start (+ start nrings 1) + ?\ pole-char) + (hanoi-put-face start (+ start nrings 1) + hanoi-pole-face)))) + ;; vertical + (setq line-offset (1+ base-len)) + (setq fly-step 1) + (setq baseward-step line-offset) + (let ((extra-lines (- (1- (window-height)) (+ nrings 2) base-lines))) + (insert-char ?\n (max 0 extra-lines)) + (setq fly-row-start (point)) + (insert-char ?\ base-len) + (insert ?\n) + (loop repeat (1+ nrings) + with pole-line = + (loop with line = (make-string base-len ?\ ) + for coord in pole-coords + for start = (- coord (/ pole-width 2)) + for end = (+ start pole-width) do + (hanoi-put-face start end hanoi-pole-face line) + (loop for i from start below end do + (aset line i pole-char)) + finally return line) + do (insert pole-line ?\n)) + (insert-char base-char base-len) + (hanoi-put-face (- (point) base-len) (point) hanoi-base-face) + (set-window-start (selected-window) + (1+ (* baseward-step + (max 0 (- extra-lines))))))) - (let ((n 1)) - (while (< n 6) - (hanoi-topos fly-row (1- (* n pole-spacing))) - (setq n (+ n 2)) - (let ((i fly-row)) - (while (< i floor-row) - (setq i (1+ i)) - (next-line 1) - (insert ?\|) - (delete-char 1) - (backward-char 1))))) - ;(sit-for 0) - ;; - ;; now draw the rings in their initial positions - ;; - (let ((i 0) - ring) - (while (< i nrings) - (setq ring (aref rings (- nrings 1 i))) - (aset ring 0 (- floor-row i)) - (hanoi-topos (cdr pole-1) - (- (car pole-1) (- nrings i))) - (hanoi-draw-ring ring t nil) - (setcdr pole-1 (1- (cdr pole-1))) - (setq i (1+ i)))) - (setq buffer-read-only t) - (sit-for 0) - ;; Disable display of line and column numbers, for speed. - (let ((line-number-mode nil) - (column-number-mode nil)) - ;; do it! - (hanoi0 (1- nrings) pole-1 pole-2 pole-3)) - (goto-char (point-min)) - (message "Done") - (setq buffer-read-only t) - (force-mode-line-update) - (sit-for 0)))) + (let + (;; each pole is a pair of buffer positions: + ;; the car is the position of the top ring currently on the pole, + ;; (or the base of the pole if it is empty). + ;; the cdr is in the fly-row just above the pole. + (poles (loop for coord in pole-coords + for fly-pos = (+ fly-row-start (* fly-step coord)) + for base = (+ fly-pos (* baseward-step (+ 2 nrings))) + collect (cons base fly-pos))) + ;; compute the string for each ring and make the list of + ;; ring pairs. Each ring pair is initially (str . diameter). + ;; Once placed in buffer it is changed to (center-pos . diameter). + (rings + (loop + ;; radii are measured from the edge of the pole out. + ;; So diameter = 2 * radius + pole-width. When + ;; there's room, we make each ring's radius = + ;; pole-number + 1. If there isn't room, we step + ;; evenly from the max radius down to 1. + with max-radius = (min nrings + (/ (- max-ring-diameter pole-width) 2)) + for n from (1- nrings) downto 0 + for radius = (1+ (/ (* n max-radius) nrings)) + for diameter = (+ pole-width (* 2 radius)) + with format-str = (format "%%0%dd" pole-width) + for str = (concat (if vert "<" "^") + (make-string (1- radius) (if vert ?\- ?\|)) + (format format-str n) + (make-string (1- radius) (if vert ?\- ?\|)) + (if vert ">" "v")) + for face = + (if (oddp n) hanoi-odd-ring-face hanoi-even-ring-face) + do (hanoi-put-face 0 (length str) face str) + collect (cons str diameter))) + ;; Disable display of line and column numbers, for speed. + (line-number-mode nil) (column-number-mode nil)) + ;; do it! + (hanoi-n bits rings (car poles) (cadr poles) (caddr poles) + start-time)) + (message "Done")) + (setq buffer-read-only t) + (force-mode-line-update))) + +(defun hanoi-current-time-float () + "Return values from current-time combined into a single float." + (destructuring-bind (high low micros) (current-time) + (+ (* high 65536.0) low (/ micros 1000000.0)))) + +(defun hanoi-put-face (start end value &optional object) + "If hanoi-use-faces is non-nil, call put-text-property for face property." + (if hanoi-use-faces + (put-text-property start end 'face value object))) + + +;;; Functions with a start-time argument (hanoi-0, hanoi-n, and +;;; hanoi-move-ring) start working at start-time and return the ending +;;; time. If hanoi-move-period is nil, start-time is ignored and the +;;; return value is junk. ;;; -;;; hanoi0 - work horse of hanoi -;;; -(defun hanoi0 (n from to work) - (cond ((input-pending-p) - (signal 'quit (list "I can tell you've had enough"))) - ((< n 0)) +;;; hanoi-0 - work horse of hanoi +(defun hanoi-0 (rings from to work start-time) + (if (null rings) + start-time + (hanoi-0 (cdr rings) work to from + (hanoi-move-ring (car rings) from to + (hanoi-0 (cdr rings) from work to start-time))))) + +;; start after n moves, where BITS is a big-endian list of the bits of n. +;; BITS must be of same length as rings. +(defun hanoi-n (bits rings from to work start-time) + (cond ((null rings) + ;; All rings have been placed in starting positions. Update display. + (hanoi-sit-for 0) + start-time) + ((zerop (car bits)) + (hanoi-insert-ring (car rings) from) + (hanoi-0 (cdr rings) work to from + (hanoi-move-ring (car rings) from to + (hanoi-n (cdr bits) (cdr rings) from work to + start-time)))) (t - (hanoi0 (1- n) from work to) - (hanoi-move-ring n from to) - (hanoi0 (1- n) work to from)))) + (hanoi-insert-ring (car rings) to) + (hanoi-n (cdr bits) (cdr rings) work to from start-time)))) + +;; put never-before-placed RING on POLE and update their cars. +(defun hanoi-insert-ring (ring pole) + (decf (car pole) baseward-step) + (let ((str (car ring)) + (start (- (car pole) (* (/ (cdr ring) 2) fly-step)))) + (setcar ring (car pole)) + (loop for pos upfrom start by fly-step + for i below (cdr ring) do + (subst-char-in-region pos (1+ pos) (char-after pos) (aref str i)) + (set-text-properties pos (1+ pos) (text-properties-at i str))) + (hanoi-goto-char (car pole)))) + +;; like goto-char, but if position is outside the window, then move to +;; corresponding position in the first row displayed. +(defun hanoi-goto-char (pos) + (goto-char (if (or hanoi-horizontal-flag (<= (window-start) pos)) + pos + (+ (window-start) (% (- pos fly-row-start) baseward-step))))) -;;; -;;; hanoi-move-ring - move ring 'n' from 'from' to 'to' -;;; -;;; -(defun hanoi-move-ring (n from to) - (let ((ring (aref rings n)) ; ring <- ring: (ring# . row) - (buffer-read-only nil)) - (let ((row (aref ring 0)) ; row <- row ring is on - (col (- (car from) n 1)) ; col <- left edge of ring - (dst-col (- (car to) n 1)) ; dst-col <- dest col for left edge - (dst-row (cdr to))) ; dst-row <- dest row for ring - (hanoi-topos row col) - (while (> row fly-row) ; move up to the fly row - (hanoi-draw-ring ring nil t) ; blank out ring - (previous-line 1) ; move up a line - (hanoi-draw-ring ring t nil) ; redraw - (sit-for 0) - (setq row (1- row))) - (setcdr from (1+ (cdr from))) ; adjust top row - ;; - ;; fly the ring over to the right pole - ;; - (while (not (equal dst-col col)) - (cond ((> dst-col col) ; dst-col > col: right shift - (end-of-line 1) - (delete-backward-char 2) - (beginning-of-line 1) - (insert ?\ ?\ ) - (sit-for 0) - (setq col (1+ (1+ col)))) - ((< dst-col col) ; dst-col < col: left shift - (beginning-of-line 1) - (delete-char 2) - (end-of-line 1) - (insert ?\ ?\ ) - (sit-for 0) - (setq col (1- (1- col)))))) - ;; - ;; let the ring float down - ;; - (hanoi-topos fly-row dst-col) - (while (< row dst-row) ; move down to the dest row - (hanoi-draw-ring ring nil (> row fly-row)) ; blank out ring - (next-line 1) ; move down a line - (hanoi-draw-ring ring t nil) ; redraw ring - (sit-for 0) - (setq row (1+ row))) - (aset ring 0 dst-row) - (setcdr to (1- (cdr to)))))) ; adjust top row +;; do one pole-to-pole move and update the ring and pole pairs. +(defun hanoi-move-ring (ring from to start-time) + (incf (car from) baseward-step) + (decf (car to) baseward-step) + (let* ;; We move flywards-steps steps up the pole to the fly row, + ;; then fly fly-steps steps across the fly row, then go + ;; baseward-steps steps down the new pole. + ((flyward-steps (/ (- (car ring) (cdr from)) baseward-step)) + (fly-steps (abs (/ (- (cdr to) (cdr from)) fly-step))) + (directed-fly-step (/ (- (cdr to) (cdr from)) fly-steps)) + (baseward-steps (/ (- (car to) (cdr to)) baseward-step)) + (total-steps (+ flyward-steps fly-steps baseward-steps)) + ;; A step is a character cell. A tick is a time-unit. To + ;; make horizontal and vertical motion appear roughly the + ;; same speed, we allow one tick per horizontal step and two + ;; ticks per vertical step. + (ticks-per-pole-step (if hanoi-horizontal-flag 1 2)) + (ticks-per-fly-step (if hanoi-horizontal-flag 2 1)) + (flyward-ticks (* ticks-per-pole-step flyward-steps)) + (fly-ticks (* ticks-per-fly-step fly-steps)) + (baseward-ticks (* ticks-per-pole-step baseward-steps)) + (total-ticks (+ flyward-ticks fly-ticks baseward-ticks)) + (tick-to-pos + ;; Return the buffer position of the ring after TICK ticks. + (lambda (tick) + (cond + ((<= tick flyward-ticks) + (+ (cdr from) + (* baseward-step + (- flyward-steps (/ tick ticks-per-pole-step))))) + ((<= tick (+ flyward-ticks fly-ticks)) + (+ (cdr from) + (* directed-fly-step + (/ (- tick flyward-ticks) ticks-per-fly-step)))) + (t + (+ (cdr to) + (* baseward-step + (/ (- tick flyward-ticks fly-ticks) + ticks-per-pole-step)))))))) + (if hanoi-move-period + (loop for elapsed = (- (hanoi-current-time-float) start-time) + while (< elapsed hanoi-move-period) + with tick-period = (/ (float hanoi-move-period) total-ticks) + for tick = (ceiling (/ elapsed tick-period)) do + (hanoi-ring-to-pos ring (funcall tick-to-pos tick)) + (hanoi-sit-for (- (* tick tick-period) elapsed))) + (loop for tick from 1 to total-ticks by 2 do + (hanoi-ring-to-pos ring (funcall tick-to-pos tick)) + (hanoi-sit-for 0))) + ;; Always make last move to keep pole and ring data consistent + (hanoi-ring-to-pos ring (car to)) + (if hanoi-move-period (+ start-time hanoi-move-period)))) -;;; -;;; draw-ring - draw the ring at point, leave point unchanged -;;; -;;; Input: -;;; ring -;;; f1 - flag: t -> draw, nil -> erase -;;; f2 - flag: t -> erasing and need to draw ?\| -;;; -(defun hanoi-draw-ring (ring f1 f2) - (save-excursion - (let* ((string (if f1 (aref ring 1) (aref ring 2))) - (len (length string))) - (delete-char len) - (insert string) - (if f2 - (progn - (backward-char (/ (+ len 1) 2)) - (delete-char 1) (insert ?\|)))))) +;; update display and pause, quitting with a pithy comment if the user +;; hits a key. +(defun hanoi-sit-for (seconds) + (sit-for seconds) + (if (input-pending-p) + (signal 'quit '("I can tell you've had enough")))) + +;; move ring to a given buffer position and update ring's car. +(defun hanoi-ring-to-pos (ring pos) + (unless (= (car ring) pos) + (let* ((start (- (car ring) (* (/ (cdr ring) 2) fly-step))) + (new-start (- pos (- (car ring) start)))) + (if hanoi-horizontal-flag + (loop for i below (cdr ring) + for j = (if (< new-start start) i (- (cdr ring) i 1)) + for old-pos = (+ start (* j fly-step)) + for new-pos = (+ new-start (* j fly-step)) do + (transpose-regions old-pos (1+ old-pos) new-pos (1+ new-pos))) + (let ((end (+ start (cdr ring))) + (new-end (+ new-start (cdr ring)))) + (if (< (abs (- new-start start)) (- end start)) + ;; Overlap. Adjust bounds + (if (< start new-start) + (setq new-start end) + (setq new-end start))) + (transpose-regions start end new-start new-end t)))) + ;; If moved on or off a pole, redraw pole chars. + (unless (eq (hanoi-pos-on-tower-p (car ring)) (hanoi-pos-on-tower-p pos)) + (let* ((pole-start (- (car ring) (* fly-step (/ pole-width 2)))) + (pole-end (+ pole-start (* fly-step pole-width))) + (on-pole (hanoi-pos-on-tower-p (car ring))) + (new-char (if on-pole pole-char ?\ )) + (curr-char (if on-pole ?\ pole-char)) + (face (if on-pole hanoi-pole-face nil))) + (if hanoi-horizontal-flag + (loop for pos from pole-start below pole-end by line-offset do + (subst-char-in-region pos (1+ pos) curr-char new-char) + (hanoi-put-face pos (1+ pos) face)) + (subst-char-in-region pole-start pole-end curr-char new-char) + (hanoi-put-face pole-start pole-end face)))) + (setcar ring pos)) + (hanoi-goto-char pos)) + +;; Check if a buffer position lies on a tower (vis. in the fly row). +(defun hanoi-pos-on-tower-p (pos) + (if hanoi-horizontal-flag + (/= (% pos fly-step) fly-row-start) + (>= pos (+ fly-row-start baseward-step)))) (provide 'hanoi)