Считайте от 1 до 100 ... в римских цифрах

29

Напишите программу, которая считает римскими цифрами от 1 до 100, и напечатайте эти числа стандартным выводом. Каждое из чисел должно быть разделено пробелами.

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

Желаемый результат

I II III IV V VI VII VIII IX X XI XII XIII XIV XV XVI XVII XVIII XIX XX XXI XXII XXIII XXIV XXV XXVI XXVII XXVIII XXIX XXX XXXI XXXII XXXIII XXXIV XXXV XXXVI XXXVII XXXVIII XXXIX XL XLI XLII XLIII XLIV XLV XLVI XLVII XLVIII XLIX L LI LII LIII LIV LV LVI LVII LVIII LIX LX LXI LXII LXIII LXIV LXV LXVI LXVII LXVIII LXIX LXX LXXI LXXII LXXIII LXXIV LXXV LXXVI LXXVII LXXVIII LXXIX LXXX LXXXI LXXXII LXXXIII LXXXIV LXXXV LXXXVI LXXXVII LXXXVIII LXXXIX XC XCI XCII XCIII XCIV XCV XCVI XCVII XCVIII XCIX C

Так как это сложная игра в гольф, выигрывает самый короткий код .

Аверроэс
источник
4
39 отсутствует X.
Тор
@Thor Исправлено, спасибо;)
Averroes
1
Я действительно хочу использовать INTERCAL для этого.
Вейцзюнь Чжоу
это может быть разделено новыми строками? А как насчет конечных / ведущих пробелов / новых строк?
FantaC

Ответы:

68

Perl 69 байт

s;.;y/XVI60-9/CLXVIX/dfor$a[$_].="32e$&"%72726;gefor 1..100;print"@a"

Работает по волшебной формуле. Выражение "32e$&"%72726преобразует каждую цифру следующим образом:
0⇒32, 1⇒ 320, 2⇒ 3200, 3⇒ 32000, 4⇒29096, 5⇒56, 6⇒560, 7⇒5600, 8⇒56000, 9⇒50918

После применения перевода y/016/IXV/мы получаем это:
0⇒32, 1⇒32 I , 2⇒32 II , 3⇒32 III , 4⇒29 I 9 V , 5⇒5 V , 6⇒5 VI , 7⇒5 VII , 8⇒5 VIII , 9⇒5 I 9 X 8

Остальные цифры ( 2-57-9) удаляются. Обратите внимание, что это можно улучшить на один байт, используя формулу, которая переводит 012вместо 016упрощения /XVI60-9/в /XVI0-9/. Я не смог найти его, но, возможно, вам повезет больше.

Как только одна цифра была преобразована таким образом, процесс повторяется для следующей цифры, добавляя результат и переводя предыдущие XVIs CLXв то же самое время, когда происходит перевод новой цифры.

Обновление
Исчерпывающий поиск не выявил ничего более короткого. Однако я нашел альтернативное 69-байтовое решение:

s;.;y/XVI0-9/CLXIXV/dfor$a[$_].="57e$&"%474976;gefor 1..100;print"@a"

Этот использует 0-2замену IXV, но имеет модуль, который на одну цифру длиннее.


Обновление: 66 65 байт

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

Не в силах сократить формулу больше, чем она есть, я решил проиграть то, что у меня было. Прошло совсем немного времени, пока я не вспомнил своего старого друга $\. Когда printвыдается отчет, $\он автоматически добавляется в конец вывода. Мне удалось избавиться от неудобной $a[$_]конструкции для двухбайтового улучшения:

s;.;y/XVI60-9/CLXVIX/dfor$\.="32e$&"%72726;ge,$\=!print$"for 1..100

Намного лучше, но это $\=!print$"все еще выглядело немного многословно. Затем я вспомнил альтернативную формулу равной длины, которую я нашел, которая не содержала число 3ни в одном из своих преобразований цифр. Таким образом, можно использовать $\=2+printвместо этого и заменить полученное 3место пробелом:

s;.;y/XVI0-9/CLXIIX V/dfor$\.="8e$&"%61535;ge,$\=2+print for 1..100

Также 67 байтов, из-за необходимого пробела между printи for.

Редактировать : это может быть улучшено одним байтом, перемещая printвперед:

$\=2+print!s;.;y/XVI0-9/CLXIIX V/dfor$\.="8e$&"%61535;gefor 1..100

Поскольку подстановка должна быть полностью оценена до print, присваивание по- $\прежнему будет выполняться последним. Удаление пробела между geи forвыдаст предупреждение об устаревании, но в остальном действует.

