La "abuela sorda" de Chris Pine

22

Soy mentor en RubyLearning y uno de los ejercicios que damos a nuestros estudiantes es el ejercicio "Abuela sorda" del libro " Aprender a programar " de Chris Pine . Aquí está la descripción:

Escribe un programa de abuela sorda. Lo que le digas a la abuela (lo que escribas), ella debería responder con: "¡¿Huh? ¡Habla, hijo!", A menos que lo grites (escribe todas las mayúsculas). Si gritas, ella puede oírte (o al menos así lo cree) y te responde: "¡No, no desde 1938!"

Para que su programa sea realmente creíble, haga que la abuela grite un año diferente cada vez; tal vez cualquier año al azar entre 1930 y 1950. (Esta parte es opcional, y sería mucho más fácil si leyeras la sección sobre el generador de números aleatorios de Ruby al final del capítulo de métodos). No puedes dejar de hablar con la abuela hasta que grita "BYE".

Después de varias iteraciones del curso, traté de ver cuán pequeño puedo obtener esto y ahora lo reduzco a 112 caracteres:

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

Tengo curiosidad por ver en qué pocos caracteres se puede lograr esto en el idioma que elija, porque creo que a Ruby ya le está yendo muy bien aquí.

Editar: La solución Perl publicada a continuación condujo a

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

que tiene 92 caracteres para la expresión + 2 más para las opciones ny l.

Michael Kohl
fuente
En un contexto de golf, esto necesita una especificación adicional. ¿Qué debería suceder si hay algún resultado adicional pasado BYE?
JB
Solo "BYE" termina exactamente el programa.
Michael Kohl

Respuestas:

13

Perl, 85 91

Ejecutar con perl -nE '<code goes there>'( ncontado en el tamaño del programa):

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

Ese signo de exclamación final es muy costoso ...

Ediciones sugeridas por IK:

  • El uso de una expresión regular en lugar de una coincidencia de cadena ahorra la -lopción global, así como dos caracteres del programa: -3.
  • Usar una variable real para guardar un valor y usarlo más tarde para la interpolación (¡Genio! ¿Quién hubiera pensado en usar una variable para eso?): 0.
  • Haciendo esa variable $=, restringida a ser un número entero: -4.

(y todavía no cuadra y tengo demasiado sueño para averiguar por qué. Oh, bueno, el conteo final es correcto al menos)

JB
fuente
Abusar $=y usar una expresión regular para "BYE" reduce esto a 84 + 1:perl -nE '$==1930+rand 21;say/^BYE$/?last:uc eq$_?"NO, NOT SINCE $=!":"HUH?! SPEAK UP, SONNY!"'
Ilmari Karonen
@IlmariKaronen Integrado, gracias!
JB
6

Python 120 Personajes

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

¿Alguna pista para mejorar?

fR0DDY
fuente
No necesita los corchetes alrededor de esa declaración if, también estoy bastante seguro de que Python tiene un techo de recursión, pero eso podría simular que su abuela se duerma.
Phoshi
Oh! Olvidé quitar los corchetes. Gracias :)
fR0DDY
Puede guardar algunos caracteres si elimina la primera línea, reemplaza la segunda con s='', reordena sus declaraciones en su ciclo while y coloca todo el ciclo while en una línea: gist.github.com/3787809 Si realmente estuviera decidido, podría guardar 2 caracteres usando python 3 (raw_input () -> input (), pero print -> print ())
Matt
4

131 caracteres en 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!"}}

W / espacio en blanco:

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

Exprimió 18 personajes de la sugerencia de Joey.

Por cierto, 'Learn to Program' fue el primer libro de programación que leí de principio a fin.

Ty Auvil
fuente
Es posible que desee echar un vistazo aquí: codegolf.stackexchange.com/questions/191/…
Joey
Puede reducir esto a 120 comprimiendo el primero if...en la verificación condicional de la for()misma manera: for(;($j=read-host)-cne"BYE"){if($j-ceq$j.ToUpper()){...también, la especificación dice 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));}}}

Más legible:

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
fuente
Ah eché de menos algunos simples en el mío y cometí algunos errores tontos. Niza +1
Kyle Rozendo
3

Befunge - 27x6 = 162 caracteres

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

EDITAR: Perdí por completo la parte "BYE". Nueva versión próximamente.

EDIT 2: En realidad, eso lo hace un poco demasiado complejo para mis escasas habilidades Befunge. Podría intentarlo más tarde, pero no puedo pensar en ninguna forma simple de implementarlo en este momento.

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

