Comptez de 1 à 100… en chiffres romains

29

Écrivez un programme qui compte de 1 à 100 en chiffres romains et imprimez ces nombres par sortie standard. Chacun des nombres doit être séparé par des espaces.

Vous ne pouvez utiliser aucune fonction intégrée pour vous transformer en chiffres romains, ni aucune application ou bibliothèque externe pour ce faire.

Le résultat souhaité est

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

Comme c'est un défi de golf de code, le code le plus court gagne .

Averroes
la source
4
39 manque un X.
Thor
@Thor Fixed, thanks;)
Averroes
1
Je veux vraiment utiliser INTERCAL pour celui-ci.
Weijun Zhou
peut-il être séparé par des retours à la ligne? Et qu'en est-il des espaces de fin / de début / des nouvelles lignes?
FantaC

Réponses:

68

Perl 69 octets

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

Fonctionne par formule magique. L'expression "32e$&"%72726transforme chaque chiffre de la manière suivante:
0⇒32, 1⇒320, 2⇒3200, 3⇒32000, 4⇒29096, 5⇒56, 6⇒560, 7⇒5600, 8⇒56000, 9⇒50918

Après avoir appliqué la traduction y/016/IXV/, nous avons ceci à la place:
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

Les autres chiffres ( 2-57-9) sont supprimés. On notera que ce pourrait être améliorée par un octet en utilisant une formule qui se traduit à la 012place de 016, ce qui simplifie /XVI60-9/à /XVI0-9/. Je n'ai pas pu en trouver, mais peut-être aurez-vous plus de chance.

Une fois qu'un chiffre a été transformé de cette manière, le processus se répète pour le chiffre suivant, en ajoutant le résultat et en traduisant les XVIs précédents CLXen même temps que la traduction du nouveau chiffre se produit.

La
recherche exhaustive n'a rien révélé de plus court. J'ai cependant trouvé une solution alternative à 69 octets:

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

Celui-ci utilise une 0-2substitution pour IXV, mais a un modulo d'un chiffre de plus.


Mise à jour: 66 65 octets

Cette version est notablement différente, donc je devrais probablement en dire quelques mots. La formule qu'il utilise est en fait un octet de plus!

Incapable de raccourcir la formule plus qu'elle ne l'est, j'ai décidé de jouer avec ce que j'avais. Il ne fallut pas longtemps pour que je me souvienne de mon vieil ami $\. Lorsqu'un printétat est émis, $\est automatiquement ajouté à la fin de la sortie. J'ai pu me débarrasser de la $a[$_]construction maladroite pour une amélioration de deux octets:

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

Beaucoup mieux, mais cela $\=!print$"semblait encore un peu bavard. Je me suis alors souvenu d'une formule alternative de longueur égale que j'avais trouvée qui ne contenait le nombre 3dans aucune de ses transformations de chiffres. Donc, il devrait être possible d'utiliser à la $\=2+printplace et de remplacer le résultat 3par un espace:

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

Également 67 octets, en raison de l'espace nécessaire entre printet for.

Edit : Cela peut être amélioré d'un octet, en déplaçant le printvers l'avant:

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

Étant donné que la substitution doit être évaluée complètement avant le print, l'affectation à $\aura toujours lieu en dernier. La suppression de l'espace entre geet forémettra un avertissement de dépréciation, mais est par ailleurs valide.

Mais, s'il y avait une formule qui n'utilisait pas 1n'importe où, $\=2+printdevient $\=printpour deux octets supplémentaires d'économies. Même si c'était un octet de plus, ce serait quand même une amélioration.

En fait, une telle formule existe, mais elle est un octet de plus que l'original, ce qui donne un score final de 65 octets :

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

Méthodologie

La question a été posée de savoir comment procéder pour trouver une telle formule. En général, trouver une formule magique pour généraliser n'importe quel ensemble de données est une question de probabilité. C'est-à-dire que vous voulez choisir une forme qui est aussi susceptible que possible de produire quelque chose de similaire au résultat souhaité.

Examen des premiers chiffres romains:

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

il y a une certaine régularité à voir. Plus précisément, de 0 à 3 puis de 5 à 8 , chaque terme successif augmente de longueur d'un chiffre. Si nous voulions créer un mappage de chiffres à chiffres, nous voudrions avoir une expression qui augmente également en longueur d'un chiffre pour chaque terme successif. Un choix logique est k • 10 dd est le chiffre correspondant et k est une constante entière.

