66 lines
2.0 KiB
Common Lisp
66 lines
2.0 KiB
Common Lisp
(defparameter *roman-numerals* '((#\I . 1)
|
|
(#\V . 5)
|
|
(#\X . 10)
|
|
(#\L . 50)
|
|
(#\C . 100)
|
|
(#\D . 500)
|
|
(#\M . 1000)))
|
|
|
|
(defparameter *roman-numeral-digits* '((#\I #\V #\X)
|
|
(#\X #\L #\C)
|
|
(#\C #\D #\M)
|
|
(#\M)))
|
|
|
|
(defun parse-roman-numerals (string)
|
|
"Parses STRING as a value written in Roman numerals, using only the 'descending order' rule"
|
|
(loop with sum = 0
|
|
for last-value = nil then value
|
|
for character across string
|
|
for value = (cdr (assoc character *roman-numerals*))
|
|
do (if (and last-value (< last-value value))
|
|
(incf sum (- value (* 2 last-value)))
|
|
(incf sum value))
|
|
finally (return sum)))
|
|
|
|
(defun digits (value)
|
|
"Returns a list of the base-10 digits in positive integer VALUE"
|
|
(loop with digits = nil
|
|
for digit = (mod value 10)
|
|
while (> value 0)
|
|
do (push digit digits)
|
|
(setf value (floor value 10))
|
|
finally (return digits)))
|
|
|
|
(defun nconc-lists (lists)
|
|
"NCONCs LISTS together"
|
|
(apply #'nconc lists))
|
|
|
|
(defun format-roman-numeral (value)
|
|
"Formats VALUE as a minimal Roman numeral string"
|
|
(-> (loop for digit in (nreverse (digits value))
|
|
for (one five ten) in *roman-numeral-digits*
|
|
collect (ecase digit
|
|
(0 nil)
|
|
(1 (list one))
|
|
(2 (list one one))
|
|
(3 (list one one one))
|
|
(4 (if five
|
|
(list one five)
|
|
(list one one one one)))
|
|
(5 (list five))
|
|
(6 (list five one))
|
|
(7 (list five one one))
|
|
(8 (list five one one one))
|
|
(9 (list one ten))))
|
|
(nreverse)
|
|
(nconc-lists)
|
|
(coerce 'string)))
|
|
|
|
(defun roman-numerals ()
|
|
(let* ((lines (uiop:read-file-lines "0089_roman.txt"))
|
|
(characters-original (loop for line in lines sum (length line)))
|
|
(values (loop for line in lines collect (parse-roman-numerals line)))
|
|
(lines-minimal (loop for value in values collect (format-roman-numeral value)))
|
|
(characters-minimal (loop for line in lines-minimal sum (length line))))
|
|
(- characters-original characters-minimal)))
|