La «grand-mère sourde» de Chris Pine


22

Je suis un mentor chez RubyLearning et l'un des exercices que nous donnons à nos élèves est l'exercice «Sourde grand-mère» du livre de Chris Pine « Apprendre à programmer ». Voici la description:

Écrivez un programme sur la grand-mère sourde. Quoi que vous disiez à grand-mère (quoi que vous tapiez), elle devrait répondre par: "Hein?! Parlez, mon fils!", À moins que vous ne le criiez (tapez toutes les capitales). Si vous criez, elle peut vous entendre (ou du moins elle le pense) et crie: "Non, pas depuis 1938!"

Pour rendre votre programme vraiment crédible, demandez à grand-mère de crier une année différente à chaque fois; peut-être n'importe quelle année au hasard entre 1930 et 1950. (Cette partie est facultative, et serait beaucoup plus facile si vous lisez la section sur le générateur de nombres aléatoires de Ruby à la fin du chapitre sur les méthodes.) Vous ne pouvez pas arrêter de parler à grand-mère jusqu'à ce que vous criez "BYE".

Après plusieurs itérations de cours, j'ai essayé de voir à quel point je pouvais obtenir cela et maintenant le réduire à 112 caractères:

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

Je suis curieux de voir combien de personnages cela peut être réalisé dans la langue de votre choix, car je pense que Ruby se débrouille déjà très bien ici.

Edit: La solution Perl publiée ci-dessous a conduit à

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

qui est de 92 caractères pour l'expression + 2 autres pour les options net l.


Dans un contexte de golf, cela nécessite des spécifications supplémentaires. Que devrait-il se passer en cas de sortie supplémentaire après BYE?
JB

Seul "BYE" termine exactement le programme.
Michael Kohl

Réponses:


13

Perl, 85 91

Exécuter avec perl -nE '<code goes there>'( ncompté dans la taille du programme):

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

Ce point d'exclamation final est très cher ...

Modifications suggérées par IK:

  • L'utilisation d'une expression rationnelle au lieu d'une correspondance de chaîne épargne l' -loption globale ainsi que deux caractères de programme: -3.
  • Utiliser une variable réelle pour enregistrer une valeur et l'utiliser plus tard pour l'interpolation (Génie! Qui aurait pensé utiliser une variable pour cela?): 0.
  • Rendre cette variable $=, contrainte d'être un entier: -4.

(et ça ne s'additionne toujours pas et j'ai trop sommeil pour savoir pourquoi. Oh bien, le décompte final est juste au moins)


Abuser $=et utiliser une expression rationnelle pour "BYE" le perl -nE '$==1930+rand 21;say/^BYE$/?last:uc eq$_?"NO, NOT SINCE $=!":"HUH?! SPEAK UP, SONNY!"'
ramène

@IlmariKaronen Integrated, merci!
JB

6

Python 120 caractères

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

Des conseils pour améliorer?


Vous n'avez pas besoin des crochets autour de cette instruction if, je suis également sûr que python a un plafond de récursivité - mais cela pourrait simplement simuler votre grand-mère qui s'endort.
Phoshi

Oh! J'ai oublié de retirer les crochets. Merci :)
fR0DDY

Vous pouvez enregistrer certains caractères si vous supprimez la première ligne, remplacez la seconde par s='', réorganisez vos instructions dans votre boucle while et placez la boucle while entière sur une seule ligne: gist.github.com/3787809 Si vous étiez vraiment déterminé, vous pourriez enregistrer 2 caractères en utilisant python 3 (raw_input () -> input (), mais print -> print ())
Matt

4

131 caractères dans 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 / espace blanc:

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

Resserré 18 caractères de la suggestion de Joey.

BTW, «Learn to Program» a été le premier livre de programmation que j'ai lu de bout en bout.


Vous voudrez peut-être jeter un oeil ici: codegolf.stackexchange.com/questions/191/…
Joey

