„Głucha babcia” Chrisa Pine'a

22

Jestem mentorem w RubyLearning, a jednym z ćwiczeń, które wykonujemy dla naszych uczniów, jest ćwiczenie „Głucha babcia” z książki Chrisa Pine'a „ Naucz się programować ”. Oto opis:

Napisz program dla głuchoniemych babć. Cokolwiek powiesz babci (cokolwiek wpiszesz), powinna odpowiedzieć: „Hę ?! Mów, synku!”, Chyba że krzykniesz (wpisz wszystkie wielkie litery). Jeśli krzyczysz, słyszy cię (a przynajmniej tak jej się wydaje) i krzyczy: „Nie, nie od 1938 roku!”

Aby twój program był naprawdę wiarygodny, niech babcia za każdym razem krzyczy o innym roku; może w dowolnym roku losowo między 1930 a 1950. (Ta część jest opcjonalna i byłaby o wiele łatwiejsza, gdybyś przeczytał sekcję generatora liczb losowych Ruby na końcu rozdziału metod.) Nie możesz przestać rozmawiać z babcią, dopóki krzycz „BYE”.

Po kilku iteracjach kursu próbowałem zobaczyć, jak mały mogę to uzyskać, a teraz mam do 112 znaków:

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

Jestem ciekawy, jak mało znaków można to osiągnąć w wybranym przez ciebie języku, ponieważ myślę, że Ruby już tutaj ma się naprawdę dobrze.

Edycja: Rozwiązanie Perla opublikowane poniżej doprowadziło do

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

czyli 92 znaki dla wyrażenia + 2 więcej dla opcji ni l.

Michael Kohl
źródło
W kontekście golfa wymaga to dodatkowej specyfikacji. Co powinno się stać, jeśli w BYE pojawi się jakaś produkcja?
JB
Tylko „BYE” dokładnie kończy program.
Michael Kohl,

Odpowiedzi:

13

Perl, 85 91

Uruchom z perl -nE '<code goes there>'( nliczony jako rozmiar programu):

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

Końcowy wykrzyknik jest bardzo drogi ...

Edycje sugerowane przez IK:

  • Użycie wyrażenia regularnego zamiast dopasowania ciągu oszczędza -lopcję globalną, a także dwa znaki programu: -3.
  • Użycie rzeczywistej zmiennej do zapisania wartości i wykorzystanie jej później do interpolacji (Geniusz! Kto by pomyślał o użyciu zmiennej do tego?): 0.
  • Utworzenie tej zmiennej $=, ograniczonej do liczby całkowitej: -4.

(i nadal się nie sumuje, a ja jestem zbyt śpiący, żeby dowiedzieć się, dlaczego. No cóż, przynajmniej ostateczna liczba jest słuszna)

JB
źródło
Nadużycie $=i użycie wyrażenia regularnego dla „BYE” sprowadza to do 84 + 1:perl -nE '$==1930+rand 21;say/^BYE$/?last:uc eq$_?"NO, NOT SINCE $=!":"HUH?! SPEAK UP, SONNY!"'
Ilmari Karonen
@IlmariKaronen Zintegrowane, dzięki!
JB
6

Python 120 znaków

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

Wszelkie wskazówki do poprawy?

fR0DDY
źródło
Nie potrzebujesz nawiasów wokół tej instrukcji if, jestem też pewien, że python ma pułap rekurencji - ale to może po prostu zasnąć twoją babcię.
Phoshi
O! Zapomniałem usunąć wsporniki. Dzięki :)
fR0DDY
Możesz zapisać niektóre znaki, jeśli usuniesz pierwszy wiersz, zamienisz drugi na s='', zmienisz kolejność instrukcji w pętli while i umieścisz całą pętlę while w jednej linii: gist.github.com/3787809 Jeśli naprawdę byłeś zdeterminowany, możesz zapisz 2 znaki, używając Pythona 3 (raw_input () -> input (), ale print -> print ())
Matt
4

131 znaków w 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 / białe znaki:

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

Wyciągnęliśmy 18 znaków z sugestii Joeya.

BTW, „Learn to Program” to pierwsza książka programowa, jaką czytałem od deski do deski.

Ty Auvil
źródło
Możesz zajrzeć tutaj: codegolf.stackexchange.com/questions/191/…
Joey
Możesz sprowadzić to do 120, wciskając pierwszy if...w warunkową kontrolę for()podobnego: tak for(;($j=read-host)-cne"BYE"){if($j-ceq$j.ToUpper()){..., specyfikacja mówi 1930-1950.
SpellingD
3

C # - 234 znaków

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

Bardziej czytelny:

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
źródło
Ah przeoczyłem kilka prostych w swoim i popełniłem głupie błędy. Ładne +1
Kyle Rozendo
3

Befunge - 27x6 = 162 znaków

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

EDYCJA: Całkowicie przegapiłem część „BYE”. Nowa wersja już wkrótce.

EDYCJA 2: Właściwie to sprawia, że ​​jest to trochę zbyt skomplikowane dla moich skromnych umiejętności Befunge. Mogę spróbować ponownie później, ale w tej chwili nie mogę wymyślić żadnego prostego sposobu na jego wdrożenie.

Nemo157
źródło
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();}}}