Cela fonctionne pour 0-3 , mais 4 doit briser le modèle. Ce que nous pouvons faire ici, c'est coller sur un modulo:
k • 10 d % m , où m est quelque part entre k • 10 3 et k • 10 4 . Cela laissera la plage 0-3 intacte et modifiera 4 de sorte qu'elle ne contiendra pas quatre Is. Si nous contraignons en outre notre algorithme de recherche de sorte que le résidu modulaire de 5 , appelons-le j , soit inférieur à m / 1000 , cela garantira que nous avons également une régularité de 5-8 . Le résultat est quelque chose comme ceci:

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

Comme vous pouvez le voir, si nous remplaçons 0par I, 0-3 et 5-8 sont tous garantis pour être correctement cartographiés! Les valeurs de 4 et 9 doivent cependant être forcées brutalement. Plus précisément, 4 doit contenir un 0et un j(dans cet ordre) et 9 doit en contenir un 0, suivi d'un autre chiffre qui n'apparaît nulle part ailleurs. Certes, il existe un certain nombre d'autres formules qui, par un coup de hasard, pourraient produire le résultat souhaité. Certains d'entre eux peuvent même être plus courts. Mais je ne pense pas qu'il y en ait qui soient aussi susceptibles de réussir que celui-ci.

J'ai également expérimenté plusieurs remplacements pour Iet / ou Vavec un certain succès. Mais hélas, rien de plus court que ce que j'avais déjà. Voici une liste des solutions les plus courtes que j'ai trouvées (le nombre de solutions de 1 à 2 octets de plus est trop important pour être répertorié):

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
primo
la source
3
Comment avez-vous trouvé la formule magique?
Ruben Verborgh
1
@RubenVerborgh Je mettrai à jour mon article avec plus d'informations concernant la méthodologie bientôt.
primo
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​}

Sortie

Liste numérotée avec chiffres romains

...

Démo sur JSBin

Patrick Oscity
la source
1
Version JS 81 octets uniquement: document.write('<ol>'+"<li style='list-style:upper-roman'/>".repeat(100)+'</ol>')(ES6)
Paperjam
ou 66 dans Chromedocument.write("<li style='list-style:upper-roman'/>".repeat(100))
Slai
10

Python 116

meilleur code golfé de la réponse de 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'
Daniel
la source
8

Python, 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
la source
6

C, 177 160 147 caractères

Il existe des solutions plus courtes, mais aucune en C, alors voici mon essai.

Nouvelle solution, complètement différente de la précédente:

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");
}

Solution précédente (160 caractères):

Logique:
1. fimprime un nombre de 1 à 10. cest le chiffre utilisé, qui peut être IVXou XLC. Appelé une fois pour les dizaines une fois pour celles.
2. Si n%5==0- n'imprime rien ou c[n/5]qui est Iou V(ou Lou C).
3. Si n%4==4- 4ou 9- imprimer I(ou X), par n+1.
4. Si n>4- imprimer 5(c'est V-à- dire ou L) alors n-5.
5. Si n<4- imprimez Ialors n-1(c.-à-d. nFois 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
la source
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");}
gastropner
5

JavaScript, 123

Inspiré par une version plus longue, je suis tombé sur un groupe de discussion polonais (au moins, Chrome pensait que c'était polonais).

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)
Paul Walls
la source
5

Q ( 81 80)

2ème coupe:

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

1ère coupe:

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

Python, 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]),

Explication

En utilisant ces valeurs, prenez la plus grande valeur non supérieure à n et soustrayez-la de n. Répétez jusqu'à ce que n soit 0.

'C'  = 100
'XC' = 90
'L'  = 50
'XL' = 40
'X'  = 10
'IX' = 9
'V'  = 5
'IV' = 4
'I'  = 1
boîte en carton
la source
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""enregistre deux caractères. Sinon très sympa.
cemper93
4

Rubis 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}

Cela compte littéralement de 1 à 100 en chiffres romains. Commence par une chaîne vide, puis passe par l'ajout de «I», puis par l'application répétée d'une série de règles de substitution, ajoutant effectivement 1.