Но, если бы формула , которая не использовать в 1любом месте, $\=2+printстановится $\=printеще два байта на сумму экономии. Даже если бы он был на один байт длиннее, это все равно было бы улучшением.

Как оказалось, такая формула существует, но она на один байт длиннее оригинальной, в результате чего итоговая оценка составляет 65 байт :

$\=print!s;.;y/XVI60-9/CLXXI V/dfor$\.="37e$&"%97366;gefor 1..100

методология

Был задан вопрос, как можно найти такую ​​формулу. В общем, поиск волшебной формулы для обобщения любого набора данных является вопросом вероятности. То есть вы хотите выбрать форму, которая с наибольшей вероятностью даст что-то похожее на желаемый результат.

Изучая первые несколько римских цифр:

0:
1: I
2: II
3: III
4: IV
5: V
6: VI
7: VII
8: VIII
9: IX

есть некоторая закономерность, которую можно увидеть. В частности, с 0-3, а затем снова с 5-8 каждый последующий член увеличивается в длине на одну цифру. Если бы мы хотели создать отображение из цифр в цифры, мы бы хотели иметь выражение, которое также увеличивается в длине на одну цифру для каждого последующего члена. Логическим выбором является k • 10 d, где d - соответствующая цифра, а k - любая целочисленная константа.

Это работает для 0-3 , но 4 должен сломать образец. То, что мы можем сделать здесь, это прибавить по модулю:
k • 10 d % m , где m находится где-то между k • 10 3 и k • 10 4 . Это оставит диапазон 0-3 нетронутым и изменит 4 так , чтобы он не содержал четыре Iс. Если мы дополнительно ограничим наш алгоритм поиска таким образом, чтобы модульный остаток 5 , назовем его j , был меньше m / 1000 , это также обеспечит регулярность 5-8 . Результат примерно такой:

0: k
1: k0
2: k00
3: k000
4: ????
5: j
6: j0
7: j00
8: j000
9: ????

Как вы можете видеть, если мы заменим 0с I, 0-3 и 5-8 все гарантированно будет отображаться правильно! Значения 4 и 9 должны быть грубыми. В частности, 4 должен содержать один 0и один j(в этом порядке), а 9 должен содержать один 0, за которым следует еще одна цифра, которая больше нигде не появляется. Конечно, есть ряд других формул, которые по стечению обстоятельств могут привести к желаемому результату. Некоторые из них могут быть даже короче. Но я не думаю, что есть такие, кто может добиться успеха так же, как этот.

Я также экспериментировал с множественными заменами Iи / или Vс некоторым успехом. Но увы, ничего короче того, что у меня уже было. Вот список самых коротких решений, которые я нашел (количество решений на 1-2 байта больше, слишком много, чтобы перечислять):

y/XVI60-9/CLXVIX/dfor$\.="32e$&"%72726
y/XVI0-9/CLXIXV/dfor$\.="57e$&"%474976
y/XVI0-9/CLXIVXI/dfor$\.="49e$&"%87971

y/XVI0-9/CLXIIXIV/dfor$\.="7e$&"%10606  #
y/XVI0-9/CLXIIXIV/dfor$\.="7e$&"%15909  # These are all essentially the same
y/XVI0-9/CLXIIXIV/dfor$\.="7e$&"%31818  #

y/XVI0-9/CLXIIX V/dfor$\.="8e$&"%61535  # Doesn't contain 3 anywhere

y/XVI60-9/CLXXI V/dfor$\.="37e$&"%97366 # Doesn't contain 1 anywhere
Примо
источник
3
Как вы нашли волшебную формулу?
Рубен Верборг
1
@RubenVerborgh Я скоро обновлю свой пост с более подробной информацией о методологии.
Примо
15

HTML + JavaScript + CSS (137)

HTML (9)

<ol></ol>

JavaScript (101)

for(i=1;i<=100;i++){document.getElementsByTagName('ol')[0].appendChild(document.createElement('li'))}

CSS (27)

ol{list-style:upper-roman​}

Выход

Нумерованный список с римскими цифрами

...

Демо на JSBin

Патрик Осцити
источник
1
81-байтовая версия только для JS: document.write('<ol>'+"<li style='list-style:upper-roman'/>".repeat(100)+'</ol>')(ES6)
Paperjam
или 66 в Chromedocument.write("<li style='list-style:upper-roman'/>".repeat(100))
Слай
10

Python 116

лучший гольф-код ответа Scleaver:

r=lambda a,b,c:('',a,2*a,3*a,a+b,b,b+a,b+a+a,b+3*a,a+c);print' '.join(i+j for i in r(*'XLC')for j in r(*'IVX'))+' C'
Даниил
источник
8