Z białymi spacjami:

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

Z pewną inspiracją od Nelliusa i fR0DDY.

Daj mi znać, czy można to poprawić.

Richard
źródło
Krótko, ale FWIW, myślę, że to przecieka (rekurencyjne dzwonienie Main()). Ponadto myślę, że chcesz, aby parens w ?:wyrażeniu uzyskały !oba. Dodałem odpowiedź z tym i EOL (ale nadal przecieki).
mc
widzę, że dodałeś pareny i usunąłeś swój komentarz. Dobra robota. Teraz moja edycja dodawania zrzutów ekranu do mojej odpowiedzi z i bez parens jest dyskusyjna. (Ale nadal nieszczelny) :-)
mc
@bill Tak, początkowo pomieszałem swoje testy. Nieszczelna wersja miałaby 199 znaków, aaaaaa za długo :)
Richard
ha. Podoba mi się Main();rozwiązanie ... żadna rozsądna osoba nie używałaby tego programu na tyle długo, aby stanowił problem.
mc
Jak powiedział Phoshi w komentarzu do fR0DDY. Program ulega awarii, gdy babcia zasypia.
Richard
3

D: 246 znaków

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

Bardziej czytelnie:

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
źródło
3

javascript, 142 znaki, 29 z nich wykonuje losowy rok

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
źródło
3

Awk: 97 znaków

$0=="BYE"{exit}$0=toupper($0)==$0?"NO, NOT SINCE "int(rand()*21+1930)"!":"HUH?! SPEAK UP, SONNY!"
człowiek w pracy
źródło
3

Windows PowerShell, 121 117

Ze względu na charakter zadania wygląda to prawie identycznie jak rozwiązanie Ty Auvila , chociaż zostało napisane niezależnie:

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

Dzięki SpellingD za sugestię,

Joey
źródło
Podoba mi się dopasowanie wyrażenia regularnego, ale instrukcja switch jest zdecydowanie nieporęczna. Wraz z sugestią, którą dałem Ty, możesz zmniejszyć liczbę swoich postaci do 117, używając wyrażenia regularnego z następującym ifzamiast tego: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

Dziwne jest to, że kod Haskell jest zwykle dużo krótszy niż porównywalny kod C podczas pisania „poważnego” programu.

marinus
źródło
Możesz uniknąć importowania Char, używając any(`elem`['a'..'z'])sdo testowania małych liter.
hammar
2

APL (76)

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

C # - 345 znaków

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

Cholernie pełny język ... :-)

Kyle Rozendo
źródło
1
Możesz po prostu zadzwonić do klasy P. I to nie wykrywa poprawnie wielkich liter. Mogę na to krzyczeć i wciąż mnie nie słyszy. Możesz skrócić główną metodę do while(t(Console.ReadLine()));. Możesz użyć using C=System.Console;na początku, aby skrócić dostęp do ReadLine()oraz WriteLine()do C.ReadLine()i C.WriteLine().
Joey,
@Joey - Dzięki za wskazówki!
Kyle Rozendo,
1

C # - 196 znaków (ale nieszczelne)

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

To odpowiedź @ (nieszczelna) @ Richarda z dwoma parenami (patrz poniżej) i dodanym tam \ n, aby uzyskać EOL w obu przypadkach. W przeciwnym razie " + "jest to tylko zmarnowane miejsce.

Sformatowany

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

AKTUALIZACJA: aby wyjaśnić mój komentarz na temat potrzebnych parenów, oto co otrzymuję bez parens (tj. Z oryginalnym rozwiązaniem @ Richarda):

bez parens

I z parens:

z parens

Żadne z nich nie korzysta z moich dodatkowych \n.

bw
źródło
Tylko 195 tutaj. Czy na końcu naliczyłeś niepotrzebne przerwanie linii?
Joey,
1

Bash: 136 128 znaków

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

Ograniczona alternatywa: 132 123 znaków

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

Możesz rozmawiać z głuchymi w nieskończoność, ale rozmowa z tym późniejszym kodem jest ograniczona stosem wywołań. (W moim teście kończy się po 4989 połączeniach).

człowiek w pracy
źródło
1

JavaScript - 133 131 130 128 127 121 znaków

golfowa wersja rozwiązania 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)+'!');

Edycja: Zapisałem kolejne sześć znaków dzięki tej wielkiej wskazówce

codeporn
źródło
Napisz operator trójskładnikowy, g=/[a-z]/.test(i)?'Huh?!...':'No...'a oszczędzasz 2 znaki.
manatwork
Edytowane, dziękuję za wskaźnik.
codeporn
1
Znalazłem jeszcze 1 znak: Math.ceil()jest krótszy niż Math.floor(). Wystarczy zmienić rok bazowy zachować odstęp niezmienione Math.ceil(Math.random()*21+1929).
manatwork
Świetnie, +1! Zapisałem kolejne dwa znaki, zmieniając chwile w pętlę for.
codeporn
0

Clojure - 160 154 znaków

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

Trochę więcej gry w golfa. Sugestie mile widziane.

Uruchom przez REPL

MrZander
źródło
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!"]]}

stosowanie

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
'
tartin
źródło