A avó surda de Chris Pine

22

Sou mentor do RubyLearning e um dos exercícios que damos aos nossos alunos é o exercício "Deaf Grandma" do livro de Chris Pine, " Learn to Program ". Aqui está a descrição:

Escreva um programa para a avó surda. O que você disser à avó (o que você digitar), ela deverá responder com: "Hein ?! Fala, filho!", A menos que você grite (digite todas as maiúsculas). Se você gritar, ela poderá ouvi-lo (ou pelo menos ela pensa assim) e gritar de volta: "Não, não desde 1938!"

Para tornar seu programa realmente crível, peça à avó que grite um ano diferente a cada vez; talvez qualquer ano aleatoriamente entre 1930 e 1950. (Esta parte é opcional e seria muito mais fácil se você ler a seção sobre o gerador de números aleatórios do Ruby no final do capítulo de métodos.) Você não pode parar de falar com a avó até que gritar "tchau".

Depois de várias iterações do curso, tentei ver o quão pequeno posso conseguir isso e agora tenho 112 caracteres:

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

Estou curioso para ver em quantos caracteres isso pode ser alcançado no idioma de sua escolha, porque acho que Ruby já está indo muito bem aqui.

Edit: A solução Perl postada abaixo levou a

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

que são 92 caracteres para a expressão + mais 2 para as opções ne l.

Michael Kohl
fonte
Em um contexto de golfe, isso precisa de especificações adicionais. O que deve acontecer se houver alguma saída extra após o BYE?
JB
Somente "BYE" termina exatamente o programa.
Michael Kohl

Respostas:

13

Perl, 85 91

Execute com perl -nE '<code goes there>'( ncontado no tamanho do programa):

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

Esse ponto de exclamação à direita é muito caro ...

Edições sugeridas por IK:

  • O uso de uma expressão regular em vez de uma correspondência de sequência poupa a -lopção global e também dois caracteres do programa: -3.
  • Usando uma variável real para salvar um valor e usá-lo mais tarde para interpolação (Genius! Quem pensaria em usar uma variável para isso?): 0.
  • Tornando essa variável $=restrita a ser um número inteiro: -4.

(e isso ainda não acontece e estou com muito sono para descobrir o porquê. Oh, bem, a contagem final está certa, pelo menos)

JB
fonte
Abusar $=e usar um regexp para "BYE" reduz esse número para 84 + 1:perl -nE '$==1930+rand 21;say/^BYE$/?last:uc eq$_?"NO, NOT SINCE $=!":"HUH?! SPEAK UP, SONNY!"'
Ilmari Karonen
@IlmariKaronen Integrated, obrigado!
JB
6

Python 120 caracteres

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

Alguma dica para melhorar?

fR0DDY
fonte
Você não precisa dos colchetes em torno dessa declaração if, também tenho certeza de que o python tem um limite de recursão - mas isso poderia simular sua avó adormecendo.
Phoshi
Oh! Eu esqueci de remover os suportes. Obrigado :)
fR0DDY
Você pode salvar alguns personagens se você remover a primeira linha, substituir a segunda com s='', reordenar as suas declarações em seu loop while, e colocar todo o loop while em uma linha: gist.github.com/3787809 Se você estava realmente determinado, você poderia salvar 2 caracteres usando python 3 (raw_input () -> input (), mas de impressão -> print ())
Matt
4

131 caracteres no PowerShell:

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!"}}

Com espaço em branco:

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!" }
}

Espremeu 18 caracteres da sugestão de Joey.

BTW, 'Learn to Program' foi o primeiro livro de programação que eu li de capa a capa.

Ty Auvil
fonte
Você pode querer dar uma olhada aqui: codegolf.stackexchange.com/questions/191/…
Joey
Você pode reduzir para 120 pressionando o primeiro if...na verificação condicional do for()mesmo modo: for(;($j=read-host)-cne"BYE"){if($j-ceq$j.ToUpper()){...Além disso, a especificação diz 1930-1950.
SpellingD
3

C # - 234 caracteres

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

Mais legível:

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));
        }
    }
}
Nellius
fonte
Senti falta de alguns dos meus e cometi alguns erros tolos. Agradável +1
Kyle Rozendo 04/02
3

Befunge - 27x6 = 162 caracteres

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

EDIT: Perdeu completamente a parte "BYE". Nova versão em breve.

EDIT 2: Na verdade, isso torna um pouco complexo demais para minhas poucas habilidades no Befunge. Posso tentar novamente mais tarde, mas não consigo pensar em nenhuma maneira simples de implementá-lo no momento.

Nemo157
fonte
3

C # - 194 CHARS

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

Com espaços em branco:

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