Vous pouvez le réduire à 120 en écrasant le premier if...dans le contrôle conditionnel du même for()type: for(;($j=read-host)-cne"BYE"){if($j-ceq$j.ToUpper()){...En outre, la spécification dit 1930-1950.
SpellingD

3

C # - 234 caractères

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

Plus lisible:

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

J'en ai manqué quelques simples dans le mien et j'ai fait quelques bêtises. Nice +1
Kyle Rozendo

3

Befunge - 27x6 = 162 caractères

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

EDIT: complètement raté la partie "BYE". Nouvelle version bientôt disponible.

EDIT 2: En fait, cela rend un peu trop complexe pour mes maigres compétences Befunge. Je pourrais réessayer plus tard, mais je ne pense pas à un moyen simple de le mettre en œuvre pour le moment.


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

Avec des espaces blancs:

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

Avec une certaine inspiration de Nellius et fR0DDY.

Veuillez me faire savoir si cela peut être amélioré.


Bref, mais FWIW, je pense que cela fuit (appel récursif Main()). De plus, je pense que vous voulez des parens dans l' ?:expression pour obtenir les !deux. J'ai ajouté une réponse avec ceci et EOL (mais fuit toujours).
pc

je vois que vous avez ajouté les parens et supprimé votre commentaire. Bon travail. Maintenant, ma modification pour ajouter des captures d'écran à ma réponse avec et sans les parens est sans objet. (Mais toujours étanche) :-)
bw

@bill Oui, j'ai foiré mes tests au départ. La version sans fuite serait de 199 caractères, trop longue :)
Richard

Ha. J'aime la Main();solution ... aucune personne sensée n'utiliserait ce programme assez longtemps pour que ce soit un problème.
pc

Comme Phoshi l'a dit dans le commentaire à fR0DDY. Le programme se bloque lorsque grand-mère s'endort.
Richard

3

D: 246 caractères

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

Plus lisiblement:

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 caractères, 29 d'entre eux effectuent une année au hasard

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 caractères

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

3

Windows PowerShell, 121 117

En raison de la nature de la tâche, cela semble à peu près identique à la solution de Ty Auvil , bien qu'elle ait été écrite indépendamment:

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

Merci à SpellingD pour la suggestion,


J'aime votre correspondance regex, mais l'instruction switch est très volumineuse. Parallèlement à la suggestion que j'ai faite à Ty, vous pouvez réduire le nombre de vos personnages à 117 en utilisant l'expression régulière avec à la ifplace comme ceci: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 ans)

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

La chose étrange est que le code Haskell est généralement beaucoup plus court que le code C comparable lors de l'écriture d'un programme «sérieux».


Vous pouvez éviter d'importer Charen utilisant any(`elem`['a'..'z'])spour tester les lettres minuscules.
hammar

2

APL (76)

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

1

C # - 345 caractères

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

Merde verbeuse ... :-)


1
Vous pouvez appeler la classe juste P. Et cela ne détecte pas correctement les majuscules. Je peux lui crier dessus et il ne m'entend toujours pas. Vous pouvez raccourcir la méthode principale en while(t(Console.ReadLine()));. Vous pouvez utiliser using C=System.Console;au début pour raccourcir l'accès à ReadLine()et WriteLine()à C.ReadLine()et C.WriteLine().
Joey

@Joey - Merci pour les conseils!
Kyle Rozendo

1

C # - 196 caractères (mais qui fuient)

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

C'est la réponse de @ Richard (qui fuit) avec deux parens (voir ci-dessous) et un \ n ajouté pour obtenir la fin de vie dans les deux cas. Sinon, l' " + "espace est juste gaspillé.

Formaté

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

MISE À JOUR: pour clarifier mon commentaire sur les parens nécessaires, voici ce que j'obtiens sans les parens (c'est-à-dire avec la solution originale de @ Richard):

sans parens

Et avec les parens:

avec parens

Aucun de ceux-ci n'utilise cependant mon supplément \n.


C'est 195 ici, seulement. Avez-vous compté un saut de ligne inutile à la fin?
Joey

1

Bash: 136128 caractères

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

Alternative limitée: 132 123 caractères

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

Vous pouvez parler à un sourd à l'infini, mais la conversation avec ce code ultérieur est limitée par la pile d'appels. (Dans mon test, il se termine après 4989 appels.)


1

Javascript - 133 131 130 128 127 121 caractères

version golfée de la solution 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: enregistré six autres caractères avec ce bon conseil


Écrivez l'opérateur ternaire comme g=/[a-z]/.test(i)?'Huh?!...':'No...'et vous épargnez 2 caractères.
manatwork

Modifié, merci pour le pointeur.
codeporn

1
1 caractère de plus que j'ai trouvé: Math.ceil()est plus court que Math.floor(). Il suffit de changer l'année de base pour maintenir l'intervalle inchangé: Math.ceil(Math.random()*21+1929).
manatwork

Génial, +1! J'ai enregistré deux autres caractères en changeant le while en une boucle for.
codeporn

0

Clojure - 160 154 caractères

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

Travailler sur le golf un peu plus. Suggestions bienvenues.

Parcourez REPL


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

usage

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
'
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.