; roomba

(define (split n xs)
  (let loop ((n n) (xs xs) (zs '()))
    (if (or (zero? n) (null? xs))
        (values (reverse zs) xs)
        (loop (- n 1) (cdr xs) (cons (car xs) zs)))))

(define (split-while pred? xs)
  (let loop ((xs xs) (ys '()))
    (if (or (null? xs) (not (pred? (car xs))))
        (values (reverse ys) xs)
        (loop (cdr xs) (cons (car xs) ys)))))

(define (digits n . args)
  (let ((b (if (null? args) 10 (car args))))
    (let loop ((n n) (d '()))
      (if (zero? n) d
          (loop (quotient n b)
                (cons (modulo n b) d))))))

(define (get-command cs)
  (call-with-values
    (lambda () (split 1 cs))
    (lambda (dir rest)
      (call-with-values
        (lambda () (split-while char-numeric? rest))
        (lambda (digits rest)
          (values (car dir) (string->number (apply string digits)) rest))))))

(define (roomba x y str)
  (let loop ((x x) (y y) (cs (string->list str)))
    (if (null? cs) (values x y)
      (call-with-values
        (lambda () (get-command cs))
        (lambda (dir steps rest)
          (case dir
          ((#\N #\n) (loop x (+ y steps) rest))
          ((#\E #\e) (loop (+ x steps) y rest))
          ((#\S #\s) (loop x (- y steps) rest))
          ((#\W #\w) (loop (- x steps) y rest))))))))

(call-with-values
  (lambda () (roomba 0 0 "N3E5S2W6"))
  (lambda (x y) (display x) (newline)
  	            (display y) (newline)))

(call-with-values
  (lambda () (roomba 17 -3 "W4S19W33N17E37N2"))
  (lambda (x y) (display x) (newline)
  	            (display y) (newline)))