代码高尔夫:四是魔术

难题

我在高中时听到的一个难题就是这样的

  • 提问者会要求我给他一个数字;
  • 听到这个号码后,提问者会反复进行某种转换(例如,他可能会说10是3 ),直到最终到达数字4(在这一点上,他将以4结束是魔术 )。
  • 无论如何,任何数字似乎最终都可以变成四个。

目标是试图找出转换function,然后能够可靠地自我监督这个难题。

解决scheme

任何一步的转换function都是

  • 以问题的数字,
  • 计算英文单词表示中的字母数量,忽略连字符或空格或“和”(例如,“十”中有三个字母,“三十四”中有十个字母,“一百四十三”有20个字母在里面)。
  • 返回那个字母的数字。

对于所有我曾经考虑过的数字,这个收敛到4.因为“四”中也有四个字母,所以在这里会有一个无限循环。 相反,它仅仅被称为魔术 ,以结束序列。

挑战

您的挑战是创build一段代码,从用户那里读取一个数字,然后打印显示重复应用转换函数的行,直到达到“四是魔术”。

特别:

  1. 解决scheme必须是完整的程序本身。 它们不能仅仅是在input中涉及数量因素的function。
  2. input必须从标准input读取。 (pipe道从“回声”或使用inputredirect是好的,因为这也是从标准input)
  3. input应该是数字forms。
  4. 对于转换函数的每个应用程序,都应该打印一行: a is b. ,其中a和b是转换中数字的数字forms。
  5. 全站(期间)是必需的!
  6. 最后一行应该自然地说, 4 is magic.
  7. 代码应该为0到99之间的所有数字生成正确的输出。

例子:

 > 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. 

获胜者是源代码字符数最短的提交也是正确的

奖金

您也可以尝试编写一个代码版本,在转换函数的每个应用程序中输出数字的英文名称。 原始input仍然是数字,但输出行应具有数字的单词forms。

(使用您的代码绘制形状的双倍奖金)

(编辑)一些澄清:

  1. 我希望这个词在所有适用的情况下都出现在双方,例如Nine is four. Four is magic. Nine is four. Four is magic.
  2. 不过,我不在乎大写字母。 我不在乎你怎么区分这个词,尽pipe它们应该分开: ninety-nine好, ninety nine好, ninetynine不好。

我正在考虑这些挑战的奖金竞赛单独的类别,所以如果你这样做,不要担心你的代码比数字版本更长。

随意为每个版本提交一个解决scheme。

GolfScript – 101 96 93 92 91 90 94 86字节

90 → 94 :固定输出为10的倍数。
94 → 86 :重组代码。 使用基数100删除不可打印的字符。
86 → 85 :较短的弦线。

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

Perl,大约147个字符

松散的基于白金Azure的解决scheme:

  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 

Common Lisp 157 Chars

新的更符合版本,现在阅读forms标准input和忽略空格和连字符:

 (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.~%"xn)(gn)))))(g(read))) 

以人类可读的forms:

  (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.~%" xn) (gn))))) (g (read))) 

还有一些testing运行:

 >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. 

而奖金版本,在165个字符:

  (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.~%"fn)(gn)))))(g(read))) 

给予

 >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. 

Python 2.x,144 150 154 166 字符

这个数字分成几十个,然后总结起来。 如果b是0,伪三元算子a and b or c返回值的不良属性在这里被滥用。

 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." 

以前的天真版(150个字)。 只需将所有长度编码为整数。

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

C – 用数字表示

445 431 427 421 399 386 371 359 * 356 354 348 347个字符

而已。 我不认为我可以做得更短。

所有换行符都是为了可读性,可以删除:

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

下面,它有点没有意识,但仍然很难阅读。 请参阅下面的更可读版本。

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

扩展和评论:

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

关于开始附近的编码string

数字的名字是用一个非常简单的scheme压缩的。 经常使用的子string被replace为名称数组中的单字符索引。 额外名称条目的“查找表”被添加到第一组中未完整使用的子串的末尾。 查找是recursion的:条目可以引用其他条目。

例如,11的压缩名称是elMprint()函数逐字输出字符el (小写'L',不是数字'1'),但是它find了M ,所以它自己用第29项(ASCII'M' – ASCII'0')到查找表中。 这个string是evL ,所以它输出ev ,然后再次使用查找表中的第28个条目的索引(它是en再次调用它,并逐字输出。 这是有用的,因为en也被用于eL (用于eighteen eight之后),用于teen (用于其他-teen名字)。

该scheme导致数字名称的压缩相当显着,而只需要less量代码进行解压缩。

string开始和结尾的逗号代表了在该string中find子string的简单方法。 在这里添加两个字符后保存更多的字符。

关于main()的滥用

argv被忽略(因此没有在压缩版本中声明),argc的值被忽略,但是存储被重用来保存当前的数字。 这只是让我不必申报一个额外的variables。

关于缺乏#include

有些人会抱怨忽略#include <stdio.h>是作弊的。 这完全不是。 给定的是一个完全合法的C程序,可以在我知道的任何C编译器上正确编译(虽然有警告)。 缺lessstdio函数的原型,编译器会认为它们是返回int cdecl函数,并且会相信你知道要传递什么参数。 在这个程序中,返回值是被忽略的,无论如何,它们都是cdecl(“C”调用约定)函数,我们确实知道要传递什么参数。

产量

产出如预期:

 0
零是四。
四是魔法。
 1
一个是三个。
三是五。
五是四。
四是魔法。
 4
四是魔法。
 20
二十是六。
六是三。
三是五。
五是四。
四是魔法。
 21
二十一是九。
九是四。
四是魔法。

*以前的版本在规格的两个部分上没有标记:它没有处理零,而是在命令行上inputinput而不是stdin。 处理零添加字符,但使用stdin而不是命令行参数,以及一些其他优化保存了相同数量的字符,导致洗。

要求已更改,以明确数字应打印在“是”的两侧。 这个新版本满足了这个要求,并且实现了更多的优化(超过)来说明所需的额外大小。

J,107 112个字符

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

(换行仅为可读性)

用法和输出:

  '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. 

T-SQL,413 451 499个字符

 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 

(不是我认真地build议你这样做…我真的只是想写一个CTE)

使用:

 M 95 

返回

 pn ----------- ---- ----------- 95 is 10. 10 is 3. 3 is 5. 5 is 4. 4 is magic. 

Java(含样板), 308 290 286 282 280个字符

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

我相信Groovy会摆脱很多。

说明和格式 (在计数中删除了所有注释,换行符和前导/尾随空白):

合理直截了当,但

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

编辑:不再使用hex,这是less击键

Windows PowerShell:152 153 184个字节

基于以前的解决scheme,受其他解决scheme的影响更大

 $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.' 

C,158个字符

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

(最初是基于Vlad的Python代码,从Tom Sirgedas的C ++解决scheme中借用了一些技巧来挤出几个字符)

扩展版本:

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

Python,129 133 137 148 字符

作为一个热身,这是我的第一个版本(改进了几个字符比以前最好的Python)。

PS。 现在经过一些修改之后,约有二十个字符变短了:

 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.' 

C#:210个字符。

压扁:

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

扩展:

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

这个方法使用的技巧:

  • 根据数字中出现的数字创build数字名称长度查找表。
  • 对string使用字符数组查找,而使用char算术而不是数字数组。
  • 使用类名别名缩短Console.C.
  • 使用条件(三元)运算符( ?: :)而不是if/else
  • Write转义码代替WriteLine来使用\n
  • 使用C#具有已定义的评估顺序的事实,以允许Write函数调用中的分配
  • 使用赋值expression式来消除额外的语句,从而消除额外的大括号

Perl:148个字符

(Perl: 233 181 212 206 200 199 198 185 179 149 148个字符)

  • 将exception散列移到单元数组中。 这导致我能够削减很多字符:-)
  • mobrule指出了一个讨厌的bug。 快速修复增加了31个字符,哎!
  • 重构为零的特殊情况,温和的高尔夫也是如此。
  • 直接列表访问单一使用,而不是存储到数组? 当然好!
  • 所以只有一个血腥的angular色这么简单。 这确实是高尔夫球员的生活。 🙁
  • 糟糕,简单的空白修复。 198现在。
  • 重构了一些冗余代码。
  • r最后一个返回关键字是不必要的,可以省略一些。
  • 对每条评论进行大规模的重构; 不幸的是我只能达到149,因为我不得不修复在我以前的代码和评论者的版本中存在的错误。
  • 尝试裸字“魔法”。

让我们用Perl进行适度的尝试吧。

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

技巧:

太多!

JavaScript 1.8(SpiderMonkey) – 153个字符

 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.') 

用法: echo 42 | js golf.js echo 42 | js golf.js

输出:

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

奖金 – 364个字符

 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.') 

输出:

 九十九是十。
十是三。
三是五。
五是四。
四是魔法。

哈斯克尔,224 270个字符

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

而且更可读 –

 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] nx = if x < 20 then ones !! x else (tens !! div x 10) + (ones !! mod x 10) fx = zipWith (\ab -> a ++ " is " ++ b ++ ".") l (tail l) where l = map show (takeWhile (/=4) (iterate nx)) ++ ["4", "magic"] main = readLn >>= mapM putStrLn . f 

C ++ Stdio版本缩小:196个字符

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

C ++ Iostreams版本缩小为195个字符

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

原始,未缩小:344个字符

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

delphi:329个字符

单行版本:

 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. 

格式化:

 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. 

可能有更多的挤压空间… 😛

C# 314 286 283 274 289 273 252个字符。

压扁:

 252 

正常:

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

编辑Dykam:有相当一些carefull插入和更改:

  • 将l.ToString()更改为一个强制转换为string "magic" object
  • 创build一个临时variableso ,所以我可以移动for循环之外的break ,也就是说,导致一个do-while
  • 内联o赋值和v赋值,继续在函数参数中插入l的计算,不再需要l 。 还内联m的分配。
  • 除去int[] xint[]x的空格也是合法的。
  • 试图将数组转换为string转换,但using System.Linq太多,使这个改进。

编辑2 Dykam将int数组更改为char数组/string,添加适当的算术以更正此错误。

Lua,176个字符

 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[(nn%10)/10]print(n.." is "..a..".")n=a end print"4 is magic." 

要么

  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." 

C – 没有数字的话

180 175 * 172 167个字符

所有换行符都是为了可读性,可以删除:

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

有点无知:

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

*以前的版本在规格的两个部分上没有标记:它没有处理零,而是在命令行上inputinput,而不是标准input。 处理零增加的字符,但使用stdin而不是命令行参数保存更多,从而导致净节省。

perl, 123 122个字符

刚刚意识到没有要求输出到STDOUT,所以输出到STDERR而不是另一个字符。

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

而且,一个返回的版本拼出了数字:

279 278 276 280个字符

 @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/ 

虽然符合规范,但它不是100%格式。 它在数字以零结尾之后返回一个额外的空格。 规范确实说:

“我不在乎你如何区分这些单词,尽pipe它们应该分开”

虽然这是一种狡猾的。 一个更正确的版本

282 281 279 283个字符

 @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/ 

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" 

C++, 171 characters (#include omitted)

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

Ruby, 164 characters

 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." 

decoded:

 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." 

Lua 185 190 199

added periods, added io.read, removed ()'s on last print

  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.' 

with line breaks

  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.' 

PhP Code

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

//////////// testing ////////////////

  $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'; } 

////// Results /////////

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

Perl – 130 chars


5.12.1 (130 chars) 121 123 132 136 140

 # 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 chars) 125 127 136 140 144

 # 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/ 

Change History:

20100714:2223 – reverted change at the attention of mobrule , but ($_%10&&$u[$_%10])(($_%=10)&&$u[$_]) , which is the same # of chars, but I did it in case someone might see a way to improve it

20100714:0041split//,'...''...'=~/./g
20100714:0025($_%10&&$u[$_%10])$u[$_%10]
20100713:2340while$_until/\D/ + removed unnecessary parentheses
20100713:xxxx$=<>;chop;$_=pop; – courtesy to mobrule


Note: I was tired of improving others' answers in comments, so now I'm being greedy and can just add my changes here 🙂 This is a split off from Platinum Azure 's answer – credit in part to Hobbs , mobrule , and Platinum Azure .

Shameless Perl with Number Words (329 characters)

Adapted fairly directly from P Daddy's C code, with some tweaks to p() to make it do the same thing using Perl primitives instead of C ones, and a mostly-rewritten mainloop. See his for an explanation. Newlines are all optional.

 @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 

Side note: it's too bad that perl print just returns true/false; if it returned a count it would save me 7 strokes.

Ruby, 141 chars:

 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} 
 while(true) { string a; ReadLine(a) WriteLine(4); }