Con espacios en blanco:

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

Con un poco de inspiración de Nellius y fR0DDY.

Avíseme si se puede mejorar.

Ricardo
fuente
Corto, pero FWIW, creo que esto se filtra (recursivamente llamando Main()). Además, creo que quieres que los parens en la ?:expresión obtengan los !dos. Agregué una respuesta con esto y EOL (pero aún tiene fugas).
bw
veo que agregaste los parens y eliminaste tu comentario. Buen trabajo. Ahora mi edición para agregar capturas de pantalla a mi respuesta de con y sin los parens es discutible. (Pero, aún con fugas) :-)
bw
@ factura Sí, al principio arruiné mis pruebas. La versión sin fugas sería de 199 caracteres, muuuucho tiempo :)
Richard
decir ah. Me gusta la Main();solución ... ninguna persona en su sano juicio usaría este programa el tiempo suficiente para que sea un problema.
bw
Como dijo Phoshi en el comentario a fR0DDY. El programa se bloquea cuando la abuela se queda dormida.
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!");}}

Más legible:

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
fuente
3

JavaScript, 142 caracteres, 29 de ellos realizan año aleatorio

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
fuente
3

Awk: 97 caracteres

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

Windows PowerShell, 121 117

Debido a la naturaleza de la tarea, esto parece bastante idéntico a la solución de Ty Auvil , aunque fue escrito de forma independiente:

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

Gracias a SpellingD por la sugerencia,

Joey
fuente
Me gusta su coincidencia de expresiones regulares, pero la declaración de cambio es muy voluminosa. Junto con la sugerencia que le di a Ty, puedes reducir tu conteo de personajes a 117 usando expresiones regulares con un 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

Lo extraño es que el código Haskell suele ser mucho más corto que el código C comparable al escribir un programa 'serio'.

marinus
fuente
Puede evitar importar Charutilizando any(`elem`['a'..'z'])spara probar letras minúsculas.
hammar
2

APL (76)

 {'BYE'≢A←⍞:∇⎕←{∧/⍵∊⎕A:'No, not since ',⍕1938+?20⋄'Huh?! Speak up sonny!'}A}⍬
marinus
fuente
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);}}

Maldito lenguaje detallado ... :-)

Kyle Rozendo
fuente
1
Puedes llamar a la clase solo P. Y esto no detecta mayúsculas correctamente. Puedo gritarle y todavía no puede oírme. Puede acortar el método principal a while(t(Console.ReadLine()));. Se puede utilizar using C=System.Console;en el inicio de acortar el acceso a ReadLine()y WriteLine()a C.ReadLine()e C.WriteLine().
Joey
@Joey: ¡Gracias por los consejos!
Kyle Rozendo
1

C # - 196 caracteres (pero con fugas)

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

Esa es la respuesta (con fugas) de @ Richard con dos parens (ver más abajo) y \ n agregada allí para obtener la EOL en ambos casos. De lo contrario, " + "solo se desperdicia espacio.

Formateado

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

ACTUALIZACIÓN: para aclarar mi comentario sobre la necesidad de los padres, esto es lo que obtengo sin los padres (es decir, con la solución original de @ Richard):

sin parens

Y con los padres:

con parens

Sin \nembargo, ninguno de estos usa mi adicional .

bw
fuente
Son 195 aquí, solo. ¿Contaste un salto de línea innecesario al 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

Puede hablar con un sordo infinitamente, pero la conversación con este código posterior está limitada por la pila de llamadas. (En mi prueba, termina después de 4989 llamadas).

hombre trabajando
fuente
1

Javascript - 133 131 130 128 127 121 caracteres

versión de golf de la solución 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)+'!');

Editar: salvó otros seis caracteres con este gran consejo

codeporn
fuente
Escribe el operador ternario como g=/[a-z]/.test(i)?'Huh?!...':'No...'y ahorras 2 caracteres.
manatwork
Editado, gracias por el puntero.
codeporn
1
Un personaje más que encontré: Math.ceil()es más corto que Math.floor(). Sólo cambia el año base para mantener sin cambios el intervalo: Math.ceil(Math.random()*21+1929).
manatwork
Genial, +1! Ahorré otros dos caracteres al cambiar el while a un bucle 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))

Trabajando en jugar al golf un poco más. Sugerencias bienvenidas.

Ejecutar a través de REPL

MrZander
fuente
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
fuente