克里斯·派恩(Chris Pine)的“聋奶奶”


22

我是RubyLearning的导师,我们为学生提供的练习之一是Chris Pine的书“ Learn to Program ”中的“聋奶奶”练习。描述如下:

编写聋人奶奶程序。无论您对奶奶说什么(无论您输入什么),她都应回答:“ Hu!如果您大喊,她会听到您的声音(或者至少她是这么认为的),然后大喊:“不,自1938年以来!”

为了使您的程序真正可信,每次让奶奶大喊一遍。可能是1930年至1950年之间的任意一年。(这部分是可选的,如果您在方法一章的末尾阅读Ruby的随机数生成器这一节,将会更加容易。)喊“再见”。

经过几次课程迭代后,我尝试查看我能得到多小,现在减少到112个字符:

puts (s||='').upcase==s ? "NO, NOT SINCE #{1930+rand(21)}!":"HUH?! SPEAK UP, SONNY!" until(s=gets.chomp)=="BYE"

我很想知道用您选择的语言可以实现几个字符,因为我认为Ruby在这里已经做得很好。

编辑:下面发布的Perl解决方案导致

ruby -nle 'puts($_=="BYE"?exit: $_.upcase!? "HUH?! SEPAK UP, SONNY!":"NO, NOT SINCE #{1930+rand(21)}!")'

表达式的长度为92个字符,而nand l选项的长度为2个字符。


在打高尔夫球的情况下,这需要附加的规范。如果BYE之外还有其他输出,该怎么办?
JB

只有“ BYE”才能完全终止程序。
Michael Kohl

Answers:


13

Perl,85 91

运行方式perl -nE '<code goes there>'n以程序大小计):

$==1930+rand 21;say/^BYE$/?last:uc eq$_?"
NO, NOT SINCE $=!":"HUH?! SPEAK UP, SONNY!"

尾随的感叹号非常昂贵。

IK建议的编辑:

  • 使用正则表达式而不是字符串匹配可避免使用-l全局选项以及两个程序字符:-3。
  • 使用实际变量保存值并在以后用于插值(Genius!谁曾考虑使用该变量?):0。
  • 使该变量$=受约束为整数:-4。

(它仍然不累加,我太困了,无法找出原因。哦,好吧,至少最后一次是对的)


滥用$=和为“再见”使用正则表达式可将其降低至84 + 1:perl -nE '$==1930+rand 21;say/^BYE$/?last:uc eq$_?"NO, NOT SINCE $=!":"HUH?! SPEAK UP, SONNY!"'
Ilmari Karonen 2012年

@IlmariKaronen综合,谢谢!
2012年

6

Python 120个字符

r=raw_input
s=r()
while'BYE'!=s:
 print["HUH?! SPEAK UP, SONNY!","NO, NOT SINCE %d!"%(1930+id(s)%21)][s.isupper()];s=r()

有任何改善的提示吗?


您不需要在if语句周围的括号,我也很确定python具有递归上限-但这可以模拟您的祖母入睡。
Phoshi 2011年

哦! 我忘了拆下括号。谢谢:)
fR0DDY 2011年

如果删除第一行,将第二行替换为s='',在while循环中重新排列语句,然后将整个while循环放在一行上,则可以保存一些字符:gist.github.com/3787809如果您确实确定,则可以使用python 3(raw_input()-> input(),但print-> print())保存2个字符
Matt

4

PowerShell中的131个字符:

for(){$j=read-host;if($j-ceq"BYE"){break}if($j-ceq$j.ToUpper()){"No, not since 19$(10..90|random)!"}else{"Huh?! Speak up, sonny!"}}

带空格:

for(){
  $j = read-host;
  if ( $j -ceq "BYE" ) { break }
  if ( $j -ceq $j.ToUpper() ) { "No, not since 19$(10..90|random)!" }
  else { "Huh?! Speak up, sonny!" }
}

从乔伊的建议中挤出了18个字符。

顺便说一句,“学习编程”是我读过的第一本编程书籍。



