Created
September 23, 2016 11:37
-
-
Save MikeMKH/1388d6d0b6863ef568109023c1f6e778 to your computer and use it in GitHub Desktop.
Roman Numeral kata in Racket using foldl
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#lang racket | |
(require rackunit rackunit/text-ui) | |
(define (string-repeat n s) | |
(string-append* (make-list n s))) | |
(define (romanize-map n) | |
(let ([arabic->roman | |
(list (cons 1000 "M") (cons 900 "CM") | |
(cons 500 "D") (cons 400 "CD") | |
(cons 100 "C") (cons 90 "XC") | |
(cons 50 "L") (cons 40 "XL") | |
(cons 10 "X") (cons 9 "IX") | |
(cons 5 "V") (cons 4 "IV") | |
(cons 1 "I"))]) | |
(cdr | |
(foldl (lambda (x m) | |
(match-let ([(cons n s) m] | |
[(cons a r) x]) | |
(if (>= n a) | |
(cons (remainder n a) (string-append s (string-repeat (quotient n a) r))) | |
m))) | |
(cons n "") | |
arabic->roman)))) | |
(run-tests | |
(test-suite | |
"roman numeral kata" | |
(test-case | |
"given a value in [1, 4] it must contain at least 1 I" | |
(for ([value (range 1 4)]) | |
(check-pred (lambda (x) (and (>= x 1) (<= x 4))) value) | |
(check-regexp-match "[VXLCDM]*I+[VXLCDM]*" (romanize-map value)))) | |
(test-case | |
"given a positive value divisible by 5 it must contain either V or X" | |
(for ([value (range 0 100 5)] | |
#:when (and (positive? value) | |
(zero? (modulo value 5)))) | |
(check-pred positive? value) | |
(check-pred zero? (modulo value 5)) | |
(check-regexp-match "V|X?" (romanize-map value)))) | |
(test-case | |
"given a value in [1, 3999] the result must be 1 or longer in length" | |
(for ([value (range 1 3999)]) | |
(check-pred (lambda (x) (and (>= x 1) (<= x 3999))) value) | |
(check >= (string-length (romanize-map value)) 1))) | |
(test-case | |
"given a mapping of arabic to roman numerals it must map values correctly" | |
(for ([arabic (list 1 4 5 9 10 40 50 90 100 400 500 900 1000)] | |
[roman (list "I" "IV" "V" "IX" "X" "XL" "L" "XC" "C" "CD" "D" "CM" "M")]) | |
(check-equal? (romanize-map arabic) roman))) | |
(test-case | |
"given a value in [1, 3] the result must contain I's equal to the value" | |
(for ([value '(1 2 3)]) | |
(check-regexp-match "I+" (romanize-map value)) | |
(check-equal? (string-length (romanize-map value)) value))) | |
(test-case | |
"given a mapping of 10th values to roman numerals when the value is triples it must return the roman numeral in triple" | |
(for ([arabic (list 1 10 100 1000)] | |
[roman (list "I" "X" "C" "M")]) | |
(check-equal? (romanize-map (* 3 arabic)) (string-append* (make-list 3 roman))))) | |
(test-case | |
"given the following tests it must map as expected" | |
(check-equal? (romanize-map 3) "III") | |
(check-equal? (romanize-map 29) "XXIX") | |
(check-equal? (romanize-map 398) "CCCXCVIII") | |
(check-equal? (romanize-map 946) "CMXLVI") | |
(check-equal? (romanize-map 2471) "MMCDLXXI")))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment