web-dev-qa-db-fra.com

Code Golf: Quatre, c'est magique

Le puzzle

Un petit casse-tête que j'ai entendu quand j'étais au lycée est allé quelque chose comme ça ...

  • Le questionneur me demanderait de lui donner un numéro;
  • En entendant le numéro, l'interrogateur effectuerait une sorte de transformation à plusieurs reprises (par exemple, il pourrait dire dix c'est trois) jusqu'à arriver finalement au numéro 4 (à quel point il finirait avec quatre est magique).
  • N'importe quel nombre semble pouvoir être transformé en quatre.

Le but était d'essayer de comprendre la fonction de transformation et de pouvoir ensuite surveiller ce casse-tête de manière fiable.

La solution

La fonction de transformation à chaque étape était de

  • Prenez le numéro en question,
  • Compter le nombre de lettres dans sa représentation en mots anglais, en ignorant un trait d'union ou des espaces ou "et" (par exemple, "dix" a 3 lettres, "trente-quatre" a 10 lettres, "cent quarante-trois" a 20 lettres dedans).
  • Renvoie ce nombre de lettres.

Pour tous les nombres que je me suis toujours efforcé de tester, cela converge vers 4. Puisque "quatre" contient également quatre lettres, il y aurait une boucle infinie ici; au lieu de cela, il est simplement appelé la magie par convention, mettre fin à la séquence.

Le défi

Votre défi consiste à créer un morceau de code qui lira un numéro de l'utilisateur, puis à imprimer des lignes montrant la fonction de transformation appliquée de manière répétée jusqu'à ce que "quatre soit magique" soit atteint.

Plus précisément:

  1. Les solutions doivent être des programmes complets en eux-mêmes. Ce ne peuvent pas être simplement des fonctions qui prennent en compte un facteur - facteur dans l'entrée.
  2. L'entrée doit être lue à partir de l'entrée standard. (La tuyauterie à partir de "echo" ou à l'aide de la redirection d'entrée est bonne car elle va aussi de stdin)
  3. L'entrée doit être sous forme numérique.
  4. Pour chaque application de la fonction de transformation, une ligne doit être imprimée: a is b., où a et b sont des formes numériques des nombres de la transformation.
  5. Les arrêts complets (périodes) sont obligatoires!
  6. La dernière ligne devrait naturellement indiquer, 4 is magic..
  7. Le code doit produire une sortie correcte pour tous les nombres de 0 à 99.

Exemples:

> 4
4 is magic.

> 12
12 is 6.
6 is 3.
3 is 5.
5 is 4.
4 is magic.

> 42
42 is 8.
8 is 5.
5 is 4.
4 is magic.

> 0
0 is 4.
4 is magic.

> 99
99 is 10.
10 is 3.
3 is 5.
5 is 4.
4 is magic.

Le gagnant est le soumission la plus courte par nombre de caractères du code source qui est aussi correct.

PRIME

Vous pouvez également essayer d’écrire une version du code qui affiche les NOMS ANGLAIS pour les nombres avec chaque application de la fonction de transformation. L'entrée d'origine est toujours numérique, mais les lignes de sortie doivent avoir la forme Word du nombre.

(Double bonus pour dessiner des formes avec votre code)

(MODIFIER) Quelques clarifications:

  1. Je veux que la Parole apparaisse des deux côtés dans tous les cas applicables, par exemple. Nine is four. Four is magic.
  2. Je me fiche de la capitalisation, cependant. Et je me fiche de la façon dont vous séparez les jetons Word, même s’ils doivent être séparés: ninety-nine va bien, ninety nine va bien, ninetynine ne va pas.

Je considère cela comme une catégorie distincte pour la compétition de bonus en ce qui concerne le défi. Donc, si vous y allez, ne vous inquiétez pas de la longueur de votre code par rapport à la version numérique.

N'hésitez pas à soumettre une solution pour chaque version.

88
Platinum Azure

GolfScript - 101969392919094 86 octets

90 → 94: sortie fixe pour des multiples de 10.
94 → 86: code restructuré. Utilisation de la base 100 pour supprimer les caractères non imprimables.
86 → 85: Distribution plus courte vers la chaîne.

{n+~."+#,#6$DWOXB79Bd")base`1/10/~{~2${~1$+}%(;+~}%++=" is "\".
"1$4$4-}do;;;"magic."
57
Nabb

Perl, environ 147 caractères

Librement inspiré de la solution Platinum Azure:

               chop
              ($_.=
              <>);@
             u="433
            5443554
           366  887
          798   866
         555    766
        "=~     /\d
       /gx      ;#4
      sub       r{4
     -$_        ?$_
    <20         ?$u
   [$_          ]:(
  $'?           $u[
 $']            :0)
+$u[18+$&]:magic}print"
$_ is ",$_=r(),'.'while
                /\d
                /x;
                444
86
mob

Chars LISP 157 communs

Nouvelle version plus conforme, lisant maintenant l’entrée standard du formulaire et ignorant les espaces et les tirets:

(labels((g (x)(if(= x 4)(princ"4 is magic.")(let((n(length(remove-if(lambda(x)(find x" -"))(format nil"~r"x)))))(format t"~a is ~a.~%"x n)(g n)))))(g(read)))

Sous forme lisible par l'homme:

 (labels ((g (x)
           (if (= x 4)
            (princ "4 is magic.")
            (let ((n (length (remove-if (lambda(x) (find x " -"))
                                        (format nil "~r" x)))))
               (format t"~a is ~a.~%" x n)
               (g n)))))
    (g (read)))

Et quelques essais:

>24
24 is 10.
10 is 3.
3 is 5.
5 is 4.
4 is magic.

>23152436
23152436 is 64.
64 is 9.
9 is 4.
4 is magic.

Et la version bonus, à 165 caractères:

 (labels((g(x)(if(= x 4)(princ"four is magic.")(let*((f(format nil"~r"x))(n(length(remove-if(lambda(x)(find x" -"))f))))(format t"~a is ~r.~%"f n)(g n)))))(g(read)))

Donnant

>24
twenty-four is ten.
ten is three.
three is five.
five is four.
four is magic.

>234235
two hundred thirty-four thousand two hundred thirty-five is forty-eight.
forty-eight is ten.
ten is three.
three is five.
five is four.
four is magic.
30

Python 2.x, 144 150154166 caractères

Cela sépare le nombre en dizaines et en un et les résume. La propriété indésirable de l'opérateur pseudo-ternaire a and b or c que c est renvoyée si b est 0, elle est mal utilisée ici.

n=input()
x=0x4d2d0f47815890bd2
while n-4:p=n<20and x/10**n%10or 44378/4**(n/10-2)%4+x/10**(n%10)%10+4;print n,"is %d."%p;n=p
print"4 is magic."

La version naïve précédente (150 caractères). Il suffit d’encoder toutes les longueurs sous forme d’entier.

n=input()
while n-4:p=3+int('1yrof7i9b1lsi207bozyzg2m7sclycst0zsczde5oks6zt8pedmnup5omwfx56b29',36)/10**n%10;print n,"is %d."%p;n=p
print"4 is magic."
21
kennytm

C - avec des mots numériques

445431427421399386371359*356354348 347 caractères

C'est tout. Je ne pense pas pouvoir raccourcir ce délai.

Toutes les nouvelles lignes sont destinées à la lisibilité et peuvent être supprimées:

i;P(x){char*p=",one,two,three,four,five,six,sM,eight,nine,tL,Elm,twelve,NP,4P,
fifP,6P,7P,8O,9P,twLQ,NQ,forQ,fifQ,6Q,7Q,8y,9Q,en,evL,thir,eL,tO,ty, is ,.\n,
4RmagicS,zero,";while(x--)if(*++p-44&&!x++)*p>95|*p<48?putchar(*p),++i:P(*p-48);
}main(c){for(scanf("%d",&c);c+(i=-4);P(34),P(c=i),P(35))P(c?c>19?P(c/10+18),
(c%=10)&&putchar(45):0,c:37);P(36);}

Ci-dessous, il est quelque peu non approfondi, mais reste difficile à lire. Voir ci-dessous pour une version plus lisible.

i;
P(x){
    char*p=",one,two,three,four,five,six,sM,eight,nine,tL,Elm,twelve,NP,4P,fifP,6P,7P,8O,9P,twLQ,NQ,forQ,fifQ,6Q,7Q,8y,9Q,en,evL,thir,eL,tO,ty, is ,.\n,4RmagicS,zero,";
    while(x--)
        if(*++p-44&&!x++)
            *p>95|*p<48?putchar(*p),++i:P(*p-48);
}
main(c){
    for(scanf("%d",&c);c+(i=-4);P(34),P(c=i),P(35))
        P(c?
            c>19?
                P(c/10+18),
                (c%=10)&&
                    putchar(45)
            :0,
            c
        :37);
    P(36);
}

Développé et commenté:

int count; /* type int is assumed in the minified version */

void print(int index){ /* the minified version assumes a return type of int, but it's ignored */
    /* see explanation of this string after code */
    char *Word =
        /* 1 - 9 */
        ",one,two,three,four,five,six,sM,eight,nine,"
        /* 10 - 19 */
        "tL,Elm,twelve,NP,4P,fifP,6P,7P,8O,9P,"
        /* 20 - 90, by tens */
        "twLQ,NQ,forQ,fifQ,6Q,7Q,8y,9Q,"
        /* lookup table */
        "en,evL,thir,eL,tO,ty, is ,.\n,4RmagicS,zero,";

    while(index >= 0){
        if(*Word == ',')
            index--;
        else if(index == 0) /* we found the right Word */
            if(*Word >= '0' && *Word < 'a') /* a compression marker */
                print(*Word - '0'/*convert to a number*/);
            else{
                putchar(*Word); /* write the letter to the output */
                ++count;
            }
        ++Word;
    }
}
int main(int argc, char **argv){ /* see note about this after code */
    scanf("%d", &argc); /* parse user input to an integer */

    while(argc != 4){
        count = 0;
        if(argc == 0)
            print(37/*index of "zero"*/);
        else{
            if(argc > 19){
                print(argc / 10/*high digit*/ + 20/*offset of "twenty"*/ - 2/*20 / 10*/);
                argc %= 10; /* get low digit */

                if(argc != 0) /* we need a hyphen before the low digit */
                    putchar('-');
            }
            print(argc/* if 0, then nothing is printed or counted */);
        }
        argc = count;
        print(34/*" is "*/);
        print(argc); /* print count as Word */
        print(35/*".\n"*/);
    }
    print(36/*"four is magic.\n"*/);
}

A propos de la chaîne encodée au début

Les noms des nombres sont compressés en utilisant un schéma très simple. Les sous-chaînes fréquemment utilisées sont remplacées par des index à un caractère dans le tableau de noms. Une "table de correspondance" d'entrées de nom supplémentaires est ajoutée à la fin pour les sous-chaînes non utilisées dans leur intégralité dans le premier ensemble. Les recherches sont récursives: les entrées peuvent faire référence à d'autres entrées.

Par exemple, le nom compressé pour 11 est Elm. La fonction print() génère les caractères e et l ('L' minuscule, pas le nombre '1'), mais elle trouve la M, de sorte qu'elle s'appelle avec l'index de la 29e entrée (ASCII 'M' - ASCII '0') dans la table de recherche. Cette chaîne est evL. Elle génère donc e et v, puis s’appelle à nouveau avec l’index de la 28e entrée de la table de recherche, qui est en, et est reproduit textuellement. Ceci est utile car en est également utilisé dans eL pour een (utilisé après eight dans eighteen), qui est utilisé dans tO pour teen (utilisé pour tout autre nom -teen).

Ce schéma entraîne une compression assez importante des noms de nombres, tout en ne nécessitant qu'une petite quantité de code pour la décompression.

Les virgules au début et à la fin de la chaîne expliquent de manière simpliste la présence de sous-chaînes dans cette chaîne. Ajouter deux caractères ici enregistre plus de caractères plus tard.

À propos de l'abus de main()

argv est ignoré (et donc non déclaré dans la version compressée), la valeur de argc est ignorée, mais la mémoire est réutilisée pour contenir le nombre actuel. Cela me évite de devoir déclarer une variable supplémentaire.

A propos du manque de #include

Certains vont se plaindre d'omettre #include <stdio.h>, c'est tricher. Ce n'est pas du tout. Le programme donné est un programme C complètement légal qui compilera correctement tous les compilateurs C que je connaisse (bien qu’avec des avertissements). En l'absence de prototypes pour les fonctions stdio, le compilateur supposera qu'il s'agit de fonctions cdecl renvoyant int et fera confiance à votre connaissance des arguments à transmettre. De toute façon, les valeurs de retour sont ignorées dans ce programme et il s’agit de fonctions cdecl (convention d’appel "C"), et nous savons en effet quels arguments doivent être passés.

Sortie

La sortie est comme prévu:

 0 
 Zéro est quatre. 
 Quatre est magique. 
 1 
 Un est trois. 
 Trois est cinq. 
 Cinq est quatre. 
 Quatre est magique. 
 4 
 Quatre est magique. 
 20 
 Vingt, c'est six. 
 Six, trois. 
 Trois, cinq. 
 Cinq, quatre. 
 Quatre, c'est magique . 
 21 
 Vingt et un ans c'est neuf. 
 Neuf c'est quatre. 
 Quatre c'est magique. 

* La version précédente manquait le repère sur deux parties de la spécification: elle ne gérait pas le zéro et prenait l'entrée sur la ligne de commande au lieu de stdin. La gestion des zéros ajoutés aux caractères, mais l'utilisation de stdin au lieu d'arguments de ligne de commande, ainsi que de quelques optimzations, a enregistré le même nombre de caractères, ce qui a entraîné un lavage.

Les exigences ont été modifiées pour indiquer clairement que le nombre Word doit être imprimé des deux côtés de "est". Cette nouvelle version répond à cette exigence et implémente plusieurs optimisations supplémentaires afin de prendre en compte la taille supplémentaire nécessaire.

20
P Daddy

J, 107 112 personnages

'4 is magic.',~}:('.',~":@{.,' is ',":@{:)"1]2&{.\.
(]{&(#.100 4$,#:3 u:ucp'䌵䐵吶梇禈榛ꪛ멩鮪鮺墊馊꥘誙誩墊馊ꥺ겻곋榛ꪛ멩鮪鮺'))^:a:

(Newline pour la lisibilité seulement)

Utilisation et sortie:

    '4 is magic.',~}:('.',~":@{.,' is ',":@{:)"1]2&{.\.(]{&(#.100 4$,#:3 u:ucp'䌵䐵吶梇禈榛ꪛ멩鮪鮺墊馊꥘誙誩墊馊ꥺ겻곋榛ꪛ멩鮪鮺'))^:a:12
12 is 6.    
6 is 3.     
3 is 5.     
5 is 4.     
4 is magic. 
10
David

T-SQL, 413 451499 caractères

CREATE FUNCTION d(@N int) RETURNS int AS BEGIN
Declare @l char(50), @s char(50)
Select @l='0066555766',@s='03354435543668877987'
if @N<20 return 0+substring(@s,@N+1,1) return 0+substring(@l,(@N/10)+1,1) + 0+(substring(@s,@N%10+1,1))END
GO
CREATE proc M(@x int) as BEGIN
WITH r(p,n)AS(SELECT p=@x,n=dbo.d(@x) UNION ALL SELECT p=n,n=dbo.d(n) FROM r where n<>4)Select p,'is',n,'.' from r print '4 is magic.'END

(Non pas que je suggère sérieusement que vous fassiez cela ... vraiment je voulais juste écrire un CTE)

Utiliser:

M 95

Résultats

p                n
----------- ---- -----------
95          is   10.
10          is   3.
3           is   5.
5           is   4.
4 is magic.
10
Leon Bambrick

Windows PowerShell: 152 153184 octets

basé sur la solution précédente, avec plus d'influence d'autres solutions

$o="03354435543668877988"
for($input|sv b;($a=$b)-4){if(!($b=$o[$a])){$b=$o[$a%10]-48+"66555766"[($a-$a%10)/10-2]}$b-=48-4*!$a
"$a is $b."}'4 is magic.'
9
Joey

Java (avec passe-partout), 308290286282 280 caractères

class A{public static void main(String[]a){int i=4,j=0;for(;;)System.out.printf("%d is %s.%n",i=i==4?new Java.util.Scanner(System.in).nextInt():j,i!=4?j="43354435543668877988699;::9;;:699;::9;;:588:998::9588:998::9588:998::97::<;;:<<;699;::9;;:699;::9;;:".charAt(i)-48:"magic");}}

Je suis sûr que Groovy s'en débarrasserait en grande partie.

Explication et mise en forme (tous les commentaires, les nouvelles lignes et les espaces de début et de fin supprimés):

Assez simple, mais

//boilerplate
class A{
   public static void main(String[]a){
      //i is current/left number, j right/next number.  i=4 signals to start
      //by reading input
      int i=4,j=0;
      for(;;)
         //print in the form "<left> is <right>."
         System.out.printf(
            "%d is %s.%n",
            i=i==4?
               //<left>: if i is 4 <left> will be a new starting number
               new Java.util.Scanner(System.in).nextInt():
               //otherwise it's the next val
               j,
            i!=4?
               //use string to map number to its length (:;< come after 9 in ASCII)
               //48 is value of '0'.  store in j for next iteration
               j="43354435543668877988699;::9;;:699;::9;;:588:998::9588:998::9588:998::97::<;;:<<;699;::9;;:699;::9;;:".charAt(i)-48:
               //i==4 is special case for right; print "magic"
               "magic");
   }
}

Edit: ne plus utiliser hex, c'est moins de frappes

9
Mark Peters

C, 158 caractères

main(n,c){char*d="03354435543668877988";for(scanf("%d",&n);n-4;n=c)printf("%d is %d.\n",n,c=n?n<19?d[n]-48:d[n%10]-"_,**+++)**"[n/10]:4);puts("4 is magic.");}

(à l'origine basé sur le code Python de Vlad, emprunté une astuce à la solution C++ de Tom Sirgedas pour extraire quelques caractères supplémentaires)

version étendue:

main(n, c) {
    char *d = "03354435543668877988";
    for (scanf("%d",&n); n-4; n = c)
        printf("%d is %d.\n", n, c = n ? n<19 ? d[n]-48 : d[n%10] - "_,**+++)**"[n/10]  : 4);
    puts("4 is magic.");
}
8
Ferruccio

C #: 210 caractères.

Squished:

using C=System.Console;class B{static void Main(){int
x=0,y=int.Parse(C.ReadLine());while(x!=4)C.Write((x=y)+" is {0}.\n",x==4?"magic":""+(y=x==0?4:"03354435543668877988"[x<20?x:x%10]+"0066555766"[x/10]-96));}}

Expanded:

using C=System.Console;
class B
{
    static void Main()
    {
        int x=0,y=int.Parse(C.ReadLine());
        while(x!=4)
            C.Write((x=y)+" is {0}.\n",
                x==4?
                     "magic":
                     ""+(y= x==0?
                                4:
                                "03354435543668877988"[x<20?x:x%10]+
                                "0066555766"[x/10]-96)
                   );
    }
}

Astuces cette approche utilise:

  • Créez une table de recherche pour les longueurs de nom de numéro basées sur les chiffres figurant dans le numéro.
  • Utilisez la recherche de tableau de caractères sur une chaîne et l'arithmétique de caractères au lieu d'un tableau numérique.
  • Utilisez l'alias de nom de classe pour raccourcir Console. à C.
  • Utilisez l'opérateur conditionnel (ternaire) (?:) au lieu de if/else.
  • Utilisez le \n avec le code d'échappement Write au lieu de WriteLine
  • Utilisez le fait que C # a un ordre d'évaluation défini pour autoriser les affectations dans l'appel de fonction Write
  • Utilisez les expressions d'affectation pour éliminer les instructions supplémentaires, et donc les accolades supplémentaires
6
LBushkin

Perl: 148 caractères

(Perl: 233181212206200199198185179149 148 caractères)

  • Les exceptions déplacées ont été hachées dans un tableau d'unités. Cela m'a permis de couper beaucoup de caractères :-)
  • mobrule a signalé un méchant virus. La solution rapide ajoute 31 caractères, aïe!
  • Refactored pour zéro cas particulier, le golf doux fait aussi bien.
  • Accès direct à la liste à usage unique plutôt que de stocker dans un tableau? Putain, oui!
  • BEAUCOUP DE REFACTORING pour UN SEUL personnage sanglant. C’est vraiment la vie d’un golfeur. :-(
  • Oops, correction facile des espaces blancs. 198 maintenant.
  • Refactorisé du code redondant.
  • Le dernier mot-clé dans r n'est pas nécessaire, il en a été réduit davantage.
  • Refactoring massif selon les commentaires; Malheureusement, je ne pouvais que l'obtenir à 149 parce que je devais corriger un bogue présent dans mon code précédent et dans les versions des commentateurs.
  • Essayer un mot simple "magique".

Commençons par une tentative modeste en Perl.

@u=split'','4335443554366887798866555766';$_=<>;chop;print"$_ is ".($_=$_==4?0:$_<20?$u[$_]:($u[$_/10+18]+($_%10&&$u[$_%10]))or magic).".
"while$_

Des trucs:

Trop!

6
Platinum Azure

Python, 129 133137148 caractères

En guise d’échauffement, voici ma première version (améliore quelques caractères par rapport au précédent meilleur Python).

PS Après quelques expurgations, le nombre de caractères est plus court:

n=input()
while n-4:p=(922148248>>n/10*3&7)+(632179416>>n%10*3&7)+(737280>>n&1)+4*(n<1);print n,'is %d.'%p;n=p
print'4 is magic.'
6
Nas Banov

JavaScript 1.8 (SpiderMonkey) - 153 Chars

l='4335443554366887798866555766'.split('')
for(b=readline();(a=+b)-4;print(a,'is '+b+'.'))b=a<20?l[a]:+l[18+a/10|0]+(a%10&&+l[a%10])
print('4 is magic.')

Utilisation: echo 42 | js golf.js

Sortie:

42 is 8.
8 is 5.
5 is 4.
4 is magic.

Avec bonus - 364 caractères

l='zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty thirty fourty fifty sixty seventy eighty ninety'.split(' ')
z=function(a)a<20?l[a]:l[18+a/10|0]+(a%10?' '+l[a%10]:'')
for(b=+readline();(a=b)-4;print(z(a),'is '+z(b)+'.'))b=z(a).replace(' ','').length
print('four is magic.')

Sortie:

quatre-vingt-dix-neuf, c'est dix. 
 dix c'est trois. 
 trois c'est cinq. 
 cinq c'est quatre.
5
gnarf

Haskell, 224 270 personnages

o="43354435543668877988"
x!i=read[x!!i]
n x|x<20=o!x|0<1="0066555766"!div x 10+o!mod x 10
f x=zipWith(\a b->a++" is "++b++".")l(tail l)where l=map show(takeWhile(/=4)$iterate n x)++["4","magic"]
main=readLn>>=mapM putStrLn.f

Et peu plus lisible -

ones = [4,3,3,5,4,4,3,5,5,4,3,6,6,8,8,7,7,9,8,8]
tens = [0,0,6,6,5,5,5,7,6,6]

n x = if x < 20 then ones !! x else (tens !! div x 10) + (ones !! mod x 10)

f x = zipWith (\a b -> a ++ " is " ++ b ++ ".") l (tail l)
    where l = map show (takeWhile (/=4) (iterate n x)) ++ ["4", "magic"]

main = readLn >>= mapM putStrLn . f
4
Martin Jonáš

Version C++ Stdio, minifiée: 196 caractères

#include <cstdio>
#define P;printf(
char*o="43354435543668877988";main(int p){scanf("%d",&p)P"%d",p);while(p!=4){p=p<20?o[p]-48:"0366555966"[p/10]-96+o[p%10]P" is %d.\n%d",p,p);}P" is magic.\n");}

Version C++ Iostreams, minifiée: 195 caractères

#include <iostream>
#define O;std::cout<<
char*o="43354435543668877988";main(int p){std::cin>>p;O p;while(p!=4){p=p<20?o[p]-48:"0366555966"[p/10]-96+o[p%10]O" is "<<p<<".\n"<<p;}O" is magic.\n";}

Original, non exploité: 344 caractères

#include <cstdio>

int ones[] = { 4, 3, 3, 5, 4, 4, 3, 5, 5, 4, 3, 6, 6, 8, 8, 7, 7, 9, 8, 8 };
int tens[] = { 0, 3, 6, 6, 5, 5, 5, 9, 6, 6 };

int n(int n) {
    return n<20 ? ones[n] : tens[n/10] + ones[n%10];
}

int main(int p) {
    scanf("%d", &p);
    while(p!=4) {
        int q = n(p);
        printf("%i is %i\n", p, q);
        p = q;
    }
    printf("%i is magic\n", p);
}
4
Karl von Moor

Delphi: 329 caractères

Version à une seule ligne:

program P;{$APPTYPE CONSOLE}uses SysUtils;const S=65;A='EDDFEEDFFEDGGIIHHJII';B='DGGFFFJGG';function Z(X:Byte):Byte;begin if X<20 then Z:=Ord(A[X+1])-S else Z:=(Ord(B[X DIV 10])-S)+Z(X MOD 10)end;var X,Y:Byte;begin Write('> ');ReadLn(X);repeat Y:=Z(X);WriteLn(Format('%d is %d.',[X,Y]));X:=Y;until X=4;WriteLn('4 is magic.');end.

Formated:

program P;

{$APPTYPE CONSOLE}

uses
  SysUtils;

const
  S = 65;
  A = 'EDDFEEDFFEDGGIIHHJII';
  B = 'DGGFFFJGG';

function Z(X:Byte):Byte;
begin
  if X<20
  then Z := Ord(A[X+1])-S
  else Z := (Ord(B[X DIV 10])-S) + Z(X MOD 10);
end;

var
  X,Y: Byte;

begin
  Write('> ');
  ReadLn(X);

  repeat
    Y:=Z(X);
    WriteLn(Format('%d is %d.' , [X,Y]));
    X:=Y;
  until X=4;

  WriteLn('4 is magic.');
end.

Probablement de la place pour un peu plus de compression ... :-P

3
Jørn E. Angeltveit

Lua, 176 personnages

o={[0]=4,3,3,5,4,4,3,5,5,4,3,6,6,8,8,7,7,9,8,8}t={3,6,6,5,5,5,7,6,6}n=0+io.read()while n~=4 do a=o[n]or o[n%10]+t[(n-n%10)/10]print(n.." is "..a..".")n=a end print"4 is magic."

ou

  o={[0]=4,3,3,5,4,4
  ,3,5,5,4,3,6,6,8,8
  ,7,7,9,8,8}t={3,6,
   6,5,5,5,7,6,6}n=
   0+io.read()while
   n ~= 4 do a= o[n
   ]or o[n%10]+t[(n
   -n%10)/10]print(
n.." is "..a.."." )n=a
end print"4 is magic."
3
gwell

C # 314286283274289273 252 caractères.

Écrasé:

252 

Ordinaire:

using C = System.Console;
class P
{
    static void Main()
    {
        var x = "4335443554366877798866555766";
        int m, o, v = int.Parse(C.ReadLine());
        do {
            C.Write("{0} is {1}.\n", o = v, v == 4 ? (object)"magic" : v = v < 20 ? x[v] - 48 : x[17 + v / 10] - 96 + ((m = v % 10) > 0 ? x[m] : 48));
        } while (o != 4);
        C.ReadLine();
    }
}

Edit Dykam: A fait quelques insertions et modifications soigneuses:

  • Changé le l.ToString () dans un transtypage en object de la string"magic".
  • Création d'une variable temporaire o afin de pouvoir déplacer la break en dehors de la boucle for, c'est-à-dire la création d'un do-while.
  • L'affectation o en ligne, ainsi que l'affectation v, continuent en insérant le calcul de l dans les arguments de la fonction, ce qui supprime le besoin de l. Également en ligne l'affectation de m.
  • Suppression d'un espace dans int[] x, int[]x est également légitime.
  • J'ai essayé de transformer le tableau en une transformation de chaîne, mais le using System.Linq était trop pour en faire une amélioration.

Edit 2 Dykam Changé le tableau int en un tableau/chaîne de caractères, ajout de l'arithmique appropriée pour corriger cela.

3
mdm20

C - sans chiffres

180175*172 167 caractères

Toutes les nouvelles lignes sont destinées à la lisibilité et peuvent être supprimées:

i;V(x){return"\3#,#6$:WOXB79B"[x/2]/(x%2?1:10)%10;}main(c){for(scanf("%d",&c);
c-4;)i=c,printf("%d is %d.\n",i,c=c?c>19?V(c/10+19)+V(c%10):V(c):4);puts(
"4 is magic.");}

Légèrement non terminé:

i;
V(x){return"\3#,#6$:WOXB79B"[x/2]/(x%2?1:10)%10;}
main(c){
    for(scanf("%d",&c);c-4;)
        i=c,
        printf("%d is %d.\n",i,c=c?c>19?V(c/10+19)+V(c%10):V(c):4);
    puts("4 is magic.");
}

* La version précédente manquait le repère sur deux parties de la spécification: elle ne gérait pas le zéro et prenait l'entrée sur la ligne de commande au lieu de stdin. La gestion de zéro caractère ajouté, mais l'utilisation de stdin au lieu d'arguments de ligne de commande permettait encore plus d'économiser, ce qui permettait de réaliser des économies nettes.

3
P Daddy

Perl, 123 122 caractères

Je viens de me rendre compte qu'il n'y a pas d'exigence de sortie sur STDOUT, donc affichez plutôt sur STDERR et supprimez un autre caractère.

@u='0335443554366887798866555766'=~/./g;$_+=<>;warn"$_ is ",$_=$_-4?$_<20?$u[$_]||4:$u[chop]+$u[$_+18]:magic,".\n"until/g/

Et une version qui retourne des nombres épelés:

279278276 280 caractères

@p=(Thir,Four,Fif,Six,Seven,Eigh,Nine);@n=("",One,Two,Three,Four,Five,@p[3..6],Ten,Eleven,Twelve,map$_.teen,@p);s/u//for@m=map$_.ty,Twen,@p;$n[8].=t;sub n{$n=shift;$n?$n<20?$n[$n]:"$m[$n/10-2] $n[$n%10]":Zero}$p+=<>;warnt$m=n($p)," is ",$_=$p-4?n$p=()=$m=~/\w/g:magic,".\n"until/c/

Bien que cela réponde aux spécifications, ce n'est pas à 100% bien formaté. Il renvoie un espace supplémentaire après les nombres se terminant par zéro. La spécification dit:

"Je me fiche de la façon dont vous séparez les jetons Word, même s'ils doivent être séparés"

C'est un peu malsain cependant. Une version plus correcte sur

282281279 283 caractères

@p=(Thir,Four,Fif,Six,Seven,Eigh,Nine);@n=("\x8",One,Two,Three,Four,Five,@p[3..6],Ten,Eleven,Twelve,map$_.teen,@p);s/u//for@m=map$_.ty,Twen,@p;$n[8].=t;sub n{$n=shift;$n?$n<20?$n[$n]:"$m[$n/10-2]-$n[$n%10]":Zero}$p+=<>;warn$m=n($p)," is ",$_=$p-4?n$p=()=$m=~/\w/g:magic,".\n"until/c/
2
user397369

Ruby, 164 personnages

n=gets.to_i;s="03354435543668877987";if n==0;puts"0 is 4.";else;puts"#{n} is #{n=(n<20)?s[n]-48:"0066555766"[n/10]-48+s[n%10]-48}." until n==4;end;puts"4 is magic."

décodé:

n = gets.to_i
s = "03354435543668877987"
if n == 0
  puts "0 is 4."
else
  puts "#{n} is #{n = (n < 20) ? s[n] - 48 : "0066555766"[n / 10] - 48 + s[n % 10] - 48}." until n == 4
end

puts "4 is magic."
1
Jon Smock

Lua 185190 199

ajout de points, ajout de io.read, remove () lors de la dernière impression

 n=io.read();while(n~=4)do m=('43354435543668877988699;::9;;:699;::9;;:588:998::9588:998::9588:998::97::<;;:<<;699;::9;;:699;::9;;:'):sub(n+1):byte()-48;print(n,' is ',m,'.')n=m;end print'4 is magic.'

avec des sauts de ligne

 n=io.read()
 while (n~=4) do
    m=('43354435543668877988699;::9;;:699;::9;;:588:998::9588:998::9588:998::97::<;;:<<;699;::9;;:699;::9;;:'):sub(n+1):byte()-48;
    print(n,' is ',m,'.')
    n=m;
 end 
 print'4 is magic.'
1
Nick Van Brunt

Python:

#!/usr/bin/env python

# Number of letters in each part, we don't count spaces
Decades = ( 0, 3, 6, 6, 6, 5, 5, 7, 6, 6, 0 )
Smalls  = ( 0, 3, 3, 5, 4, 4, 3, 5, 5, 4 )
Teens  =  ( 6, 6, 8, 8, 7, 7, 9, 8, 8 )

def Count(n):
    if n > 10 and n < 20: return Teens[n-11]
    return   Smalls[n % 10 ] + Decades [ n / 10 ]

N = input()

while N-4:
    Cnt = Count(N)
    print "%d is %d" % ( N, Cnt)
    N = Cnt

print "4 is magic"
1
Vlad

C++, 171 caractères (#include omis)

void main(){char x,y,*a="03354435543668877988";scanf("%d",&x);for(;x-4;x=y)y=x?x<19?a[x]-48:"_466555766"[x/10]+a[x%10]-96:4,printf("%d is %d.\n",x,y);puts("4 is magic.");}
1
Tom Sirgedas

Ruby, 141 caractères:

n=gets.to_i;m="4335443554366887798866555766";loop{s=n;n=n>20?m[18+n/10]+m[n%10]-96: m[n]-48;puts"#{s} is #{n==s ? 'magic': n}.";n==s &&break}
0
Krzysztof

Code PhP

function get_num_name($num){  
    switch($num){  
        case 1:return 'one';  
    case 2:return 'two';  
    case 3:return 'three';  
    case 4:return 'four';  
    case 5:return 'five';  
    case 6:return 'six';  
    case 7:return 'seven';  
    case 8:return 'eight';  
    case 9:return 'nine';  
    }  
}  

function num_to_words($number, $real_name, $decimal_digit, $decimal_name){  
    $res = '';  
    $real = 0;  
    $decimal = 0;  

    if($number == 0)  
        return 'Zero'.(($real_name == '')?'':' '.$real_name);  
    if($number >= 0){  
        $real = floor($number);  
        $decimal = number_format($number - $real, $decimal_digit, '.', ',');  
    }else{  
        $real = ceil($number) * (-1);  
        $number = abs($number);  
        $decimal = number_format($number - $real, $decimal_digit, '.', ',');  
    }  
    $decimal = substr($decimal, strpos($decimal, '.') +1);  

    $unit_name[1] = 'thousand';  
    $unit_name[2] = 'million';  
    $unit_name[3] = 'billion';  
    $unit_name[4] = 'trillion';  

    $packet = array();    

    $number = strrev($real);  
    $packet = str_split($number,3);  

    for($i=0;$i<count($packet);$i++){  
        $tmp = strrev($packet[$i]);  
        $unit = $unit_name[$i];  
        if((int)$tmp == 0)  
            continue;  
        $tmp_res = '';  
        if(strlen($tmp) >= 2){  
            $tmp_proc = substr($tmp,-2);  
            switch($tmp_proc){  
                case '10':  
                    $tmp_res = 'ten';  
                    break;  
                case '11':  
                    $tmp_res = 'eleven';  
                    break;  
                case '12':  
                    $tmp_res = 'twelve';  
                    break;  
                case '13':  
                    $tmp_res = 'thirteen';  
                    break;  
                case '15':  
                    $tmp_res = 'fifteen';  
                    break;  
                case '20':  
                    $tmp_res = 'twenty';  
                    break;  
                case '30':  
                    $tmp_res = 'thirty';  
                    break;  
                case '40':  
                    $tmp_res = 'forty';  
                    break;  
                case '50':  
                    $tmp_res = 'fifty';  
                    break;  
                case '70':  
                    $tmp_res = 'seventy';  
                    break;  
                case '80':  
                    $tmp_res = 'eighty';  
                    break;  
                default:  
                    $tmp_begin = substr($tmp_proc,0,1);  
                    $tmp_end = substr($tmp_proc,1,1);  

                    if($tmp_begin == '1')  
                        $tmp_res = get_num_name($tmp_end).'teen';  
                    elseif($tmp_begin == '0')  
                        $tmp_res = get_num_name($tmp_end);  
                    elseif($tmp_end == '0')  
                        $tmp_res = get_num_name($tmp_begin).'ty';  
                    else{  
                        if($tmp_begin == '2')  
                            $tmp_res = 'twenty';  
                        elseif($tmp_begin == '3')  
                            $tmp_res = 'thirty';  
                        elseif($tmp_begin == '4')  
                            $tmp_res = 'forty';  
                        elseif($tmp_begin == '5')  
                            $tmp_res = 'fifty';  
                        elseif($tmp_begin == '6')  
                            $tmp_res = 'sixty';  
                        elseif($tmp_begin == '7')  
                            $tmp_res = 'seventy';  
                        elseif($tmp_begin == '8')  
                            $tmp_res = 'eighty';  
                        elseif($tmp_begin == '9')  
                            $tmp_res = 'ninety';  

                        $tmp_res = $tmp_res.' '.get_num_name($tmp_end);  
                    }  
                    break;  
            }  

            if(strlen($tmp) == 3){  
                $tmp_begin = substr($tmp,0,1);  

                $space = '';  
                if(substr($tmp_res,0,1) != ' ' && $tmp_res != '')  
                    $space = ' ';  

                if($tmp_begin != 0){  
                    if($tmp_begin != '0'){  
                        if($tmp_res != '')  
                            $tmp_res = 'and'.$space.$tmp_res;  
                    }  
                    $tmp_res = get_num_name($tmp_begin).' hundred'.$space.$tmp_res;  
                }  
            }  
        }else  
            $tmp_res = get_num_name($tmp);  
        $space = '';  
        if(substr($res,0,1) != ' ' && $res != '')  
            $space = ' ';  
        $res = $tmp_res.' '.$unit.$space.$res;  
    }  

    $space = '';  
    if(substr($res,-1) != ' ' && $res != '')  
        $space = ' ';  

    if($res)  
        $res .= $space.$real_name.(($real > 1 && $real_name != '')?'s':'');  

    if($decimal > 0)  
        $res .= ' '.num_to_words($decimal, '', 0, '').' '.$decimal_name.(($decimal > 1 && $decimal_name != '')?'s':'');  
    return ucfirst($res);  
}  

//////////// tests //////////////////

 $str2num = 12;
    while($str2num!=4){
        $str = num_to_words($str2num, '', 0, '');  
        $str2num = strlen($str)-1;
        echo $str . '=' . $str2num .'<br/>';
        if ($str2num == 4)
            echo 'four is magic';
    }

////// Résultats /////////

Twelve =6
Six =3
Three =5
Five =4
four is magic
0
Developer

Perl - 130 caractères


5.12.1 (130 caractères) 121123132136140

#        1         2         3         4         5         6         7         8         9        100        11        12        13       14    
#23456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123

@u='4335443554366887798866555766'=~/./g;$_=pop;say"$_ is ",$_=$_-4?$_<20?$u[$_]:$u[$_/10+18]+(($_%=10)&&$u[$_]):magic,"."until/\D/


5.10.1 (134 caractères) 125127136140144

#        1         2         3         4         5         6         7         8         9        100        11        12        13       14    
#23456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234

@u='4335443554366887798866555766'=~/./g;$_=pop;print"$_ is ",$_=$_-4?$_<20?$u[$_]:$u[$_/10+18]+(($_%=10)&&$u[$_]):magic,".\n"until/\D/


Historique des changements:

20100714:2223 - changement annulé à l'attention de mobrule , mais ($_%10&&$u[$_%10])(($_%=10)&&$u[$_]), qui est le même nombre de caractères, mais je l'ai fait au cas où quelqu'un verrait un moyen de l'améliorer

20100714:0041 - split//,'...''...'=~/./g
20100714:0025 - ($_%10&&$u[$_%10])$u[$_%10]
20100713:2340 - while$_until/\D/ + suppression des parenthèses inutiles
20100713:xxxx - $=<>;chop;$_=pop; - gracieuseté de mobrule


Remarque: J'étais fatigué d'améliorer les réponses des autres dans les commentaires. Je suis donc trop gourmand et je peux ajouter mes modifications ici :) C'est une séparation de Platinum Azure 's answer - crédit partiel de Hobbs , mobrule , et Platinum Azure .

0
vol7ron

Perl sans vergogne avec mots numériques (329 caractères)

Adapté assez directement du code C de P Daddy, avec quelques ajustements à p() pour lui faire faire la même chose en utilisant des primitives Perl au lieu de C, et une boucle principale principalement réécrite. Voir le sien pour une explication. Les nouvelles lignes sont toutes facultatives.

@t=(qw(zero one two three four five six sM eight nine
tL Elm twelve NP 4P fifP 6P 7P 8O 9P twLQ NQ forQ fifQ
6Q 7Q 8y 9Q en evL thir eL tO ty 4SmagicT)," is ",".\n");
sub p{local$_=$t[pop];1while s/[0-Z]/$t[-48+ord$&]/e;
print;length}$_=<>;chop;while($_-4){
$_=($_>19?(p($_/10+18),$_&&print("-"),$_%=10)[0]:0)+p$_;
p 35;p$_;p 36}p 34

Note latérale: il est dommage que Perl print ne retourne que vrai/faux; si cela retournait, ça me ferait gagner 7 coups.

0
hobbs