Last active
April 25, 2022 20:02
-
-
Save Crowbrammer/dcc7b94dcc32aa9a2212cd907ec02990 to your computer and use it in GitHub Desktop.
Roman Numerals Decoder
This file contains 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
(ns translate-roman-numerals.test | |
(require [clojure.test :refer :all] | |
[translate-roman-numerals.core :refer :all])) | |
(deftest give-values-test | |
(are [given-value calculated-value] (= given-value calculated-value) | |
2 (letters-value \I 2) | |
2 (letters-value \I 4) | |
10 (letters-value \V 2) | |
10 (letters-value \V 2) | |
20 (letters-value \X 2) | |
20 (letters-value \X 2) | |
0 (letters-value \X 0) | |
50 (letters-value \L 1) | |
300 (letters-value \C 3) | |
200 (letters-value \C 2) | |
500 (letters-value \D 1) | |
3000 (letters-value \M 3))) | |
(deftest sample-roman-numerals | |
(are [given-value calculated-value] (= given-value calculated-value) | |
1 (translate-roman-numerals "I") | |
4 (translate-roman-numerals "IV") | |
2008 (translate-roman-numerals "MMVIII") | |
1666 (translate-roman-numerals "MDCLXVI"))) |
This file contains 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
(ns translate-roman-numerals.core | |
"Turn Roman numerals into Arabic numerals" | |
(:require [clojure.string :as str])) | |
(defn letters-value | |
"Given a Roman character and its number of occurences | |
(perhaps from `frequencies`), give its total value. Once | |
it hits 4, the subtraction principle kicks in, and it's | |
effectively equal two letter occurences. Assumes correct | |
Roman numeral notation. | |
This fails with IV, XL, XC, CD, and CM, so a correction must | |
be applied outside the function for these results." | |
[ch freq] | |
(let [char-values {\I 1 | |
\V 5 | |
\X 10 | |
;; L should prolly not be used more than once due to C | |
\L 50 | |
\C 100 | |
;; Same with D | |
\D 500 | |
;; Interestingly, there's nothing after M. | |
;; You use bars https://qr.ae/pv24MV | |
\M 1000} | |
;; There can never be more than four numerals. | |
;; At four, you subtract the last one, which means | |
;; +3 -1 for 2. At four letters, you effectively have | |
;; 2. Make that the freq. | |
;; The only exception is the I's can have one :( ) | |
actualized-freq (case freq | |
0 0 | |
1 1 | |
2 2 | |
3 3 | |
4 2)] | |
(* (get char-values ch 0) actualized-freq))) | |
(defn translate-roman-numerals | |
[roman] | |
;; You can handle the subtraction principle in two ways: order and | |
;; frequency. Order can be used to determine all necessary subtraction, | |
;; and order must be considered for "IV", "XL","XC", "CD", and "CM". There | |
;; can never be more than three identical letters without the subtraction | |
;; principle, so the fourth subtracts, thus `letters-value`. When using | |
;; the frequency approach, we must conditionally handle these four cases. | |
;; For a ridiculous point because performance isn't needed, I suspect this | |
;; is faster and simpler than the order-only approach. | |
(let [fqs (frequencies roman) | |
Arabic-vals (map #(apply letters-value %) fqs) | |
prelim-result (apply + Arabic-vals)] | |
;; 1) Undoing the "mistake" of adding when subtracting, and then | |
;; 2) Subtracting from the original number makes two a theme. | |
(cond-> prelim-result | |
(str/includes? roman "IV") (- 2) ;; Should be four. Will be six. | |
(str/includes? roman "XL") (- 20) ;; Should be forty. Will be sixty. | |
(str/includes? roman "XC") (- 20) ;; Should be ninety. Will be 110. | |
(str/includes? roman "CD") (- 200) ;; Should be 400. Will be 600. | |
(str/includes? roman "CM") (- 200) ;; Should be 900. Will be 1100. | |
) | |
)) | |
;; Random question: This site, http://www.romannumerals.co/learn/subtractive-principle/, | |
;; says "The subtractive principle, applies to the numbers 4, 9, 40, 90, 400 and 900 only.". | |
;; Is this true? |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment