Je précise que la fonction doit marcher pour n entre 1 et 3999 en effet.
Une question me taraude, je ne connais pas très bien la numérotation romaine, mais est-ce qu'on est pas supposés écrire 490 comme "XD" ou 99 comme "IC" ?
Version imprimable
Je précise que la fonction doit marcher pour n entre 1 et 3999 en effet.
Une question me taraude, je ne connais pas très bien la numérotation romaine, mais est-ce qu'on est pas supposés écrire 490 comme "XD" ou 99 comme "IC" ?
49 s'écrit XLIX et non pas IL.
Sinon, j'ai pas encore essayé mais je tenterai de proposer un code d'ici demain.
Il y a pas mal de libertés prises avec l’énoncé :aie:
Citation:
Les unités à intégrer sont :
I 1
V 5
X 10
L 50
C 100
D 500
M 1 000
pile dans les clou sauf qu'elle ne marche pas sur 49 par exemple :cry:Code:
1
2
3 function fct(v){ s='';r='I,V,X,L,C,D,M,1,5,10,50,100,500,1e3'.split(',');for(i=6;v;i--){d=~~(v/r[i+7]);if(d>=1){for(g=0;g<d;g++)s+=r[i]}v%=r[i+7]}return s; }
Dans l'énoncé il y a surtout les 4 assertions à vérifier. Si une ne passe pas, c'est refusé :)
Foi de fabricant d'usines à gaz ;)
Cela dit... je suis admiratif ! 8OCitation:
vous êtes tous des MALADES !!! :fou:
Comme à mon habitude, je fais le rapia en économisant 1 caractère sur la meilleure solution :mrgreen:
124 caractèresCode:
1
2
3
4
5
6
7
8
9 function romain(n){ r='';for(x in(a={M:100,CM:90,D:50,CD:40,C:10,XC:9,L:5,XL:4,X:1,IX:.9,V:.5,IV:.4,I:.1}))for(i=a[x]*10;n>=i;n-=i)r+=x;return r } console.log( romain(12) + ' / ' + (romain(12) === "XII") ); console.log( romain(49) + ' / ' + (romain(49) === "XLIX") ); console.log( romain(74) + ' / ' + (romain(74) === "LXXIV") ); console.log( romain(383) + ' / ' + (romain(383) === "CCCLXXXIII")); console.log( romain(1000) + ' / ' + (romain(1000) === "M")); console.log( romain(3888) + ' / ' + (romain(3888) === "MMMDCCCLXXXVIII")); // le plus long possible !
Mouhéhéhé 98 :mrgreen: (fonctionne si n > 0 et n < 4000)
Explications :Code:
1
2
3
4
5
6
7
8
9 function romain(n){ for(a='',b=0,c=5;n;b++,c^=7)for(d=n%c,n=n/c^0;d--;a='IVXLCDM'[d>2?b+n-(n&=-2)+(d=1):b]+a);return a } console.log( romain(12) + ' / ' + (romain(12) === "XII") ); console.log( romain(49) + ' / ' + (romain(49) === "XLIX") ); console.log( romain(74) + ' / ' + (romain(74) === "LXXIV") ); console.log( romain(383) + ' / ' + (romain(383) === "CCCLXXXIII")); console.log( romain(1000) + ' / ' + (romain(1000) === "M")); console.log( romain(3888) + ' / ' + (romain(3888) === "MMMDCCCLXXXVIII")); // le plus long possible !
Je suis parti de cette base : ça serait cool de pouvoir "piocher" dans la chaine "IVXLCDM" comme ceci : "IVXLCDM"[0] === "I".
Et ça pourrait marcher, car imaginons cet algo :
- On recherche le romain de 5
- On divise par 5. Reste 0, Résultat : 1
- "IVXLCDM"[Résultat] === "V"
Pour 10 ?
- On recherche le romain de 10
- On divise par 5. Reste 0, Résultat : 2
- "IVXLCDM"[Résultat] === "X"
Pour 50 ?
- On recherche le romain de 50
- On divise par 5. Reste 0, Résultat : 10
- "IVXLCDM"[Résultat] === "c'était trop beau pour être vrai :)"
Mais y'a de l'espoir ! Creusons un peu plus :
J'ai remarqué que pour passer de I à V puis de V à X puis de X à L, etc, il faut respectivement multiplier par 5 puis par 2 puis par 5, etc
Il faudrait donc faire une boucle qui divise le nombre à chercher par 5, puis 2, puis 5, puis 2, etc
Parti de ce postulat, c'est "bouclable" en se servant de XOR alias ^.
Exemple :
Cool ! Imaginons que l'on recherche le romain de 1000, cela veut dire que diviser 1000, par 5, puis 2, puis 5, etc jusqu'à 0 se fait en 7 fois !Code:
1
2
3
4
5
6
7
8
9
10
11 for(a=5,i=0;i<5;i++,a^=7) console.log(a); /* Va afficher : 5 2 5 2 5 .... */
Que vaut "IVXLCDM"[6] ? :mrgreen:Code:
1
2
3
4
5
6
7
8
9
10
11
12
13 n=1000 for(b=0,c=5;n;b++,c^=7) console.log((n=n/c^0) + ' / indice : ' + b); /* Donne : 200 / 0 100 / 1 20 / 2 10 / 3 2 / 4 1 / 5 0 / 6 */
on a notre algo. Il suffit ensuite de jongler avec les divisions, les modulo pour récupérer les restes et construire ainsi notre chaine romaine.
Une version de dév commentée qui m'a aidé à construire le code :
ps : oui, ça m'a pris la soirée d'hier, et j'ai eu mal au crâne en me relisant aujourd'hui après manger :mrgreen:Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 function romain(n){ for(a='', // la chaine finale b=0, // IVXLCDM[b] c=5; // initialisation de c à 5 pour commencer à diviser n par 5 n; // tant que n n'est pas "falsy" (égal à 0 en l'occurrence). Il va subir une division par 5, puis 2, puis 5, etc ... b++, c^=7) { // c^=7 fait 2, puis, au prochain tour de boucle, c^=7 refera 5, puis encore 2 ensuite, etc console.log('d='+(n%c)+'/n='+(n/c^0)); for(d=n%c, // récupération du reste. Il ne peut jamais être > 4 ! n=n/c^0; // division par 5 ou 2 puis arrondi à l'inférieur => équivaut à n=Math.floor(n/c) ou encore n=~~(n/c) d--;) { // tant que le reste de la division n'est pas "falsy" (égal à 0 en l'occurrence) console.log('n='+n+'/m='+(n&-2)+'/a='+a+'/b='+b+'/c='+c+'/d='+d+'/x='+(1+(d>2?b+n-(n&-2)+1:b))); a='IVXLCDM'[d>2? // pour un reste de 4, soit les 4 ou 9. b+ // gestion des "cinquaines", dizaines, cinquantaines, etc n-(n&=-2) // ajoute 1 ou 0 et transforme n au nombre pair inférieur. n-(n&=-2) fait 0 si n pair et 1 si n impair. Car si n = 9 il faut taper dans la "cinquaine" suivante : ex IX. Tandis que si n = 4 on est dans la bonne cinquaine : ex. IV // si n est pair, (n&-2) === n. Par contre, si n est impair (n&-2) === n-1 +(d=1) // il ne faut plus qu'un tour derrière (exemple : IV si 4, IX si 9, XC si 90) :b]+a; // pour tout le reste, répétition de la lettre pendant d } } return a; }
:bravo: :ave: :scarymov:
Grand fou... J'avais tenté de faire la même chose avec la chaîne "IVXLCDM", mais je n'ai pas eu assez de temps pour arriver à une version aussi optimisée que la tienne. Moi j'utilisais deux variables, une pour l'unité et une pour la cinquaine. Mais basculer entre les deux via l'opérateur ^=, c'est du grand art. Bravo et merci d'avoir pris le temps de rédiger toute l'explication :ccool:
Impressionnant !! 8O8O
J'ai pas réussi à faire mieux que toi d'où le fait de ne pas avoir donné de réponse. J'avais aussi tenté de faire un truc avec la chaîne "IVXLCDM" mais mon approche était différente et trop longue en nombre de caractères.
Pour afficher par exemple 4, je me disais il faut d'abord afficher 1 "I" puis ajouter ce 1 à 4 ce qui donne 5 puis afficher 5 "V" ce qui donne au final "IV". J'avais une idée fixe sur cette méthode et j'ai pas trouvé comment la concrétiser. Je la garde cependant en tête, je m'y replongerai à l'occasion même si le résultat doit dépasser le tien en nombre de caractères.
Démonstration ESPOUSTOUFLANTE :hola::ave:
J'avais remarqué cette séquence 5-2-5-2... et prévue de l'exploiter avec un classique k=7-k, mais j'en suis resté là, de plus le c^=7 +1, euh! -1 caractère :lol:
Quoiqu'il en soit encore un grand coup de chapeau pour ce code et les explications qui vont avec :ccool:
Ces 98 caractères méritent de rester dans les annales du javascript.
Remercions également la période estivale sans qui tout ceci n'aurait pu être possible :mrgreen:
La période estivale n'est pas profitable à tous, y'en a qui bossent et qui ont droit à une canicule en prime :mrgreen:
Puisque le sujet des nombres romains vous a plu, et comme je doute qu'on puisse faire mieux que 98 caractères, je vous propose le sujet inverse:
Numéro 7: décoder les chiffres romains de I à MMMCMXCIX (3999)
Code:
1
2
3
4
5
6
7
8
9 function decodeRomain(s){ //votre code ici, retourne un entier de 1 à 3999 } console.log( decodeRomain("XII") + ' / ' + (decodeRomain("XII") === 12) ); console.log( decodeRomain("XLIX") + ' / ' + (decodeRomain("XLIX") === 49) ); console.log( decodeRomain("LXXIV") + ' / ' + (decodeRomain("LXXIV") === 74) ); console.log( decodeRomain("CCCLXXXIII") + ' / ' + (decodeRomain("CCCLXXXIII") === 383) ); console.log( decodeRomain("M") + ' / ' + (decodeRomain("M") === 1000) ); console.log( decodeRomain("MMMDCCCLXXXVIII") + ' / ' + (decodeRomain("MMMDCCCLXXXVIII") === 3888) );
Salut,
je propose ça :
106 caractèresCode:
1
2
3 function decodeRomain(str){ y=0for(s in a={M:1000,D:500,C:100,L:50,X:10,V:5,I:1}){y+=str.match(new RegExp(s,'g')).length*a[s]}return y }
EDIT : Oups, j'avais oublié le V:5
Version plus courte :
94 caractèresCode:
1
2
3 function decodeRomain(str){ y=0for(s in a={M:1000,D:500,C:100,L:50,X:10,V:5,I:1}){y+=(str.split(s).length-1)*a[s]}return y }
si on change le nom de la variable = -2 char :)Citation:
function decodeRomain(str){
y=0for(s in a={M:1000,D:500,C:100,L:50,X:10,V:5,I:1}){y+=(str.split(s).length-1)*a[s]}return y
}
Code:
1
2
3 function decodeRomain(n){ y=0for(s in a={M:1000,D:500,C:100,L:50,X:10,V:5,I:1}){y+=(n.split(s).length-1)*a[s]}return y }
On ne peut pas changer l'énoncé :mrgreen:
Par contre, tu peux enlever les {} et ajouter un ; pour que ça fonctionne :
Par contre, ça ne marche pas. Par exemple, test decodeRomain("IV") et decodeRomain("VI"), cela renverra 6. Alors qu'on attend 4 et 6. Idem pour le reste : XC, IX, etcCode:
1
2
3 function decodeRomain(str){ y=0;for(s in a={M:1000,D:500,C:100,L:50,X:10,V:5,I:1})y+=(str.split(s).length-1)*a[s];return y }
C'est là toute la problématique
Bon,
et bien je me suis vautré :sm:
Oui ce n'est pas aussi simple qu'un remplacement regexp, la règle de la numérotation romaine IV = V - I reste à indiquer.
Pour le nom de la variable vous pouvez la remplacer par s, c'est purement indicatif dans l'énoncé.
52 ! :ptdr:Code:
1
2
3 function decodeRomain(str){ open('http://fr.wikipedia.org/wiki/Nombres_romains') }
:sm:Bovino
Malin le bouc :ptdr: