代码高尔夫:四是魔术

Pla*_*ure 88 language-agnostic code-golf rosetta-stone

这个谜题

我在高中时听到的一个小谜题是这样的......

  • 提问者会让我给他一个号码;
  • 在听到这个数字时,提问者会反复对它进行某种改变(例如,他可能会说十个是三个),直到最终到达数字4(此时他将用四个完成魔术).
  • 无论如何,任何数字似乎最终都可以转化为四个.

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

解决方案

任何步骤的转换功能都是

  • 拿这个号码,
  • 计算其英文单词表示中的字母数,忽略连字符或空格或"和"(例如,"十"中有3个字母,"三十四"中有10个字母,"一百四十三"有20个字母).
  • 返回那个字母数.

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

挑战

您的挑战是创建一段代码,该代码将从用户读取数字,然后打印显示重复应用的转换函数的行,直到达到"四是魔术".

特别:

  1. 解决方案必须是完整的程序.它们不仅仅是在输入中引入数字因子的函数.
  2. 必须从标准输入读取输入.(从"echo"管道或使用输入重定向管道很好,因为它也来自stdin)
  3. 输入应为数字形式.
  4. 对于转换函数的每个应用,都应打印一行:a is b.其中a和b是转换中数字的数字形式.
  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.
Run Code Online (Sandbox Code Playgroud)

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

奖金

您也可以尝试编写一个代码版本,该代码使用转换函数的每个应用程序打印数字的ENGLISH NAMES.原始输入仍为数字,但输出行应具有数字的单词形式.

(使用您的代码绘制形状的双重奖励)

(编辑)一些澄清:

  1. 我确实希望在所有适用的案例中双方都出现这个词,例如 Nine is four. Four is magic.
  2. 不过,我不关心大写.而且我不在乎你如何将单词标记分开,尽管它们应该是分开的:ninety-nine好的,ninety nine没关系,ninetynine不行.

我正在考虑将这些作为奖金竞争的单独类别,因此如果你这样做,不要担心你的代码比数字版本更长.

随意为每个版本提交一个解决方案.

mob*_*mob 85

Perl,大约147个字符

松散地基于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
Run Code Online (Sandbox Code Playgroud)

  • 这真是令人印象深刻. (4认同)

Nab*_*abb 57

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

90 ? 94:固定输出为10的倍数
94 ? 86:重组代码.使用base 100删除不可打印的字符.
86 ? 85:缩短演员阵容.

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

  • 我喜欢代码以"魔术"结束的方式."它几乎总结了它. (36认同)
  • @Aistina:哈哈,这有点好笑."mumbo jumbo yada yada..magic" (9认同)

小智 30

Common Lisp 157 Chars

新的更符合标准的版本,现在读取标准输入并忽略空格和连字符:

(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)))
Run Code Online (Sandbox Code Playgroud)

以人类可读的形式:

 (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)))
Run Code Online (Sandbox Code Playgroud)

一些测试运行:

>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.
Run Code Online (Sandbox Code Playgroud)

奖金版本,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.~%"f n)(g n)))))(g(read)))
Run Code Online (Sandbox Code Playgroud)

给予

>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.
Run Code Online (Sandbox Code Playgroud)

  • 我以为"二十四"只有10个字母? (5认同)
  • 为什么这么高?其他的不使用内置格式功能,它们的字符较少 (5认同)
  • @Claudiu因为Common Lisp太棒了. (3认同)
  • 如果你没有将球拿到球洞中,你的击球次数无关紧要.人们似乎忘记了当他们提出不正确的解决方案时. (3认同)

ken*_*ytm 21

Python 2.x,144 150 154 166 字符

这将数字分成数十和一,并将它们相加.伪三元运算符的不想要的性质a and b or cc,如果返回b值为0这里正在被滥用.

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."
Run Code Online (Sandbox Code Playgroud)

以前的天真版本(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."
Run Code Online (Sandbox Code Playgroud)

  • @Plat:这会在`.`之前产生额外的空间. (2认同)

P D*_*ddy 20

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);}
Run Code Online (Sandbox Code Playgroud)

下面,它有点不明确,但仍然很难阅读.请参阅下面的更易读的版本.

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);
}
Run Code Online (Sandbox Code Playgroud)

扩大和评论:

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"*/);
}
Run Code Online (Sandbox Code Playgroud)

关于开头附近的编码字符串

使用非常简单的方案压缩数字的名称.经常使用的子字符串被一个字符的索引替换为name数组.对于未在第一组中完整使用的子串,将额外名称条目的"查找表"添加到末尾.查找是递归的:条目可以引用其他条目.

例如,11的压缩名称是elM.该print()函数逐字输出字符el(小写'L',而不是数字'1'),但随后它找到了M,所以它用第29个条目的索引(ASCII'M' - ASCII'0')调用自身进入查找表.这个字符串evL,因此它输出ev,然后在查找表,这是第28项的指标再次调用自身en,并逐字输出.这很有用,因为en它也用于eLfor een(在after之后eight使用eighteen),用于tOfor teen(用于其他所有-teen名称).

该方案导致数字名称的相当大的压缩,同时仅需要少量代码来解压缩.

字符串开头和结尾的逗号表示在此字符串中找到子字符串的简单方式.此处添加两个字符可以在以后保存更多字

关于虐待 main()

