Skip to content

Instantly share code, notes, and snippets.

@MikeMKH
Created September 23, 2016 11:37
Show Gist options
  • Save MikeMKH/1388d6d0b6863ef568109023c1f6e778 to your computer and use it in GitHub Desktop.
Save MikeMKH/1388d6d0b6863ef568109023c1f6e778 to your computer and use it in GitHub Desktop.
Roman Numeral kata in Racket using foldl
#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