Com alguma inspiração de Nellius e fR0DDY.

Por favor, deixe-me saber se pode ser melhorado.

Richard
fonte
Curto, mas FWIW, acho que isso vaza (chamando recursivamente Main()). Além disso, acho que você deseja parens na ?:expressão para obter os !dois. Eu adicionei uma resposta com isso e EOL (mas ainda vaza).
bw
Vejo que você adicionou o parens e removeu seu comentário. Bom trabalho. Agora, minha edição para adicionar capturas de tela à minha resposta com e sem as parênteses é discutível. (Mas, ainda assim, vazando) :-) #
194
@ bill Sim, eu estraguei meus testes inicialmente. A versão não gotejante seria 199 caracteres, waaay muito tempo :)
Richard
ha Eu gosto da Main();solução ... nenhuma pessoa sã usaria este programa por tempo suficiente para que ele fosse um problema.
bw
Como Phoshi disse no comentário para fR0DDY. O programa falha quando a avó adormece.
Richard
3

D: 246 caracteres

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

Mais legivelmente:

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!");
    }
}
Jonathan M Davis
fonte
3

javascript, 142 caracteres, 29 deles executam ano aleatório

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)}
www0z0k
fonte
3

Awk: 97 caracteres

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

Windows PowerShell, 121 117

Devido à natureza da tarefa, isso parece praticamente idêntico à solução de Ty Auvil , embora tenha sido escrita de forma independente:

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

Graças a SpellingD pela sugestão,

Joey
fonte
Gosto da correspondência de regex, mas a instrução switch é muito volumosa. Junto com a sugestão que eu dei Ty, você poderia reduzir a sua contagem de caracteres para 117 usando regex com um iflugar como este:for(;($j=read-host)-cne'BYE'){if($j-cmatch'[a-z]'){'Huh?! Speak up, sonny!'}else{"No, not since 19$(30..50|random)"}}
SpellingD
2

Haskell (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

O estranho é que o código Haskell geralmente é muito menor que o código C comparável ao escrever um programa 'sério'.

marinus
fonte
Você pode evitar a importação Charusando any(`elem`['a'..'z'])spara testar letras minúsculas.
22711 hammar
2

APL (76)

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

C # - 345 caracteres

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

Maldita linguagem detalhada ... :-)

Kyle Rozendo
fonte
1
Você pode chamar apenas a turma P. E isso não detecta maiúsculas corretamente. Eu posso gritar e ele ainda não pode me ouvir. Você pode encurtar o método principal para while(t(Console.ReadLine()));. Você pode usar using C=System.Console;no início de encurtar o acesso a ReadLine()e WriteLine()a C.ReadLine()e C.WriteLine().
Joey
@ Joey - Obrigado pelas dicas!
Kyle Rozendo
1

C # - 196 caracteres (mas com vazamento)

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

Essa é a resposta de @ Richard (com vazamento) com dois parênteses (veja abaixo) e um \ n adicionado lá para obter a EOL nos dois casos. Caso contrário, o " + "espaço é apenas desperdiçado.

Formatado

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

UPDATE: para esclarecer meu comentário sobre as parênteses sendo necessárias, eis o que recebo sem as parênteses (ou seja, com a solução original do @ Richard):

sem parênteses

E com os parênteses:

com parênteses

Nenhum destes usa meu adicional \nembora.

bw
fonte
São 195 aqui, apenas. Você contou uma quebra de linha desnecessária no final?
Joey
1

Bash: 136 128 caracteres

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

Alternativa limitada: 132 123 caracteres

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

Você pode conversar com um surdo infinitamente, mas a conversa com esse código posterior é limitada pela pilha de chamadas. (No meu teste, ele é finalizado após 4989 chamadas.)

homem a trabalhar
fonte
1

Javascript - 133 131 130 128 127 121 caracteres

versão golfed da solução 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)+'!');

Edit: salvou outros seis caracteres com esta ótima dica

codeporn
fonte
Escreva o operador ternário como g=/[a-z]/.test(i)?'Huh?!...':'No...'e você poupa 2 caracteres.
manatwork
Editado, obrigado pelo ponteiro.
codeporn
1
Mais 1 caractere que encontrei: Math.ceil()é menor que Math.floor(). Basta alterar o ano base para manter o inalterada intervalo: Math.ceil(Math.random()*21+1929).
manatwork 27/09/12
Ótimo, +1! Salvei mais dois caracteres ao alterar o tempo para um loop for.
codeporn
0

Clojure - 160 154 caracteres

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

Trabalhando no golfe um pouco mais. Sugestões são bem-vindas.

Execute o REPL

MrZander
fonte
0

Q, 115

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

uso

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
'
tmartin
fonte