Преобразовать в римскую цифру!

13

Ваша задача - преобразовать данное положительное целое число из арабской цифры в римскую цифру.

Все становится сложнее, если считать до 4000.

Римляне сделали это, добавив строку над символом, чтобы умножить этот символ на 1 000. Однако в ASCII обводки не отображаются точно. Кроме того, существуют двойные пометки для умножения символа на 1 000 000, а затем тройные пометки для умножения символа на 1 000 000 000и т. Д.

Поэтому я решил использовать круглые скобки, чтобы заменить подчеркивания.

Символы могут быть индивидуально помещены в скобки. Например, оба (VI)и (V)(I)являются действительными представлениями 6 000.(V)Mтакже является действительным представлением 6000.

(I) это правильный способ представлять 1 000 .

Testcases

Input: 1
Output: I
Input: 2
Output: II
Input: 3
Output: III
Input: 4
Output: IV
Input: 15
Output: XV
Input: 40
Output: XL
Input: 60
Output: LX
Input: 67
Output: LXVII
Input: 400
Output: CD
Input: 666
Output: DCLXVI
Input: 3000
Output: MMM
Input: 3999
Output: MMMCMXCIX
Input: 4000
Output: M(V)
Input: 4999
Output: M(V)CMXCIX
Input: 6000
Output: (VI)
Input: 6000000
Output: ((VI))
Input: 6006000
Output: ((VI)VI)
Input: 6666666666
Output: (((VI)DCLXVI)DCLXVI)DCLXVI

счет

Это . Самый короткий код в байтах побеждает.

Дрянная Монахиня
источник
1
Обоснование того, почему это не дубликат, сбивает с толку спецификации. Было бы лучше без него ИМО.
Мего
Куда бы я добавил обоснование?
Утренняя монахиня
1
Пропусти это. Если кто-то спрашивает, является ли он дубликатом, обсудите это в комментариях или в чате.
Мего
@ Мего Готово. :-)
Дрянная Монахиня
Является (IV)ли приемлемое представление 4000?
Нил

Ответы:

9

Mathematica, 67 байт

Fold["("<>#<>")"<>#2&,RomanNumeral[#~IntegerDigits~1000]/."N"->""]&

Предотвращает все проблемы Mпутем преобразования ввода в базу 1000 и преобразования каждой цифры отдельно с помощью RomanNumeral. Затем мы складываем их, вставляя (...)слева.

К сожалению, Mathematica представляет нули, Nпоэтому мы должны избавиться от них.

Мартин Эндер
источник
1
чертовски mathematica с его встроенными
функциями
1
@ OldBunny2800 Я был бы удивлен, если бы это все равно не было побито ни одним из языков игры в гольф.
Мартин Эндер
@ OldBunny2800 И это стоит реальных денег, чтобы получить его. Плохо.
Эрик Outgolfer
@ MartinBüttner Я думал, просто RomanNumeralможет это сделать?
Утренняя монахиня
1
@KennyLau Он выводит MMMMдля 4000, он только начинает работать по спецификации 5000(а затем вы получаете ту же проблему для 4000000и т. Д.). Даже тогда он использует надстрочные знаки вместо скобок. Если вы в порядке с этим, вы должны сказать об этом в спецификации вызова.
Мартин Эндер
7

JavaScript (ES6), 136 байт

f=n=>n<4e3?"M1000CM900D500CD400C100XC90L50XL40X10IX9V5IV4I1".replace(/(\D+)(\d+)/g,(_,r,d)=>r.repeat(n/d,n%=d)):`(${f(n/1e3)})`+f(n%1e3)

Для чисел до 4000 повторяется каждая римская «буква» столько раз, сколько возможно, используя список римских «букв» и их десятичных значений. В противном случае рекурсивно строит ответ от деления и по модулю с 1000. К счастью, repeatусекает, поэтому мне не нужно делать это самому.

Нил
источник
3

Common Lisp, 108

(defun p(n)(if(> n 0)(if(< n 4000)(format()"~@R"n)(format()"(~A)~@[~A~]"(p(floor n 1000))(p(mod n 1000))))))

Ungolfed

(defun p(n)
  (if (> n 0)
      (if (< n 4000)

          ;; Built-in Roman formatter (between 1 and 3999)
          (format () "~@R" n)

          ;; Divide N by 1000, as 1000*Q + R.
          ;; First print (p Q) in parentheses (recursively)
          ;; Then, if it is not NIL, the remainder R.
          (format () "(~A)~@[~A~]"
                  (p (floor n 1000))
                  (p (mod n 1000))))))

тесты

Два теста дают разные результаты, чем те, которые приведены в вопросе:

(loop for (in out) in '((1 "I")
                        (2 "II")
                        (3 "III")
                        (4 "IV")
                        (15 "XV")
                        (40 "XL")
                        (60 "LX")
                        (67 "LXVII")
                        (400 "CD")
                        (666 "DCLXVI")
                        (3000 "MMM")
                        (3999 "MMMCMXCIX")
                        (4000 "M(V)")
                        (4999 "M(V)CMXCIX")
                        (6000 "(VI)")
                        (6000000 "((VI))")
                        (6006000 "((VI)VI)")
                        (6666666666 "(((VI)DCLXVI)DCLXVI)DCLXVI"))
   for computed = (p in)
   unless (string= out computed)
   collect (list in out computed))