Питон, 139

print' '.join(' '.join(i+j for  j in ' _I_II_III_IV_V_VI_VII_VIII_IX'.split('_'))for i in ' _X_XX_XXX_XL_L_LX_LXX_LXXX_XC'.split('_'))+' C'
scleaver
источник
6

С 177 160 147 символов

Есть более короткие решения, но их нет в C, так что вот моя попытка.

Новое решение, полностью отличающееся от моего предыдущего:

char*c;
f(n){
    printf("%.*s",n%5>3?2:n%5+n/5,c+=n%5>3?n%4*4:2-n/5);
}
main(i){
        for(;i<100;putchar(32))
                c="XLXXXC",f(i/10),
                c="IVIIIX",f(i++%10);
        puts("C");
}

Предыдущее решение (160 символов):

Логика:
1. fпечатает число от 1 до 10. cИспользуются цифры, которые могут быть IVXили XLC. Вызывается один раз для десятков, один раз для тех.
2. Если n%5==0- ничего не печатать или c[n/5]что есть Iили V(или Lили C).
3. Если n%4==4- 4или 9- распечатать I(или X), с помощью n+1.
4. Если n>4- печатать 5(то есть Vили L) то n-5.
5. Если n<4- печатать Iто n-1(т.е. nраз I).

char*c;
p(c){putchar(c);}
f(n){
        n%5?
                n%5>3?
                        f(1),f(n+1):
                        n>4?
                                f(5),f(n-5):
                                f(n-1,p(*c)):
                n&&p(c[n/5]);
}
main(i){
        for(;++i<101;p(32))
                c="XLC",f(i/10),
                c="IVX",f(i%10);
        p(10);
}
ugoren
источник
137:f(c,n){printf("%.*s",n%5>3?2:n%5+n/5,"XLXXXCIVIIIX "+c+(n%5>3?n%4*4:2-n/5));}main(i){for(;i<100;f(12,4))f(0,i/10),f(6,i++%10);puts("C");}
гастропнер
5

JavaScript, 123

Вдохновленный более длинной версией, я наткнулся на польскую группу новостей (по крайней мере, Chrome думал, что это польский язык).

for(i=100,a=[];n=i--;a[i]=r)
  for(r=y='',x=5;n;y++,x^=7)
    for(m=n%x,n=n/x^0;m--;)
      r='IVXLC'[m>2?y+n-(n&=-2)+(m=1):+y]+r;
alert(a)
Пол Уоллс
источник
5

Q ( 81 80)

2-й срез:

1_,/'[($)``X`XX`XXX`XL`L`LX`LXX`LXXX`XC cross``I`II`III`IV`V`VI`VII`VIII`IX],"C"

1-й срез:

1_,/'[$:[``X`XX`XXX`XL`L`LX`LXX`LXXX`XC cross``I`II`III`IV`V`VI`VII`VIII`IX]],"C"
scottstein37
источник
4

Питон, 168

r=lambda n,l,v:(r(n,l[1:],v[1:])if n<v[0]else l[0]+r(n-v[0],l,v))if n else''
for i in range(1,101):print r(i,'C XC L XL X IX V IV I'.split(),[100,90,50,40,10,9,5,4,1]),

объяснение

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

'C'  = 100
'XC' = 90
'L'  = 50
'XL' = 40
'X'  = 10
'IX' = 9
'V'  = 5
'IV' = 4
'I'  = 1
картонная коробка
источник
1
r=lambda n,l,v:n and(n<v[0]and r(n,l[1:],v[1:])or l[0]+r(n-v[0],l,v))or""сохраняет два символа. В остальном очень мило.
cemper93
4

Рубин 1.9, 140 132

r=" "
100.times{r+=?I
0while[[?I*4,"IV"],["VIV","IX"],[?X*4,"XL"],["LXL","XC"],[/(.)((?!\1)[^I])\1/,'\2']].any?{|q|r.sub! *q}
$><<r}

Это буквально считается от 1 до 100 римскими цифрами. Начинается с пустой строки, затем циклически добавляется «I», а затем повторно применяется ряд правил подстановки, эффективно добавляя 1.

Редактировать: Добавлен номер версии, так как ?Iработает только в 1.9, и использовал изменения @ Howard для обрезки некоторых символов.

histocrat
источник
Вы можете сохранить два символа: r while-> 0while, r.sub!(*q)-> r.sub! *q. Вы также можете перетащить печать внутри цикла и использовать 100.times{...}вместо оператора map.
Говард
(%w[IIII VIV XXXX LXL]<</(.)((?!\1)[^I])\1/).zip(%w(IV IX XL XC)<<'\2')экономит 7 символов.
Steenslag
4