Edit: Ajout du numéro de version, car ?Ine fonctionne que dans 1.9, et a utilisé les modifications de @ Howard pour couper certains caractères.

histocrate
la source
Vous pouvez enregistrer deux caractères: r while-> 0while, r.sub!(*q)-> r.sub! *q. Vous pouvez également faire glisser l'impression à l'intérieur de la boucle et l'utiliser à la 100.times{...}place de l'instruction map.
Howard
(%w[IIII VIV XXXX LXL]<</(.)((?!\1)[^I])\1/).zip(%w(IV IX XL XC)<<'\2')enregistre 7 caractères.
steenslag
4

Ruby 112 caractères

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}

Fondamentalement, en utilisant la to_romanméthode expliquée ici , mais en utilisant un tableau zippé pour plus de brièveté.

steenslag
la source
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}]

chiffres romains


Solution intégrée : IntegerString38 caractères

IntegerString[k, "Roman"]~Table~{k, 100}
DavidC
la source
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;

Golfé:

@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;
Thor
la source
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 " "

Même algorithme que @cardboard_box, dont j'ai repris l'explication textuellement -

Explication

En utilisant ces valeurs, prenez la plus grande valeur non supérieure à n et soustrayez-la de n. Répétez jusqu'à ce que n soit 0.

'C'  = 100
'XC' = 90
'L'  = 50
'XL' = 40
'X'  = 10
'IX' = 9
'V'  = 5
'IV' = 4
'I'  = 1
psr
la source
2

R , 85 octets

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

Essayez-le en ligne!

Utilise la utilsvariable de package aléatoire .romanspour obtenir les valeurs des chiffres romains, mais effectue la conversion par elle-même; l'approche intégrée serait de 20 octets:cat(as.roman(1:100))

Giuseppe
la source
Étonnamment, l'approche intégrée que vous mentionnez ne fonctionne pas telle quelle ... il faut taper cat(paste(as.roman(1:100)))ou simplement as.roman(1:100). Bizarre.
JayCe
@JayCe odd; Je ne dois pas l'avoir testé ... les documents pour catindiquent qu'il effectue moins de conversion que printet ne fonctionne que sur des atomicvecteurs - ce qui explique cela!
Giuseppe
1

APL 128

J'ai essayé une solution d'indexation en 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              

Il peut être de 4 octets plus court en origine d'index 0 au lieu de 1 mais le véritable porc spatial est la génération de la matrice d'index via:

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

Jusqu'à présent, je n'ai pas pu générer les indices à la volée!

Graham
la source
1

LaTeX (138)

\documentclass{minimal}
\usepackage{forloop}
\begin{document}
\newcounter{i}
\forloop{i}{1}{\value{i} < 101}{\roman{i}\par}
\end{document}
Patrick Oscity
la source
1
-1: la question dit "Vous ne pouvez utiliser aucune fonction intégrée pour vous transformer en chiffres romains"
izabera
1

Python, 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
la source
1

PHP, 38 37 octets

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

-1 octet grâce à @manatwork

Même idée que la réponse de Patrick , mais dans un langage plus compact. Beats Mathematica !

Essayez-le en ligne!

geokavel
la source
Terminez la déclaration avec ;, alors pas besoin de ?>.
manatwork
1

VBA (Excel), 245 octets

fonction créée pour la répétition et le remplacement - 91 octets

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

en utilisant la fenêtre immédiate ( 154 octets )

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
la source
0

Java (OpenJDK 8) , 152 octets

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";}

Essayez-le en ligne!

Explication:

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
la source
0

TeX, 354 octets

\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

Quelques explications: TeX fournit une commande intégrée \romannumeralpour convertir des nombres en chiffres romains. Comme la question ne permet pas d'utiliser les fonctions intégrées, le code ci-dessus est une version golfée du même algorithme que le compilateur TeX original de Knuth utilise pour \romannumeral(voir TeX: The Program , § 69, print_roman_int) réimplémenté dans TeX.

Comme il veut laisser la joie de dérouter le fonctionnement de ce code au lecteur, Knuth refuse de donner une explication de cette partie du code. Je vais donc emboîter le pas et donner juste une version non golfée et légèrement modifiée, qui est plus proche de l'original que le code ci-dessus:

\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
siracusa
la source