通过将第一个压缩if...for()类似的条件检查中,您可以将其降低到120,如下所示:for(;($j=read-host)-cne"BYE"){if($j-ceq$j.ToUpper()){...同样,该规格说明为1930-1950。
SpellingD 2012年

3

C#-234个字符

using System;class P{static void Main(){for(;;){var s=Console.ReadLine();if(s!=s.ToUpper()){Console.WriteLine("Huh?! Speak up, sonny!");continue;}if(s=="BYE")break;Console.WriteLine("No, not since 19{0}!",new Random().Next(30,51));}}}

更具可读性:

using System;
class P
{
    static void Main()
    {
        for(;;)
        {
            var s=Console.ReadLine();
            if(s!=s.ToUpper())
            {
                Console.WriteLine("Huh?! Speak up, sonny!");
                continue;
            }
            if(s=="BYE")
                break;
            Console.WriteLine("No, not since 19{0}!",new Random().Next(30,51));
        }
    }
}

阿错过了我的一些简单的错误,并犯了一些愚蠢的错误。尼斯+1
凯尔·罗曾多

3

Befunge-27x6 = 162个字符

> ~:0`  #v _            vv<
         >:"a"`!#v  _:"z"`|
^                <       <
v"Huh?! Speak up, sonny!"0<
v"No, not since 1938!"0 <
>:# #, _@

编辑:完全错过了“再见”部分。新版本即将推出。

编辑2:实际上,这对于我微薄的Befunge技能来说有点太复杂了。我可能稍后再试,但是目前我想不出任何简单的方法来实现它。


3

C#-194个字符

using System;class P{static void Main(){var s=Console.ReadLine();if(s!="BYE"){Console.Write((s==s.ToUpper()?"No, not since 19"+new Random().Next(30, 51):"Huh?! Speak up, sonny")+"!");Main();}}}

带空格:

using System;
class P
{
    static void Main()
    {
        var s = Console.ReadLine();
        if (s != "BYE")
        {
            Console.Write((s == s.ToUpper() ? "No, not since 19" + new Random().Next(30, 51) : "Huh?! Speak up, sonny") + "!");
            Main();
        }
    }
}

从Nellius和fR0DDY获得一些灵感。

请让我知道是否可以改进。


简短,但FWIW,我认为这会泄漏(递归调用Main())。另外,我认为您希望?:表达式中的括号同时获得!两者。我为此和EOL添加了一个答案(但仍然存在泄漏)。
bw

我看到您添加了括号并删除了您的评论。做得好。现在,我的编辑添加屏幕截图到有或没有括号的答案中都没有意义。(但是仍然漏水):-)
bw

@bill是的,我最初弄乱了测试。非泄漏版本将为199个字符,太长了:)
理查德(Richard)

哈。我喜欢这种Main();解决方案...没有一个理智的人会使用此程序足够长的时间,以免出现问题。
bw

正如Phoshi在对fR0DDY的评论中所说。奶奶入睡时程序崩溃。
理查德

3

D:246个字符

import std.random,std.stdio,std.string;void main(){auto r=rndGen();for(;;){auto t=strip(readln());if(t=="BYE")break;if(t.toupper()==t)writefln("No, not since %s!",{r.popFront();return r.front%20+1930;}());else writeln("Huh?! Speak up, sonny!");}}

更清晰:

import std.random, std.stdio, std.string;

void main()
{
    auto r = rndGen();

    for(;;)
    {
        auto t = strip(readln());

        if(t == "BYE")
            break;

        if(t.toupper() == t)
            writefln("No, not since %s!", {r.popFront(); return r.front % 20 + 1930;}());
        else
            writeln("Huh?! Speak up, sonny!");
    }
}

3

javascript,142个字符,其中29个随机年份

n='a'; while((/[a-z]/.test(n)?r="HUH?! SPEAK UP, SONNY!":n=="BYE"?r='':r="NO, NOT SINCE "+Math.floor(Math.random()*21+1930))!=''){n=prompt(r)}

3

Awk:97个字符

$0=="BYE"{exit}$0=toupper($0)==$0?"NO, NOT SINCE "int(rand()*21+1930)"!":"HUH?! SPEAK UP, SONNY!"

3

Windows PowerShell,121 117

由于任务的性质,这看起来与Ty Auvil的解决方案几乎相同,尽管它是独立编写的:

for(;($j=read-host)-cne'BYE'){if($j-cmatch'[a-z]'){'Huh?! Speak up, sonny!'}else{"No, not since 19$(30..50|random)"}}

感谢SpellingD的建议,


我喜欢您的正则表达式匹配项,但是switch语句很笨重。连同我给Ty的建议,您可以使用正则表达式将字符数减少到117,if例如:for(;($j=read-host)-cne'BYE'){if($j-cmatch'[a-z]'){'Huh?! Speak up, sonny!'}else{"No, not since 19$(30..50|random)"}}
SpellingD 2012年

2

哈斯克尔(189)

import Random
import Char
main=getLine>>=g
g"BYE"=return""
g s|s/=map toUpper s=putStrLn"HUH?! SPEAK UP SONNY!">>main|4>2=randomRIO(30,50::Int)>>=putStrLn.("NO, NOT SINCE 19"++).show>>main

奇怪的是,编写“严重”程序时,Haskell代码通常比同等的C代码短很多。


您可以Char通过使用any(`elem`['a'..'z'])s测试小写字母来避免导入。
hammar 2011年

2

APL(76)

 {'BYE'≢A←⍞:∇⎕←{∧/⍵∊⎕A:'No, not since ',⍕1938+?20⋄'Huh?! Speak up sonny!'}A}⍬

1

C#-345个字符

using System;class Program{static void Main(){for(;;){if(!t(Console.ReadLine()))break;}}static bool t(string s){bool b=false;if(s=="BYE")return b;int i=0;for(;i<s.Length;i++){b=(s[i]>65&&s[i]<90)?true:false;if(!b)break;}if(b) p("NO, NOT SINCE 1938!");else p("HUH?! SPEAK UP, SONNY!");return true;}static void p(string s){Console.WriteLine(s);}}

该死的冗长语言... :-)


1
您可以只给班级打电话P。这不能正确检测大写。我可以大声喊叫,但它仍然听不到我的声音。您可以将main方法缩短为while(t(Console.ReadLine()));。您可以使用using C=System.Console;在开始缩短访问ReadLine(),并WriteLine()C.ReadLine()C.WriteLine()
乔伊,

@Joey-感谢您的提示!
凯尔·罗曾多

1

C#-196个字符(但泄漏)

using System;class P{static void Main(){var s=Console.ReadLine();if(s!="BYE"){Console.Write((s==s.ToUpper()?"No, not since 19"+new Random().Next(30, 51):"Huh?! Speak up, sonny")+"!\n");Main();}}}

这是@Richard的(泄漏)答案,其中有两个括号(见下文),并在其中添加了\ n来获得两种情况下的EOL。否则," + "这只是浪费的空间。

格式化的

using System;
class P
{
    static void Main() { 
        var s = Console.ReadLine(); 
        if (s != "BYE") { 
            Console.Write((
                s == s.ToUpper() ? 
                "No, not since 19" + new Random().Next(30, 51) : 
                "Huh?! Speak up, sonny"
                ) + "!\n");
            Main(); 
        } 
    }
}

更新:为了澄清我对需要的parens的评论,这是我没有parens的结果(即使用@Richard的原始解决方案):

没有原谅

并加上括号:

与原谅

这些都不使用我的额外\n


这里只有195。您是否在末尾算了不必要的换行符?
Joey

1

重击:136128个字符

while read s
do
[[ $s = BYE ]]&&break
[[ ${s^^} = $s ]]&&echo NO, NOT SINCE $[RANDOM%21+1930]!||echo HUH?! SPEAK UP, SONNY!
done

有限的替代:132 123个字符

f(){
read s
[[ $s = BYE ]]||{
[[ ${s^^} = $s ]]&&echo NO, NOT SINCE $[RANDOM%21+1930]!||echo HUH?! SPEAK UP, SONNY!
f
}
}
f

您可以无限地与聋哑人交谈,但是与该更高版本代码的对话受到调用堆栈的限制。(在我的测试中,它在4989次通话后被终止。)


1

使用Javascript - 133 131 130 128 127 121个字符

高尔夫版本的www0z0ks解决方案

g='';while((i=prompt(g))!='BYE'){/[a-z]/.test(i)?g='Huh?! Speak up, sonny!':g='No, not since '+Math.floor(Math.random()*21+1930)+'!'}

g='';while((i=prompt(g))!='BYE'){g=/[a-z]/.test(i)?'Huh?! Speak up, sonny!':'No, not since '+Math.floor(Math.random()*21+1930)+'!'}

g='';while((i=prompt(g))!='BYE'){g=/[a-z]/.test(i)?'Huh?! Speak up, sonny!':'No, not since '+Math.ceil(Math.random()*21+1929)+'!'}

for(g='';(i=prompt(g))!='BYE';g=/[a-z]/.test(i)?'Huh?! Speak up, sonny!':'No, not since '+Math.ceil(Math.random()*21+1929)+'!');

for(g='';(i=prompt(g))!='BYE';g=/[a-z]/.test(i)?'Huh?! Speak up, sonny!':'No, not since '+parseInt(Math.random()*21+1930)+'!');

for(g='';(i=prompt(g))!='BYE';g=/[a-z]/.test(i)?'Huh?! Speak up, sonny!':'No, not since '+(Math.random()*21+1930|0)+'!');

编辑:这个很棒的技巧保存了另外六个字符


将三元运算符写为g=/[a-z]/.test(i)?'Huh?!...':'No...',您将保留2个字符。
manatwork 2012年

编辑,谢谢你的指导。
codeporn 2012年

1
我发现还有1个字符:Math.ceil()比短Math.floor()。只需更改基准年即可保持时间间隔不变:Math.ceil(Math.random()*21+1929)
manatwork 2012年

太好了,+ 1!通过将while更改为for循环,我节省了另外两个字符。
codeporn 2012年

0

Clojure- 160154个字符

(#(if(= % "BYE")%(do(if(=(.toUpperCase %)%)(prn(str"No, not since "(+ 1930(rand-int 9))"!"))(prn"Huh?! Speak up, sonny!"))(recur(read-line))))(read-line))

打高尔夫球要多一点。欢迎提出建议。

通过REPL运行


0

问115

{while[1;v:read0 0;$[v~"BYE";'`;v~upper v;-1"No, not since ",/:(($)1?1930+(!)20),'"!";-1"Huh?! Speak up, sonny!"]]}

用法

q){while[1;v:read0 0;$[v~"BYE";'`;v~upper v;-1"No, not since ",/:(($)1?1930+(!)20),'"!";-1"Huh?! Speak up, sonny!"]]}`
Hi
Huh?! Speak up, sonny!
Hello
Huh?! Speak up, sonny!
HELLO!
No, not since 1938!
Goodbye Grandma
Huh?! Speak up, sonny!
BYE
'
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.