=> ((4000 "M(V)" "(IV)")
    (4999 "M(V)CMXCIX" "(IV)CMXCIX"))
CoreDump
источник
2

R 134

m=1000;x=scan();while(x[1]>=m)x=c(floor(x[1]/m),x[1]%%m,x[-1]);cat(rep("(",length(x)),sep="");cat(as.character(as.roman(x)),sep=")")

Это в значительной степени не лучший вариант, но я думаю, что идея должна идти примерно так.

Masclins
источник
1

Питон, 188 194

-6 байт от избавления от пробелов

Эта проблема вернула меня к тому времени, когда я только начинал учиться программировать ...

def f(x,s=zip("M CM D CD C XC L XL X IX V IV I".split(),[1e3,900,500,400,100,90,50,40,10,9,5,4,1])):
 r=""if x<4e3else"("+f(x/1e3)+")";x%=1e3
 for a,b in s:
    while x>=b:r+=a;x-=b
 return r

Возможно, это не самое короткое решение, но я получил удовольствие от игры в гольф.

Попробуйте!

Мистер Паблик
источник
1

Рубин, 137 134 130 байтов

Рекурсивная функция, которая возвращает строку. Я пытаюсь поиграть в цифровые кодировки немного больше, если это возможно, но я не уверен, как.

Ой, теперь это практически прямой порт ответа @ Neil's ES6.

f=->x{(x<t=1e3)?"CM900D500CD400C100XC90L50XL40X10IX9V5IV4I1".gsub(/(\D+)(\d+)/){v=$2.to_i;s=x/v;x%=v;$1*s}:"(#{f[x/t]})#{f[x%t]}"}
Значение чернил
источник
1

Рубин, 185 161 144 байта

r=->i{i>(t=1e3)? "(#{r[i/t]})"+r[i%t]:(s=?I*i;"IVXXLCCDM".scan(/(.)(.)(.)/){|x,y,z|{x*5=>y,x*4=>x+y,y*2=>z,y+x+y=>x+z}.map{|x,y|s.gsub!x,y}};s)}

Спустя год после первоначального поста, я думаю, что узнал кое-что о гольфе.

Спасибо Value Ink за ваши ценные комментарии.

MegaTom
источник
gsubможет принимать строку в качестве первого аргумента, устраняя необходимость в подстановках в шаблоне регулярных выражений, поскольку s.gsub! x,yделает это автоматически. Кроме этого, вы, вероятно, можете просто отказаться от назначения вашего aмассива, поскольку вы используете его только один раз и вставляете его непосредственно в each_sliceвызов.
Value Ink
"IVXXLCCDM".scan(/(.)(.)(.)/){|x,b,c|...тоже работает
Value Ink
Кроме того r[x], функционально эквивалентен тому, что r.(x)когда-либо участвуют колбасные лямбды
Value Ink
@ValueInk спасибо. Этот r[x]трюк будет полезен всем моим рекурсивным гольфам в рубине!
MegaTom
1

TCL 134 байта

proc f r {
set map {M 1000+ CM 900+ D 500+ CD 400+ C 100+ XC 90+ L 50+ XL 40+ X 10+ IX 9+ V 5+ IV 4+ I 1+}
expr [string map $map $r]0}

Попробуйте это здесь: https://rextester.com/BJC92885

Чау Гианг
источник