Hoje em dia, a maioria das pessoas no mundo usa algarismos árabes (0–9). Mas se recuasses dois mil anos, verias que a maioria dos europeus usava algarismos romanos.
Para escrever um número romano, usamos as seguintes letras latinas, cada uma com um valor:
| M | D | C | L | X | V | I |
|---|---|---|---|---|---|---|
| 1000 | 500 | 100 | 50 | 10 | 5 | 1 |
Um número romano é uma sequência destas letras, e o seu valor é a soma dos valores das letras.
Por exemplo, XVIII tem o valor 18 (10 + 5 + 1 + 1 + 1 = 18).
Há, no entanto, uma regra que torna tudo mais complicado: a mesma letra não pode ser usada mais de três vezes seguidas.
Isso significa que não podemos representar números como o 4 com o aparentemente natural IIII.
Em vez disso, para esses números, usamos um método de subtração entre duas letras.
Por isso, pensamos no 4 não como 1 + 1 + 1 + 1, mas sim como 5 - 1.
E, de forma um pouco confusa para o nosso pensamento moderno, escrevemos primeiro o número menor.
Isto aplica-se apenas nos seguintes casos: 4 (IV), 9 (IX), 40 (XL), 90 (XC), 400 (CD) e 900 (CM).
A ordem é importante nos números romanos! As letras (e os compostos especiais acima) têm de estar ordenadas por valor decrescente, da esquerda para a direita.
Aqui estão alguns exemplos:
105 => CV
---- => --
100 => C
+ 5 => V
106 => CVI
---- => --
100 => C
+ 5 => V
+ 1 => I
104 => CIV
---- => ---
100 => C
+ 4 => IV
E um último exemplo mais complexo:
1996 => MCMXCVI
----- => -------
1000 => M
+ 900 => CM
+ 90 => XC
+ 5 => V
+ 1 => I
A tua tarefa é converter um número de algarismos árabes para algarismos romanos.
Neste exercício, só nos interessam os algarismos romanos tradicionais, em que o número mais alto é MMMCMXCIX (ou 3 999).
Há muitas formas diferentes de converter entre algarismos árabes e algarismos romanos. Recomendamos que comeces por uma abordagem simples, para te familiarizares com o conceito de algarismos romanos, e que só depois procures métodos mais eficientes.
Certifica-te de que vês o nosso vídeo Deep Dive no final, para explorares as diferentes abordagens que podes seguir!
Para algo um pouco diferente, também podes experimentar uma solução com uma função unfold. Provavelmente já conheces foldLeft/Right: «mapeiam» uma coleção inteira para outra coisa (normalmente algo que não é uma coleção). unfoldLeft/Right são as operações «inversas»: «mapeiam» algo (normalmente algo que não é uma coleção) para uma coleção. Por isso, fazer unfold é uma adição lógica e faz parte do repertório padrão da programação funcional.
Este exercício pode ser encarado como um caso para fazer unfold: «mapear» um Int para uma String (que é, naturalmente, de forma implícita, uma Seq[Char]).
Infelizmente, unfoldLeft/Right não está incluído na biblioteca de coleções do Scala. Mas podes tirar a implementação daqui.
Inscreve-te no Exercism para aprenderes e dominares Scala com 95 exercícios, e mentoria humana real, tudo grátis.
Explora várias soluções diferentes para este exercício complicado, desde a recursão a consultas baseadas em tabelas, passando por uma solução que recorre a números de base mista e por alguns truques simplistas em Common Lisp.