Новогоднее издание Code Golf - от целых до римских цифр
Напишите программу, которая принимает один аргумент командной строки N и печатает соответствующий римский номер.
Например, N = 2009 должен печатать MMIX.
Допустим, это должно работать для 0 (Было весело поиграть в мой первый раунд гольф-кода с рождественским изданием, и я подумал, что это может подойти к Новому году. Погуглил, чтобы увидеть, если это произошло раньше, и похоже, что нет, но дайте мне знать, если это это слишком сложно или слишком просто, или если правила требуют изменения.) Счастливого MMIX!
31 ответ
Perl: 69 ударов (считай!)
Шестьдесят девять ударов, в том числе вызов perl:
$ perl -ple's!.!($#.=5x$&*8%29628)=~y$IVCXL4620-8$XLMCDIXV$d!eg;last}{'
3484
MMMCDLXXXIV
- Читает одну строку, пишет одну строку.
- Работает от 0 до 3999 включительно. (Печатает пустую строку для 0.)
- В соревнованиях по гольфу Perl это обычно оценивается как 62 удара = 58 для кода + 4 для переключателей.
- Почему, да, это несоответствующие брекеты. Спасибо за вопрос. знак равно
Кредиты: первоначально благодаря Тону Хоспелу. Трюк с использованием несовпадающих фигурных скобок rev.pl
в этом посте (что, кстати, гениально).
В C# в качестве метода расширения Int32
:
public static class Int32Extension {
public static string ToRomanNumeral(this int number) {
Dictionary<int, string> lookup = new Dictionary<int, string>() {
{ 1000000, "M_" },
{ 900000, "C_D_" },
{ 500000, "D_" },
{ 400000, "C_D_" },
{ 100000, "C_" },
{ 90000, "X_C_" },
{ 50000, "L_" },
{ 40000, "X_L_" },
{ 10000, "X_" },
{ 9000, "MX_"},
{ 5000, "V_" },
{ 4000, "MV_" },
{ 1000, "M" },
{ 900, "CM" },
{ 500, "D" },
{ 400, "CD" },
{ 100,"C" },
{ 90, "XC" },
{ 50, "L" },
{ 40, "XL" },
{ 10, "X" },
{ 9, "IX" },
{ 5, "V" },
{ 4, "IV" },
{ 1, "I" }
};
StringBuilder answer = new StringBuilder();
foreach (int key in lookup.Keys.OrderBy(k => -1 * k)) {
while (number >= key) {
number -= key;
answer.Append(lookup[key]);
}
}
return answer.ToString();
}
}
Подчеркивание должно быть подчеркнуто над соответствующей буквой, чтобы быть истинной римской цифрой.
Общий шепот (SBCL). 63 символа подсчитаны "wc -c".
(format t "~@R~%" (parse-integer (elt *posix-argv* 1)))
(quit)
Это работает только для номеров до 3999.
C#: 179 символов (не включая пробелы / табуляции)
static string c(int a)
{
int[] v = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
var s = "";
for ( var i = 0; i < 13; i++ )
while (a >= v[i])
{
a -= v[i];
s += "M CM D CD C XC L XL X IX V IV I".Split()[i];
}
return s;
}
Язык: JavaScript.
129 символов без дополнительного форматирования
Следующий код является результатом теста по кодированию, который проходил в pl.comp.lang.javascript
newsgrup несколько лет назад. Я не автор кода.
function rome(N,s,b,a,o){
for(s=b='',a=5;N;b++,a^=7)for(o=N%a,N=N/a^0;o--;)
s='IVXLCDM'.charAt(o>2?b+N-(N&=~1)+(o=1):b)+s;return s
}
Оригинальное сообщение от Elus
Perl, 19 ударов. Гарантируется работа для значений от 1 до 12.
sub r{chr 8543+pop}
Python, 173 байта.
r=lambda n:o[n]if n<10 else''.join(dict(zip('ivxlc','xlcdm'))[c]for c in r(n//10))+o[n%10]
o=' i ii iii iv v vi vii viii ix'.split(' ')
import sys
print r(int(sys.argv[1]))
(Я впервые увидел этот алгоритм в алгоритмах Gimpel в Snobol4; Snobol выразил его более элегантно.)
Язык: C, Количество символов: 174
#define R(s,v)for(;n>=v;n-=v)printf(#s);
main(int n,char**a){n=atoi(a[1]);R(M,1000)R(CM,900)R(D,500)R(CD,400)R(C,100)R(XC,90)R(L,50)R(XL,40)R(X,10)R(IX,9)R(V,5)R(IV,4)R(I,1)}
щука
60 символов, действительны от 0 до 10000:
int main (int c, array a) {
write(String.int2roman((int)a[1]));
}
Простая версия на Haskell, которая до сих пор сохраняет ясность. 205 символов, включая пробелы.
l = ["M","CM","L","CD","C","XC","L","XL","X","IX","V","IV","I"]
v = [1000,900,500,400,100,90,50,40,10,9,5,4,1]
roman n i
| n == 0 = ""
| n >= v!!i = l!!i ++ roman (n-v!!i) i
| otherwise = roman n (i+1)
Perl 5.10
perl -nE'@l=qw{1 I 4 IV 5 V 9 IX 10 X 40 XL 50 L 90 XC 100 C 400 CD 500 D 900 CM 1000 M};
$o="";while(@l){$o.=pop(@l)x($_/($c=pop @l));$_%=$c;}say$o'
Вы вводите строку, она дает вам римскую цифру, равную. Эта первая версия даже позволяет вводить более одной строки.
Вот более короткая версия, которая работает только для одной строки и игнорирует крайние случаи. так 4
становится IIII
вместо IV
,
perl -nE'@l=qw{1 I 5 V 10 X 50 L 100 C 500 D 1000 M};
while(@l){$o.=pop(@l)x($_/($c=pop @l));$_%=$c;}say$o'
Вот как будет выглядеть первая версия скрипта Perl.
use 5.010;
while(<>){
@l=qw{1 I 4 IV 5 V 9 IX 10 X 40 XL 50 L 90 XC 100 C 400 CD 500 D 900 CM 1000 M};
$o="";
while(@l){
$o .= pop(@l) x ($_/($c=pop @l));
# $l = pop @l;
# $c = pop @l;
# $o .= $l x ($_/$c);
$_ %= $c;
}
say $o;
}
Perl, 145 ударов (если вы удалите все новые строки, которые являются необязательными), действителен для 1..3999:
%t=qw(1000 M 900 CM 500 D 400 CD 100 C 90 XC 50 L 40 XL 10 X 9 IX 5 V 4 IV 1 I);
$d=pop;
for(sort{$b<=>$a}keys%t){$r.=$t{$_}x($d/$_);$d%=$_}
print$r
Некоторые скажут, что я мог бы использовать say
но у меня нет say
-capable версия Perl здесь. Не стесняйтесь вычесть 2 из числа ударов при использовании say
работает.:-)
Для не программистов на Perl эта программа использует ряд полезных функций Perl:
- Хеши строятся из списков четной длины.
- Списки строк могут быть указаны в компактном синтаксисе, используя
qw
, - Строки могут автоматически приводиться к целым числам, как используется в
<=>
оператор сравнения при сортировке ключей. - Есть
x
оператор, который делает копии строк / списков. К сожалению для игры в гольф здесь,x
имеет идентичный приоритет/
; если/
были выше, скобки тоже были бы необязательными.
Рубин, 136 символов
n = $*[0].to_i
for k,v in [1e3,900,500,400,100,90,50,40,10,9,5,4,1].zip %w{M CM D CD C XC L XL X IX V IV I}
until n < k
n -= k
print v
end
end
J, 20 символов!
'MDCLXVI'#~(7$5 2)#:
Использование:
'MDCLXVI'#~(7$5 2)#: 2009
MMVIIII
Хорошо, это не делает вычитание должным образом, но эй, это довольно круто!
Объяснение;
(7$5 2)
Это принимает правильный аргумент (список 5 2
) и превращает его в список размером 7, а именно 5 2 5 2 5 2 5
,
(7$5 2)#: 2009
Это делает "анти-базовую" операцию - в основном выполняет итеративные операции div и mod, возвращая список 2 0 0 0 0 0 1 4
,
затем #~
использует предыдущий список как подсчет, чтобы вытащить соответствующие символы из 'MDCLXVI'
,
Язык: dc (через оболочку) Количество символов:122
РЕДАКТИРОВАТЬ: Q эквивалентно 2Q
dc -e '[I]1[IV]4[V]5[IX]9[X]10[XL]40[L]50[XC]90[C]100[CD]400[D]500[CM]900[M]?1000[szsz2Q]sq[~Sa[d0!<qrdPr1-lbx]dsbxLarz3<c]dscx10P' <<<$1
РЕДАКТИРОВАТЬ: еще два символа путем оптимизации манипуляций стека основного цикла
dc -e '[I]1[IV]4[V]5[IX]9[X]10[XL]40[L]50[XC]90[C]100[CD]400[D]500[CM]900[M]?1000[szsz2Q]sq[~Sa[d0!<qrdPr1-lbx]dsbxLarz3<c]dscx10P' <<<$1
РЕДАКТИРОВАТЬ: сохранить 2 символа
dc -e '[I]1[IV]4[V]5[IX]9[X]10[XL]40[L]50[XC]90[C]100[CD]400[D]500[CM]900[M]1000?[sz2Q]sq[r~r[d0!<qSardPrLa1-lbx]dsbxrszz2<c]dscx10P' <<<$1
Предыдущая версия:
dc -e '[I]1[IV]4[V]5[IX]9[X]10[XL]40[L]50[XC]90[C]100[CD]400[D]500[CM]900[M]1000?[sz2Q]sq[r~r[d0!<qSaSadPLaLa1-lbx]dsbxrszz2<c]dscx10P' <<<$1
Я не эксперт по Haskell, и это слишком долго, чтобы быть победителем, но вот решение, которое я написал некоторое время назад, чтобы решить Euler #89.
toRoman 0 = ""
toRoman 1 = "I"
toRoman 2 = "II"
toRoman 3 = "III"
toRoman 4 = "IV"
toRoman n
| n >= 1000 = repeatRoman 'M' 1000
| n >= 900 = subtractRoman "CM" 900
| n >= 500 = subtractRoman "D" 500
| n >= 400 = subtractRoman "CD" 400
| n >= 100 = repeatRoman 'C' 100
| n >= 90 = subtractRoman "XC" 90
| n >= 50 = subtractRoman "L" 50
| n >= 40 = subtractRoman "XL" 40
| n >= 10 = repeatRoman 'X' 10
| n >= 9 = subtractRoman "IX" 9
| n >= 5 = subtractRoman "V" 5
| otherwise = error "Hunh?"
where
repeatRoman c n' = (take (n `div` n') (repeat c)) ++ (toRoman $ n `mod` n')
subtractRoman s n' = s ++ (toRoman $ n - n')
В Python - взято из ActiveState (предоставлено Полом Винклером) и немного сжато:
def int2roman(n):
if not 0 < n < 4000: raise ValueError
ints = (1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1)
nums = ('M', 'CM', 'D', 'CD','C', 'XC','L','XL','X','IX','V','IV','I')
result = ""
for i in range(len(ints)):
count = int(n / ints[i])
result += nums[i] * count
n -= ints[i] * count
return result
VB: 193 символа
Function c(ByVal a)
Dim v() = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}
Dim s = ""
For i = 0 To 12
While a >= v(i)
a -= v(i)
s += "M|CM|D|CD|C|XC|L|XL|X|IX|V|IV|I".Split("|")(i)
End While
Next
Return s
End Function
Excel 8 символов (не считая числа):
= РОМАН (N)
Работает до 3000.
Язык в щеке
От неопределенно C-подобного языка, называемого LPC (предшественник Pike):
string roman_numeral(int val) {
check_argument(1, val, #'intp);
unless(val)
return "N";
string out = "";
if(val < 0) {
out += "-";
val = -val;
}
if(val >= 1000) {
out += "M" * (val / 1000);
val %= 1000;
}
if(val >= 100) {
int part = val / 100;
switch(part) {
case 9 :
out += "CM";
break;
case 6 .. 8 :
out += "D" + ("C" * (part - 5));
break;
case 5 :
out += "D";
break;
case 4 :
out += "CD";
break;
default :
out += "C" * part;
break;
}
val %= 100;
}
if(val >= 10) {
int part = val / 10;
switch(part) {
case 9 :
out += "XC";
break;
case 6 .. 8 :
out += "L" + ("X" * (part - 5));
break;
case 5 :
out += "L";
break;
case 4 :
out += "XL";
break;
default :
out += "X" * part;
break;
}
val %= 10;
}
switch(val) {
case 9 :
out += "IX";
break;
case 6 .. 8 :
out += "V" + ("I" * (val - 5));
break;
case 5 :
out += "V";
break;
case 4 :
out += "IV";
break;
default :
out += "I" * val;
break;
}
return out;
}
Python, 190 байт. Основано на фрагменте из ActiveState, через Федерико.
Несколько небольших оптимизаций: удаление лишнего вызова int(), разбиение строки для получения массива, удаление пробелов,...
import sys
n=int(sys.argv[1])
N=(1000,900,500,400,100,90,50,40,10,9,5,4,1)
r=""
for i in range(len(N)):
c=n/N[i]
r+='M,CM,D,CD,C,XC,L,XL,X,IX,V,IV,I'.split(',')[i]*c
n-=N[i]*c
print r
РЕДАКТИРОВАТЬ: лишнее, не поддельное и удалить проверку дальности - благодаря Chris Jester-Young и dreeves! Украл идею использования встроенного массива символов из BenAlabaster.
В C# (работает на.NET 4 RC) с 335 символами (если вы удалите постороннее форматирование).
using System;
using System.Linq;
class C
{
static void Main()
{
Console.WriteLine(
Console.ReadLine()
.PadLeft(4,'0')
.Select(d=>d-'0')
.Zip(new[]{" M","MDC","CLX","XVI"},(x,y)=>new{x,y})
.Aggregate("",(r,t)=>r+
new string(t.y[2],t.x%5/4)+
new string(t.y[0],t.x%5/4*t.x/5)+
new string(t.y[1],Math.Abs(t.x%5/4-t.x/5))+
new string(t.y[2],t.x%5%4)));
}
}
Я знаю, что это не лучший текущий ответ C# (182 символа), но это всего лишь одна большая строка LINQ. Как только я увидел raytracer, написанный как один запрос LINQ, я начал подходить к кодовым играм с этой точки зрения.
Поскольку этот подход является функциональным, я работаю над тем же алгоритмом на Haskell (наверняка будет короче).
Railo CFML - 53 символа, 46 без пробелов...
<cfoutput>
#NumberFormat( N , 'roman' )#
</cfoutput>
Или, для других двигателей CF, не уверен, что они самые короткие, но пока они подойдут...
CFML - 350..453 знаков:
<cffunction name="RomanNumberFormat">
<cfset var D = ListToArray('M,CM,D,C,XC,L,X,IX,V,IV,I') />
<cfset var I = [1000,900,500,100,90,50,10,9,5,4,1] />
<cfset var R = '' />
<cfset var x = 1 />
<cfset var A = Arguments[1] />
<cfloop condition="A GT 0">
<cfloop condition="A GTE I[x]">
<cfset R &= D[x] />
<cfset A -= I[x] />
</cfloop>
<cfset x++ />
</cfloop>
<cfreturn R />
</cffunction>
<cfoutput>
#RomanNumberFormat(N)#
</cfoutput>
CFScript - 219,323 символов:
<cfscript>
function RomanNumberFormat(A)
{
var D = ListToArray('M,CM,D,C,XC,L,X,IX,V,IV,I');
var I = [1000,900,500,100,90,50,10,9,5,4,1];
var R = '';
var x = 1;
while ( A > 0 )
{
while( A >= I[x] )
{
R &= D[x];
A -= I[x];
}
x++;
}
return R;
}
WriteOutput( RomanNumberFormat(N) );
</cfscript>
Delphi (или Pascal, здесь нет ничего специфичного для Delphi):
Function ToRoman(N : Integer) : String;
Const
V : Array [1..13] of Word = (1000,900,500,400,100,90,50,40,10.9,5,4,1);
T : Array [1..13] of String = ('M','CM','D','CD','C','XC','L','XL','X','IX','V','I');
Var I : Word;
Begin
I := 1;
Repeat
While N < V[I] do Inc(I);
Result := Result + T[I];
N := N - V[I];
Until N = 0;
End;
Как каждый получает счет персонажа? (Я считаю 8 необходимых пробелов, все остальное просто для форматирования.)
Язык: Erlang, Количество символов: 222
EDIT2: препроцессор Erlang допускает какие-то несбалансированные макросы, поэтому эта версия на 9 символов короче.
-module(n2).
-export([y/1]).
-define(D(V,S),n(N)when N>=V->[??S|n(N-V)];).
y(N)->io:format(n(N)).
?D(1000,M)?D(900,CM)?D(500,D)?D(400,CD)?D(100,C)?D(90,XC)?D(50,L)?D(40,XL)?D(10,X)?D(9,IX)?D(5,V)?D(4,IV)?D(1,I)n(0)->[10].
РЕДАКТИРОВАТЬ: более короткая версия, вдохновленная версией Дария (231 символ)
-module(n).
-export([y/1]).
y(N)->io:format([n(N),10]).
n(N)when N>9->[Y||C<-n(N div 10),{K,Y}<-lists:zip("IVXLC","XLCDM"),K==C]++o(N rem 10);n(N)->o(N).
o(N)->lists:nth(N+1,[[]|string:tokens("I II III IV V VI VII VIII IX"," ")]).
Это менее читабельно, но сохранить 2 символа (233 символа).
-module(n).
-export([y/1]).
-define(D(V,S),n(N)when N>=V->[??S|n(N-V)]).
y(N)->io:format(n(N)).
?D(1000,M);?D(900,CM);?D(500,D);?D(400,CD);?D(100,C);?D(90,XC);?D(50,L);?D(40,XL);?D(10,X);?D(9,IX);?D(5,V);?D(4,IV);?D(1,I);n(0)->[10].
Версия командной строки:
-module(n).
-export([y/1]).
-define(D(V,S),n(N)when N>=V->[??S|n(N-V)]).
y([N])->io:format(n(list_to_integer(N))),init:stop().
?D(1000,M);?D(900,CM);?D(500,D);?D(400,CD);?D(100,C);?D(90,XC);?D(50,L);?D(40,XL);?D(10,X);?D(9,IX);?D(5,V);?D(4,IV);?D(1,I);n(0)->[10].
Призвание:
$ erl -noshell -noinput -run n y 2009
MMIX
РЕДАКТИРОВАТЬ: я сохранил 17 символов, используя расширение буквального макроса.
Java: 286 значимых символов
public class R {
String[]x="M,CM,D,C,XC,L,X,IX,V,I".split(",");
int[]n={1000,900,500,100,90,50,10,9,5,1};
String p(String s,int d,int i){return 10<=i?s:n[i]<=d?p(s+x[i],d-n[i],i):p(s,d,i+1);}
public static void main(String[] a) {
System.out.println(new R().p("",Integer.parseInt(a[0]),0));
}
}
Под "значимыми символами" я подразумеваю печатные символы и необходимые пробелы (например, между типом и аргументом), но не чисто косметический пробел (переводы строки и отступы).
Вот решение C в 252 значащих символах. Допустимо от 0 <= i < 4000. В основном я написал это, потому что многие решения включают IV и IX в точках массива. Декодирование: t - это наш временный буфер, который мы заполняем обратно, чтобы нам не пришлось обращать его обратно при выводе. Переданный буфер должен содержать не менее 16 символов (для 3888 -> MMMDCCCLXXXVIII).
char* i2r(int i, char* r) {
char t[20];
char* o=t+19;*o=0;
char* s="IVXLCDMM";
for (char*p=s+1;*p&&i;p+=2) {
int x=i%10;
if (x==9) {*--o=p[1];*--o=p[-1];}
else if (x==4) {*--o=*p;*--o=p[-1];}
else {
for(;x&&x!=5;--x)*--o=p[-1];
if(x)*--o=*p;
}
i/=10;
}
return strcpy(r,o);
}
И я всегда забываю надеть главное. Вот вам и 252 символа:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main(int a,char**v){
char buf[16];
printf("%s\n",i2r(atoi(v[1])));
}
Реально просто: передайте запрос в Google и снимите с экрана ответ. Следующий.:п
Кстати, разве это не должно быть вики сообщества?
Язык: C, Количество символов: 195
Основано в значительной степени на C-решении me.yahoo.com/joe_mucchielle:
char t[99],*o=t+99,*s="IVXLCDMM",*p,x;n(v){*--o=p[v];}main(int i,int**v){i=atoi(v[1]);*o=0;
for(p=s+1;*p&&i;p+=2){x=i%10;if(x%5==4)n(x==9),n(-1);else{for(;x%5;--x)n(-1);if(x)n(0);}i/=10;}puts(o);}
Хаскелл, 245 персонажей.
roman = numeral [(1000,"M"),(900,"CM"),(500,"D"),(400,"CD"),(100,"C"),(90,"XC"),
(50,"L"),(40,"XL"),(10,"X"),(9,"IX"),(5,"V"),(4,"IV"),(1,"I")]
numeral [] n = ""
numeral ((m,c):xs) n = concat (replicate (n `div` m) c) ++ numeral xs (n `mod` m)