;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; NAME:        rearranger.scm
;;
;; DESCRIPTION: Examples of hash/unhash functions for Rearranger games 
;;              with only a single type of piece (o) and with two kinds
;;              of pieces (o and x).
;;
;; AUTHOR:      Dan Garcia  -  University of California, Berkeley
;;              Copyright (C) Dan Garcia, 2002. All rights reserved.
;;
;; DATE:        2002-10-05
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Defaults for Character representations for Blank, O and X
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define *Bc* '-)
(define *Oc* 'o)
(define *Xc* 'x)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; General-purpose functions we'll need later
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (1- n) (- n 1))
(define (1+ n) (+ n 1))
(define (se-0-upto-n n)                         ;; (se-0-upto-n 3) ==> (0 1 2)
  ((repeated (lambda (s) (se s (1+ (last s)))) (- n 1)) '(0)))

;;;;;;;;;;;;;;;;;;;
;; !
;;  Input: n [int] "n"
;; Output: n! (n factorial)
;;;;;;;;;;;;;;;;;;;

(define (! n)
  (if (<= n 1)
      1
      (* n (! (1- n)))))

;;;;;;;;;;;;;;;;;;;
;; c
;;  Input: n [int] "n"
;;       : k [int] "k"
;; Output: n choose k (how many ways to choose k elts from a set of n)
;;;;;;;;;;;;;;;;;;;

(define (c n k)
  (/ (! n) (! k) (! (- n k))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;                                   ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;            REARRANGER-O           ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;                                   ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;
;; rearranger-o-positions
;;  Input: s [slots] "the number of slots of the board"
;;       : o [os]    "the number of o's on the board
;; Output: How many ways to rearrange o os in s slots
;;;;;;;;;;;;;;;;;;;

(define (rearranger-o-positions s o)
  (c s o))

;;;;;;;;;;;;;;;;;;;
;; hash-rearranger-o
;;  Input: b  [board] "the o-only board, e.g., (o - o o -)
;;       : Bc [char]  "the character representing Blank"
;;       : Oc [char]  "the character representing o"
;; Output: n  [int]   "the hashed number of the board"
;;;;;;;;;;;;;;;;;;;

(define (hash-rearranger-o b Bc Oc)
  (hash-rearranger-o-h b (count b) (appearances Oc b) Bc Oc))

;;;;;;;;;;;;;;;;;;;
;; hash-rearranger-o-h (helper)
;;  Input: b  [board] "the o-only board, e.g., (o - o o -)
;;       : s  [slots] "the number of slots of the board"
;;       : o  [os]    "the number of o's on the board
;;       : Bc [char]  "the character representing Blank"
;;       : Oc [char]  "the character representing o"
;; Output: n  [int]   "the hashed number of the board"
;;;;;;;;;;;;;;;;;;;

(define (hash-rearranger-o-h b s o Bc Oc)
  (cond ((or (empty? b) (= s o) (= o 0)) 0)
        ((equal? (first b) Bc) (hash-rearranger-o-h (bf b) (1- s) o Bc Oc))
	(else (+ (rearranger-o-positions (1- s) o)
		 (hash-rearranger-o-h (bf b) (1- s) (1- o) Bc Oc)))))

;; Tests
 
; (se (hash-rearranger-o (se *Bc*) *Bc* *Oc*)       ;; (-)   0
;     (hash-rearranger-o (se *Oc*) *Bc* *Oc*)       ;; (o)   0
;     (hash-rearranger-o (se *Bc* *Bc*) *Bc* *Oc*)  ;; (- -) 0
;     (hash-rearranger-o (se *Bc* *Oc*) *Bc* *Oc*)  ;; (- o) 0
;     (hash-rearranger-o (se *Oc* *Bc*) *Bc* *Oc*)  ;; (o -) 1
;     (hash-rearranger-o (se *Oc* *Oc*) *Bc* *Oc*)) ;; (o o) 0

; (se (hash-rearranger-o (se *Bc* *Bc* *Oc* *Oc*) *Bc* *Oc*)  ;; (- - o o) 0
;    (hash-rearranger-o (se *Bc* *Oc* *Bc* *Oc*) *Bc* *Oc*)  ;; (- o - o) 1
;     (hash-rearranger-o (se *Bc* *Oc* *Oc* *Bc*) *Bc* *Oc*)  ;; (- o o -) 2
;     (hash-rearranger-o (se *Oc* *Bc* *Bc* *Oc*) *Bc* *Oc*)  ;; (o - - o) 3 
;     (hash-rearranger-o (se *Oc* *Bc* *Oc* *Bc*) *Bc* *Oc*)  ;; (o - o -) 4
;     (hash-rearranger-o (se *Oc* *Oc* *Bc* *Bc*) *Bc* *Oc*)) ;; (o o - -) 5

;;;;;;;;;;;;;;;;;;;
;; unhash-rearranger-o
;;  Input: s [slots] "the number of slots of the board"
;;       : o [o]     "the number of o's on the board
;;       : i [int]   "the hashed number of the board"
;;       : Bc [char] "the character representing Blank"
;;       : Oc [char] "the character representing o"
;; Output: b [board] "the o-only board", e.g., (o - o o -)
;;;;;;;;;;;;;;;;;;;

(define (unhash-rearranger-o s o i Bc Oc)
  (cond ((= s 0) '())
        ((= s o)                                         ;; all os
         (se Oc (unhash-rearranger-o (1- s) (1- o) i Bc Oc)))
        ((< i (rearranger-o-positions (1- s) o))         ;; no o cause #pos with o first not > i
         (se Bc (unhash-rearranger-o (1- s) o i Bc Oc)))
        (else 
         (se Oc (unhash-rearranger-o (1- s) (1- o)       ;; yes o cause #pos with o first < i
                   (- i (rearranger-o-positions (1- s) o)) Bc Oc)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;                                   ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;            REARRANGER-O           ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;            HASH / UNHASH          ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;                TESTS              ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;                                   ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;
;; test-unhash-rearranger-o
;;  Input: s [slots] "the number of slots of the board"
;;       : o [o]     "the number of o's on the board
;; Output: A list of all the boards with s slots and o os.
;;;;;;;;;;;;;;;;;;;

(define (test-unhash-rearranger-o s o)
  (map (lambda (i) (unhash-rearranger-o s o i *Bc* *Oc*))
       (se-0-upto-n (rearranger-o-positions s o))))

;; Tests

; (test-unhash-rearranger-o 4 2)
;; ==> ((- - o o) (- o - o) (- o o -) (o - - o) (o - o -) (o o - -))

;;;;;;;;;;;;;;;;;;;
;; test-hash-unhash-rearranger-o
;;  Input: s [slots] "the number of slots of the board"
;;       : o [o]     "the number of o's on the board
;; Output: The sentence (0 1 2 ... num-rearranger-o-positions) if it works
;;;;;;;;;;;;;;;;;;;

(define (test-hash-unhash-rearranger-o s o)
  (map (lambda (b) (hash-rearranger-o b *Bc* *Oc*))
	 (test-unhash-rearranger-o s o)))

;; Tests

; (test-hash-unhash-rearranger-o 5 2) ;; ==> (0 1 2 3 4 5 6 7 8 9)

;;;;;;;;;;;;;;;;;;;
;; test-hash-unhash-rearranger-o-broken?
;;  Input: s [slots] "the number of slots of the board"
;;       : o [o]     "the number of o's on the board
;; Output: if any of the numbers 0 through num-positions unhash & hash wrong,
;;         return the broken list, otherwise #f (not broken) [semipredicate]
;;;;;;;;;;;;;;;;;;;

(define (test-hash-unhash-rearranger-o-broken? s o)
  (if (equal? (test-hash-unhash-rearranger-o s o)
	      (se-0-upto-n (rearranger-o-positions s o)))
      #f                                    ;; not-broken
      (test-hash-unhash-rearranger-o s o))) ;; yep, broken, and here it is!

;; Tests

; (test-hash-unhash-rearranger-o-broken? 5 2) ;; ==> #f (all is well)

;;;;;;;;;;;;;;;;;;;
;; broken-hash-unhash-rearranger-o-sequences
;;  Input: s [slots] "the number of slots of the board"
;; Output: A list of all the sequences that are broken
;;;;;;;;;;;;;;;;;;;

(define (broken-hash-unhash-rearranger-o-sequences s)
  (filter (lambda (broken-sequence) broken-sequence)
	  (map (lambda (o) (test-hash-unhash-rearranger-o-broken? s o)) 
	       (se-0-upto-n (1+ s))))) ;; values for o

;; Tests

; (broken-hash-unhash-rearranger-o-sequences 5) ;; ==> () [that means none broken]

;;;;;;;;;;;;;;;;;;;
;; test-hash-unhash-rearranger-o-up-through-slot
;;        Input: s [slots] "the max number of slots to test up to"
;; Side-Effects: Prints out status whether hash/unhash all works
;;;;;;;;;;;;;;;;;;;

(define (test-hash-unhash-rearranger-o-up-through-slot max-s)
  (newline)
  (display "TESTING rearranger-o hash & unhash together...")
  (newline)
  (for-each (lambda (s) 
	      (display "Slots: ")
	      (display s)
	      (display ", Hash-Unhash ")
	      (let ((broken (broken-hash-unhash-rearranger-o-sequences s)))
		(cond ((null? broken) (display "ok!"))
		      (else (display "BROKEN for s=")
			    (display s)
			    (display ", sequence= ")
			    (display broken))))
	      (newline))
	    (se-0-upto-n (1+ max-s))))

;; Tests

; (test-hash-unhash-rearranger-o-up-through-slot 8) ;; ==>
; TESTING rearranger-o hash & unhash together...
; Slots: 0, Hash-Unhash ok!
; Slots: 1, Hash-Unhash ok!
; Slots: 2, Hash-Unhash ok!
; Slots: 3, Hash-Unhash ok!
; Slots: 4, Hash-Unhash ok!
; Slots: 5, Hash-Unhash ok!
; Slots: 6, Hash-Unhash ok!
; Slots: 7, Hash-Unhash ok!
; Slots: 8, Hash-Unhash ok!

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;                                   ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;           REARRANGER-OX           ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;                                   ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;
;; rearranger-ox-positions
;;  Input: s [slots] "the number of slots of the board"
;;       : o [os]    "the number of o's on the board
;;       : x [xs]    "the number of x's on the board
;; Output: How many ways are there of rearranging this board?
;;;;;;;;;;;;;;;;;;;

(define (rearranger-ox-positions s o x)
  (* (c s (+ o x))    ;; the number of ways to rearrange the pieces/slots
     (c (+ o x) x)))  ;; the number of ways to rearrange the xs & os

;;;;;;;;;;;;;;;;;;;
;; hash-rearranger-ox
;;  Input: b  [board] "the ox board, e.g., (o - x o -)
;;       : Bc [char]  "the character representing Blank"
;;       : Oc [char]  "the character representing o"
;;       : Xc [char]  "the character representing x"
;; Output: n  [int]   "the hashed number of the board"
;;;;;;;;;;;;;;;;;;;

(define (hash-rearranger-ox b Bc Oc Xc)
  (hash-rearranger-ox-h b (count b) (appearances Oc b) (appearances Xc b) Bc Oc Xc))

;;;;;;;;;;;;;;;;;;;
;; hash-rearranger-ox-h (helper)
;;  Input: b  [board] "the ox board, e.g., (o - x o -)
;;       : s  [slots] "the number of slots of the board"
;;       : o  [os]    "the number of o's on the board
;;       : x  [xs]    "the number of x's on the board
;;       : Bc [char]  "the character representing Blank"
;;       : Oc [char]  "the character representing o"
;;       : Xc [char]  "the character representing x"
;; Output: n  [int]   "the hashed number of the board"
;;;;;;;;;;;;;;;;;;;

(define (hash-rearranger-ox-h b s o x Bc Oc Xc)
  (cond ((or (= s o) (= s x) (and (= o 0) (= x 0))) 0)                      ;; base caes, done
	((equal? (first b) Bc)                                              ;; first slot Blank,
	 (hash-rearranger-ox-h (bf b) (1- s) o x Bc Oc Xc))                 ;; ...so skip
	((equal? (first b) Oc)                                              ;; first slot O
	 (+ (if (= (+ x o) s) 0 (rearranger-ox-positions (1- s) o x))       ;; ...no blanks left? 0 else count-blanks
	    (hash-rearranger-ox-h (bf b) (1- s) (1- o) x Bc Oc Xc)))
        (else                                                               ;; first slot X
	 (+ (if (= (+ x o) s) 0 (rearranger-ox-positions (1- s) o x))       ;; ...no blanks left? 0 else count-blanks
	    (if (= o 0)       0 (rearranger-ox-positions (1- s) (1- o) x))  ;; ...no os left?     0 else count-os
	    (hash-rearranger-ox-h (bf b) (1- s) o (1- x) Bc Oc Xc)))))

;; Tests

; (se
;   (hash-rearranger-ox (se *Bc* *Oc* *Xc*) *Bc* *Oc* *Xc*) ;; (- o x) 0
;  (hash-rearranger-ox (se *Bc* *Xc* *Oc*) *Bc* *Oc* *Xc*) ;; (- x o) 1
;  (hash-rearranger-ox (se *Oc* *Bc* *Xc*) *Bc* *Oc* *Xc*) ;; (o - x) 2
;  (hash-rearranger-ox (se *Oc* *Xc* *Bc*) *Bc* *Oc* *Xc*) ;; (o x -) 3
;  (hash-rearranger-ox (se *Xc* *Bc* *Oc*) *Bc* *Oc* *Xc*) ;; (x - o) 4
;  (hash-rearranger-ox (se *Xc* *Oc* *Bc*) *Bc* *Oc* *Xc*));; (x o -) 5

;;;;;;;;;;;;;;;;;;;
;; unhash-rearranger-ox
;;  Input: s  [slots] "the number of slots of the board"
;;       : o  [o]     "the number of o's on the board
;;       : x  [x]     "the number of x's on the board
;;       : i  [int]   "the hashed number of the board"
;;       : Bc [char]  "the character representing Blank"
;;       : Oc [char]  "the character representing o"
;;       : Xc [char]  "the character representing x"
;; Output: b  [board] "the ox board, e.g., (o - x o -)
;;;;;;;;;;;;;;;;;;;

(define (unhash-rearranger-ox s o x i Bc Oc Xc)
  (cond ((= s 0) '())
        ((and (= o 0) (= x 0))                                      ;; all blanks
         (se Bc (unhash-rearranger-ox (1- s) o x i Bc Oc Xc)))      ;; ...so put blanks there
        ((= s o)                                                    ;; all os
         (se Oc (unhash-rearranger-ox (1- s) (1- o) x i Bc Oc Xc))) ;; ...so put os there
        ((= s x)                                                    ;; all xs
         (se Xc (unhash-rearranger-ox (1- s) o (1- x) i Bc Oc Xc))) ;; ...so put xs there
        ((= s (+ x o))                                              ;; no -s
	 (unhash-rearranger-o s x i Oc Xc))                         ;; ...so treat like unhash-rearranger-o o x
        ((= o 0)                                                    ;; no os
	 (unhash-rearranger-o s x i Bc Xc))                         ;; ...so treat like unhash-rearranger-o - x
        ((= x 0)                                                    ;; no xs
	 (unhash-rearranger-o s o i Bc Oc))                         ;; ...so treat like unhash-rearranger-o - o
        ((< i (rearranger-ox-positions (1- s) o x))                 ;; index hasn't run out of blanks
         (se Bc (unhash-rearranger-ox (1- s) o x i Bc Oc Xc)))      ;; ...so put a - there
        ((< i (+ (rearranger-ox-positions (1- s) o x)               ;; index hasn't run out of os
		 (rearranger-ox-positions (1- s) (1- o) x)))        
         (se Oc (unhash-rearranger-ox (1- s) (1- o) x               ;; ...so put an o there
		   (- i (rearranger-ox-positions (1- s) o x)) Bc Oc Xc)))
        (else                                                       ;; index is bigger than -s and os,
         (se Xc (unhash-rearranger-ox (1- s) o (1- x)               ;; so put an x there
		   (- i (+ (rearranger-ox-positions (1- s) o x)   
			   (rearranger-ox-positions (1- s) (1- o) x))) Bc Oc Xc)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;                                   ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;            REARRANGER-OX          ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;            HASH / UNHASH          ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;                TESTS              ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;                                   ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;
;; test-unhash-rearranger-ox
;;  Input: s [slots] "the number of slots of the board"
;;       : o [o]     "the number of o's on the board
;;       : x [x]     "the number of x's on the board
;; Output: A list of all the boards with s slots, o os and x xs.
;;;;;;;;;;;;;;;;;;;

(define (test-unhash-rearranger-ox s o x)
  (map (lambda (i) (unhash-rearranger-ox s o x i *Bc* *Oc* *Xc*))
       (se-0-upto-n (rearranger-ox-positions s o x))))

;; Tests

; (test-unhash-rearranger-ox 3 1 1) ;; ==> ((- o x) (- x o) (o - x) (o x -) (x - o) (x o -))

;;;;;;;;;;;;;;;;;;;
;; test-hash-unhash-rearranger-ox
;;  Input: s [slots] "the number of slots of the board"
;;       : o [o]     "the number of o's on the board
;;       : x [x]     "the number of x's on the board
;; Output: The sentence (0 1 2 ... num-rearranger-ox-positions) if it works
;;;;;;;;;;;;;;;;;;;

(define (test-hash-unhash-rearranger-ox s o x)
  (map (lambda (b) (hash-rearranger-ox b *Bc* *Oc* *Xc*))
       (test-unhash-rearranger-ox s o x)))

;; Tests

; (test-hash-unhash-rearranger-ox 4 1 2) ;; ==> (0 1 2 3 4 5 6 7 8 9 10 11)

;;;;;;;;;;;;;;;;;;;
;; test-hash-unhash-rearranger-ox-broken?
;;  Input: s [slots] "the number of slots of the board"
;;       : o [o]     "the number of o's on the board
;;       : x [x]     "the number of x's on the board
;; Output: if any of the numbers 0 through num-positions unhash & hash wrong,
;;         return the broken list, otherwise #f (not broken) [semipredicate]
;;;;;;;;;;;;;;;;;;;

(define (test-hash-unhash-rearranger-ox-broken? s o x)
  (if (equal? (test-hash-unhash-rearranger-ox s o x)
	      (se-0-upto-n (rearranger-ox-positions s o x)))
      #f                                    ;; not-broken
      (test-hash-unhash-rearranger-ox s o x))) ;; yep, broken, and here it is!

;; Tests

(test-hash-unhash-rearranger-ox-broken? 4 1 2) ;; ==> #f (all is well)

;;;;;;;;;;;;;;;;;;;
;; broken-hash-unhash-rearranger-ox-sequences
;;  Input: s [slots] "the number of slots of the board"
;; Output: A list of all the sequences that are broken
;;;;;;;;;;;;;;;;;;;

(define (broken-hash-unhash-rearranger-ox-sequences s)
  (filter (lambda (seq) (not (null? seq)))
	  (map (lambda (o) 
		 (filter (lambda (broken-sequence) broken-sequence)
			 (map (lambda (x) (test-hash-unhash-rearranger-ox-broken? s o x))
			      (se-0-upto-n (1+ (- s o)))))) ;; x takes values [0, s-o]
	       (se-0-upto-n (1+ s))))) ;; o takes values [0,s]

;; Tests

; (broken-hash-unhash-rearranger-ox-sequences 5) ;; ==> () [that means none broken]

;;;;;;;;;;;;;;;;;;;
;; test-hash-unhash-rearranger-ox-up-through-slot
;;        Input: s [slots] "the max number of slots to test up to"
;; Side-Effects: Prints out status whether hash/unhash all works
;;;;;;;;;;;;;;;;;;;

(define (test-hash-unhash-rearranger-ox-up-through-slot max-s)
  (newline)
  (display "TESTING rearranger-ox hash & unhash together...")
  (newline)
  (for-each (lambda (s) 
	      (display "Slots: ")
	      (display s)
	      (display ", Hash-Unhash ")
	      (let ((broken (broken-hash-unhash-rearranger-ox-sequences s)))
		(cond ((null? broken) (display "ok!"))
		      (else (display "BROKEN for s=")
			    (display s)
			    (display ", sequence= ")
			    (display broken))))
	      (newline))
	    (se-0-upto-n (1+ max-s))))

;; Tests

; (test-hash-unhash-rearranger-ox-up-through-slot 5) ;; ==>
; TESTING rearranger-ox hash & unhash together...
; Slots: 0, Hash-Unhash ok!
; Slots: 1, Hash-Unhash ok!
; Slots: 2, Hash-Unhash ok!
; Slots: 3, Hash-Unhash ok!
; Slots: 4, Hash-Unhash ok!
; Slots: 5, Hash-Unhash ok!


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;                                   ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;             DARTBOARD             ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;                                   ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(+ (rearranger-ox-positions 9 0 0)
   (rearranger-ox-positions 9 0 1)
   (rearranger-ox-positions 9 1 1)
   (rearranger-ox-positions 9 1 2)
   (rearranger-ox-positions 9 2 2)
   (rearranger-ox-positions 9 2 3)
   (rearranger-ox-positions 9 3 3)
   (rearranger-ox-positions 9 3 4)
   (rearranger-ox-positions 9 4 4)
   (rearranger-ox-positions 9 4 5))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;                                   ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;              QUARTO               ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;                                   ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (quarto stage)
  (if (= stage 0)
      1
      (* (/ (! 16)
	    (! (- 16 stage)))
	 (c 16 (- stage 1)))))

(accumulate + (every quarto (se-0-upto-n 18))) 
;;     20,667,870,288,606,737
;;     P   T   G   M   K
(expt 2 64)
;; 18,446,744,073,709,551,616