argv被忽略(因此未在压缩版本中声明),argc的值被忽略,但存储被重用以保存当前数字.这只是让我不必声明一个额外的变量.

关于缺乏 #include

有人会抱怨省略#include <stdio.h>是作弊.它完全没有.给定的是一个完全合法的C程序,可以在我知道的任何C编译器上正确编译(尽管有警告).由于缺少stdio函数的原型,编译器会假设它们是cdecl函数返回的int,并且相信你知道要传递什么参数.无论如何,在这个程序中忽略返回值,它们都是cdecl("C"调用约定)函数,我们确实知道要传递什么参数.

产量

输出符合预期:

0
zero is four.
four is magic.
1
one is three.
three is five.
five is four.
four is magic.
4
four is magic.
20
twenty is six.
six is three.
three is five.
five is four.
four is magic.
21
twenty-one is nine.
nine is four.
four is magic.

*之前的版本错过了规范的两个部分:它没有处理零,并且它在命令行而不是stdin上输入.处理零添加了字符,但使用stdin而不是命令行args,以及其他一些优化保存了相同数量的字符,从而导致清洗.

已更改要求,以明确数字应印在"是"的两侧.这个新版本满足了这个要求,并实现了一些更多的优化(超过)考虑所需的额外大小.

  • 这很有趣,我想我将从现在开始在日常生活中使用这些数字.六,sem,八,九,tel,elem,十二,enpee,fourpee,fifpee,sixpee,sevenpee,eightoh,ninepee,twelkyu ... =) (5认同)

Dav*_*vid 10

J,107 112个字符

'4 is magic.',~}:('.',~":@{.,' is ',":@{:)"1]2&{.\.
(]{&(#.100 4$,#:3 u:ucp'?????????????????????????'))^:a:
Run Code Online (Sandbox Code Playgroud)

(仅限可读性换行符)

用法和输出:

    '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. 
Run Code Online (Sandbox Code Playgroud)

  • 它是用中文编写的 (15认同)
  • 请选择非中国裁判 (3认同)
  • @beli:멩,겻,곋,멩是韩国人. (3认同)
  • @belisarius:1)她不懂韩语.2)中国人是胡言乱语. (3认同)

Leo*_*ick 10

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
Run Code Online (Sandbox Code Playgroud)

(不是说我真的建议你这样做......真的我只是想写一个CTE)

使用:

M 95
Run Code Online (Sandbox Code Playgroud)

返回

p                n
----------- ---- -----------
95          is   10.
10          is   3.
3           is   5.
5           is   4.
4 is magic.
Run Code Online (Sandbox Code Playgroud)


Mar*_*ers 9

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");}}
Run Code Online (Sandbox Code Playgroud)

我相信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");
   }
}
Run Code Online (Sandbox Code Playgroud)

编辑:不再使用十六进制,这是更少的击键


Joe*_*oey 9

Windows PowerShell:152 153 184字节

基于以前的解决方案,其他解决方案的影响更大

$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.'
Run Code Online (Sandbox Code Playgroud)


Fer*_*cio 8

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.");}
Run Code Online (Sandbox Code Playgroud)

(最初基于Vlad的Python代码,借用了Tom Sirgedas的C++解决方案中的技巧来挤出更多的字符)

扩展版本:

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.");
}
Run Code Online (Sandbox Code Playgroud)


Pla*_*ure 6

Perl:148个字符

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

  • 将异常哈希移动到单元数组中.这导致我能够削减很多角色:-)
  • mobrule指出了一个讨厌的bug.快速修复添加31个字符,哎哟!
  • 重复零特殊情况,也进行温和的高尔夫球.
  • 直接列表访问一次性使用而不是存储到数组?当然好!
  • 对于一个血腥的角色来说,只需要很多的改造.这确实是高尔夫球手的生活.:-(
  • 哎呀,简单的空白修复.198现在.
  • 重构了一些冗余代码.
  • 最后一个返回关键字in r是不必要的,剃掉了一些关闭.
  • 每条评论都进行了大规模的重构; 不幸的是我只能得到149,因为我必须修复我早期代码和评论者版本中出现的错误.
  • 尝试赤字"魔术".

让我们在Perl中进行一次适度的尝试.

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

技巧:

太多!


LBu*_*kin 6

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));}}
Run Code Online (Sandbox Code Playgroud)

扩展:

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)
                   );
    }
}
Run Code Online (Sandbox Code Playgroud)

这种方法使用的技巧:

  • 根据数字中显示的数字为数字名称长度创建查找表.
  • 对字符串使用字符数组查找,使用char算术而不是数字数组.
  • 使用类名混叠短Console.C.
  • 使用条件(三元)运算符(?:)代替if/else.
  • 使用\nwith Writeescape代码而不是WriteLine
  • 使用C#具有已定义的评估顺序以允许在Write函数调用内进行赋值的事实
  • 使用赋值表达式来消除额外的语句,从而消除额外的括号


Nas*_*nov 6

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.'
Run Code Online (Sandbox Code Playgroud)


gna*_*arf 5

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.')
Run Code Online (Sandbox Code Playgroud)

用法: echo 42 | js golf.js

输出:

42 is 8.
8 is 5.
5 is 4.
4 is magic.
Run Code Online (Sandbox Code Playgroud)

奖金 - 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.')
Run Code Online (Sandbox Code Playgroud)

输出:

ninety nine is ten.
ten is three.
three is five.
five is four.
four is magic.