; the last prime digit

(import (rnrs hashtables (6)))

(define (make-matrix rows columns . value)
  (do ((m (make-vector rows)) (i 0 (+ i 1)))
      ((= i rows) m)
    (if (null? value)
        (vector-set! m i (make-vector columns))
        (vector-set! m i (make-vector columns (car value))))))

(define (matrix-ref m i j) (vector-ref (vector-ref m i) j))

(define (matrix-set! m i j x) (vector-set! (vector-ref m i) j x))

(define (primegen)
  (let ((ps #f) (p #f) (q #f) (c #f) (d (make-eq-hashtable)))
    (lambda ()
      (define (add m s)
        (do () ((not (hashtable-ref d m #f))) (set! m (+ m s)))
        (hashtable-set! d m s))
      (cond ((not p) (set! p #t) 2) ((not q) (set! q #t) 3)
      (else (when (not ps) (set! ps (primegen)) (set! c 5)
              (set! p (and (ps) (ps))) (set! q (* p p)))
            (let loop ()
              (cond ((hashtable-ref d c #f) =>
                      (lambda (s)
                        (hashtable-delete! d c)
                        (add (+ c s) s)
                        (set! c (+ c 2)) (loop)))
                    ((< c q) (let ((x c)) (set! c (+ c 2)) x))
                    (else (add (+ c p p) (+ p p))
                          (set! p (ps)) (set! q (* p p))
                          (set! c (+ c 2)) (loop)))))))))

(define (grimes n)
  (let ((ps (primegen)) (counts (make-matrix 4 4 0)))
    (ps) (ps) (ps) ; discard 2,3,5
    (let loop ((prev (ps)) (n (- n 4)))
      (if (zero? n) counts
        (let ((curr (modulo (ps) 10)))
          (matrix-set! counts (quotient prev 3) (quotient curr 3)
            (+ 1 (matrix-ref counts (quotient prev 3) (quotient curr 3))))
          (loop curr (- n 1)))))))

(display (grimes 1000))