Руби 112 символов

101.times{|n|r=' ';[100,90,50,40,10,9,5,4,1].zip(%w(C XC L XL X IX V IV I)){|(k,v)|a,n=n.divmod k;r<<v*a};$><<r}

В основном используется to_romanметод, описанный здесь , но для краткости используется zip-массив.

steenslag
источник
4

Mathematica 159 150 142

c = {100, 90, 50, 40, 10, 9, 5, 4, 1};
Table["" <> Flatten[ConstantArray @@@ Thread@{StringSplit@"C XC L XL X IX V IV I", 
  FoldList[Mod, k, Most@c]~Quotient~c}], {k, 100}]

римские цифры


Встроенное решение : IntegerString38 символов

IntegerString[k, "Roman"]~Table~{k, 100}
DavidC
источник
2

Perl 205

@r = split //, "IVXLC";
@n = (1, 5, 10, 50, 100);

for $num (1..100) {
  for($i=@r-1; $i>=0; $i--) {
    $d = int($num / $n[$i]);
    next if not $d;
    $_ .= $r[$i] x $d;
    $num -= $d * $n[$i];
  }
  $_ .= " ";
}
s/LXXXX/XC/g;
s/XXXX/XL/g;
s/VIIII/IX/g;
s/IIII/IV/g;
print;

Golfed:

@r=split//,"IVXLC";@n=(1,5,10,50,100);for$num(1..100){for($i=@r-1;$i>=0;$i--){$d=int($num/$n[$i]);next if!$d;$_.=$r[$i]x$d;$num-=$d*$n[$i];}$_.=" ";}s/LXXXX/XC/g;s/XXXX/XL/g;s/VIIII/IX/g;s/IIII/IV/g;print;
Тор
источник
2

MUMPS 184

S V(100)="C",V(90)="XC",V(50)="L",V(40)="XL",V(10)="X",V(9)="IX",V(5)="V",V(4)="IV",V(1)="I" F I=1:1:100 S S=I,N="" F  Q:'S  S N=$O(V(N),-1) I S&(S'<N ) S S=S-N W V(N) S N="" w:'S " "

Тот же алгоритм, что и у @cardboard_box, у которого я дословно взял объяснение -

объяснение

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

'C'  = 100
'XC' = 90
'L'  = 50
'XL' = 40
'X'  = 10
'IX' = 9
'V'  = 5
'IV' = 4
'I'  = 1
PSR
источник
2

R , 85 байт

R=.romans
for(r in 1:100){while(r>0){cat(names(R[I<-R<=r][1]))
r=r-R[I][1]}
cat(" ")}

Попробуйте онлайн!

Использует случайную utilsпеременную пакета, .romansчтобы получить значения римских цифр, но выполняет преобразование само по себе; встроенный подход будет 20 байтов:cat(as.roman(1:100))

Giuseppe
источник
Удивительно, но упомянутый вами встроенный подход не работает как есть ... нужно вводить текст cat(paste(as.roman(1:100)))или просто as.roman(1:100). Weird.
JayCe
@JayCe странно; Я, должно быть, не проверял это на самом деле ... документы catуказывают на то, что он выполняет меньше преобразований, чем printи работает только на atomicвекторах - так что это объясняет!
Джузеппе
1

APL 128

Я попробовал решение для индексирования в APL:

r←⍬                                                                             
i←1                                                      
l:r←r,' ',('   CXI LV CX'[,⍉((1+(4 4 2 2⊤0 16 20 22 24 32 36 38 39 28)[;1+(3⍴10)⊤i])×3)-4 3⍴2 1 0])~' '
→(100≥i←i+1)/l                                                                  
r              

Он может быть на 4 байта короче в начале индекса 0 вместо 1, но реальный пробел в пространстве - это создание матрицы индекса посредством:

4 4 2 2⊤0 16 20 22 24 32 36 38 39 28

До сих пор я не смог генерировать индексы на лету!

Грэхем
источник
1

Латекс (138)

\documentclass{minimal}
\usepackage{forloop}
\begin{document}
\newcounter{i}
\forloop{i}{1}{\value{i} < 101}{\roman{i}\par}
\end{document}
Патрик Осцити
источник
1
-1: вопрос гласит: «Вы не можете использовать любую встроенную функцию для преобразования в римские цифры»
изабера
1

Питон, 125

' '.join(i+j for i in['']+'X XX XXX XL L LX LXX LXXX XC C'.split()for j in['']+'I II III IV V VI VII VIII IX'.split())[1:-38]
TheCrypt
источник
1

