(define-module (t) #:use-module (srfi srfi-1) #:export (t spelt->numbers starts-with? parse-int replace-elements find-true)) (define numbers '((#\1 . ((#\o #\n #\e) . 3)) (#\2 . ((#\t #\w #\o) . 3)) (#\3 . ((#\t #\h #\r #\e #\e) . 5)) (#\4 . ((#\f #\o #\u #\r) . 4)) (#\5 . ((#\f #\i #\v #\e) . 4)) (#\6 . ((#\s #\i #\x) . 3)) (#\7 . ((#\s #\e #\v #\e #\n) . 5)) (#\8 . ((#\e #\i #\g #\h #\t) . 5)) (#\9 . ((#\n #\i #\n #\e) . 4)))) (define (t str convert?) (apply + (map (lambda (line) (let ((lst (string->list line))) (parse-int (if convert? (spelt->numbers lst) lst)))) (string-split (string-trim-both str char-set:whitespace) #\newline)))) (define (parse-int lst) "Given LST of characters, return a two-digit integer representing containing the first and last digits in LST." (let ((digits (filter (lambda (x) (char-numeric? x)) lst))) (string->number (string (car digits) (last digits))))) (define (spelt->numbers lst) "Loops through the string, replacing numbers that are spelt-out with their digit counterparts." (let loop ((lst lst) (result '())) (if (null? lst) result (let ((index (find-true (map (lambda (num-pair) (starts-with? lst num-pair)) numbers)))) (when index (set! lst (replace-elements lst (list-ref numbers index)))) (loop (cdr lst) (append result (list (car lst)))))))) (define (find-true lst) "Given LST of boolean values, returns the index of the first #t value, or false otherwise." (let ((sublist (member #t lst))) (if sublist (- (length lst) (length sublist)) #f))) (define (starts-with? lst num-pair) "Returns #t if LST starts with CADR NUM-PAIR" (let ((sub-length (cddr num-pair))) (and (>= (length lst) sub-length) (equal? (list-head lst sub-length) (cadr num-pair))))) (define (replace-elements lst num-pair) "Given LST, removes LENGTH elements from the front and replaces them with CHAR. As an edit, we should NOT remove ALL letters, because some letters are shared between spelt numbers (twone). As a safety, we are safe always leaving one." (cons (car num-pair) (list-tail lst (1- (cddr num-pair)))))