PHP, 38 37 байт

<ol type=I><?=str_repeat("<li>",100);

-1 байт благодаря @manatwork

Та же идея, что и в ответе Патрика , но на более компактном языке. Бьет Mathematica !

Попробуйте онлайн!

geokavel
источник
Завершите утверждение с помощью ;, тогда нет необходимости ?>.
manatwork
1

VBA (Excel), 245 байт

созданная функция для повторения и замены - 91 байт

Function s(a,b):s=String(a,b):End Function Function b(x,y,z):b=Replace(x,y,z):End Function

используя непосредственное окно ( 154 байта )

p="I":for x=1to 100:?b(b(b(b(b(b(b(b(s(x,p),s(100,p),"C"),s(90,p),"XC"),s(50,p),"L"),s(40,p),"XL"),s(10,p),"X"),s(9,p),"IX"),s(5,p),"V"),s(4,p),"IV"):next

remoel
источник
0

Java (OpenJDK 8) , 152 байта

a->{String[] t=",X,XX,XXX,XL,L,LX,LXX,LXXX,XC,,I,II,III,IV,V,VI,VII,VIII,IX".split(",");for(int i=1;i<100;i++){a+=t[i/10]+t[i%10+10]+" ";}return a+"C";}

Попробуйте онлайн!

Объяснение:

String[] t=",X,XX,XXX,XL,L,LX,LXX,LXXX,XC,,I,II,III,IV,V,VI,VII,VIII,IX".split(",");
//Create an array of numerals, first half represents tens place, second half represents ones place
    for(int i=1;i<100;i++){             
//Loop 99 times
        a+=t[i/10]+t[i%10+10]+" ";   
//Add tens place and ones place to the string
    }return a+"C";                         
//Add numeral for 100 and return the string
X1M4L
источник
0

TeX, 354 байта

\let~\let~\d\def~\a\advance~\b\divide~\x\expandafter~\f\ifnum{~~\newcount~\n~\i~\j~\k~\u~\v}~~\or\d\p#1{\ifcase#1C~2~L~5~X~2~V~5~I\fi}\d\q#1{\p{#1~}}\d\r{\j0
\v100\d\m{\d\w{\f\n<\v\else\p\j\a\n-\v\x\w\fi}\w\f\n>0\k\j\u\v\d\g{\a\k2\b\u\q\k}\g\f\q\k=2\g\fi\a\n\u\f\n<\v\a\n-\u\a\j2\b\v\q\j\else\p\k\fi\x\m\fi}\m}\i1\d\c{
\f\i<101 \n\i\r\a\i1 \x\c\fi}\c\bye

Некоторое объяснение: TeX предоставляет встроенную команду \romannumeralдля преобразования чисел в римские цифры. Поскольку вопрос не позволяет использовать встроенные функции, приведенный выше код представляет собой версию для гольфа того же самого алгоритма, который использует оригинальный компилятор TeX Кнута \romannumeral(см. TeX: Программа , § 69 print_roman_int), повторно реализованный в TeX.

Поскольку он хочет оставить читателю радость от размышлений о том, как этот код работает, Кнут отказывается дать объяснение этой части кода. Поэтому я последую их примеру и просто приведу неоправданную и слегка измененную версию, которая ближе к оригиналу, чем приведенный выше код:

\newcount\n
\newcount\j
\newcount\k
\newcount\u
\newcount\v

\def\chrnum#1{\ifcase#1m\or 2\or d\or 5\or c\or 2\or l\or 5\or x\or 2\or v\or 5\or i\fi}
\def\chrnumM#1{\chrnum{#1\or}}

\def\roman#1{%
    \n=#1\relax
    \j=0\relax
    \v=1000\relax
    \def\mainloop{%
        \def\while{%
            \ifnum\n<\v
            \else
                \chrnum\j
                \advance\n -\v
                \expandafter\while
            \fi
        }\while
        \ifnum\n>0\relax
            \k=\j \advance\k 2\relax
            \u=\v \divide\u \chrnumM\k
            \ifnum\chrnumM\k=2\relax
                \advance\k 2\relax
                \divide\u \chrnumM\k
            \fi
            \advance\n \u
            \ifnum\n<\v
                \advance\n -\u
                \advance\j 2\relax
                \divide\v \chrnumM\j
            \else
                \chrnum\k
            \fi
            \expandafter\mainloop
        \fi
    }\mainloop
}

\newcount\i \i=1
\def\countloop{%
    \ifnum\i<100\relax
        \roman\i\ 
        \advance\i 1
        \expandafter\countloop
    \fi
}\countloop
\bye
Сиракуза
источник