Chris Pine'ın “Sağır Büyükanne”


22

RubyLearning'de danışmanım ve öğrencilerimize verdiğimiz alıştırmalardan biri, Chris Pine'ın " Programlamayı Öğren " kitabındaki "Sağır Büyükanne" alıştırması . İşte açıklaması:

Bir Sağır Büyükanne programı yazın. Büyükannene ne söylersen söylesin (ne yazarsın), cevap vermeli: "Huh ?! Konuş, evlat!", Diye bağırmadığın sürece (tüm harfleri yaz). Bağırırsanız, sizi duyabilir (ya da en azından öyle düşünüyor) ve geri bağırır: "Hayır, 1938'den beri değil!"

Programınıza gerçekten inandırıcı yapmak için, büyükannenin her seferinde farklı bir yıl bağırmasını sağlayın; 1930 ve 1950 yılları arasında rastgele herhangi bir yıl olabilir. (Bu bölüm isteğe bağlıdır ve yöntemler bölümünün sonunda Ruby'nin rasgele sayı üreteci bölümünü okursanız çok daha kolay olurdu.) Size kadar büyükannenizle konuşmayı durduramazsınız. "BYE" diye bağır.

Birkaç ders tekrarından sonra bunu ne kadar küçük alabileceğimi görmeye çalıştım ve şimdi 112 karaktere düşürdüm:

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

Bunun, seçtiğiniz dilde kaç karaktere ulaşılabileceğini görmek merak ediyorum, çünkü Ruby'nin burada gerçekten çok başarılı olduğunu düşünüyorum.

Düzenleme: aşağıda yayınlanan Perl çözümü yol açtı

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

ifadesi için 92 karakterdir nve lseçenekler için + 2 .


Bir golf bağlamında, bu ek şartname gerektirir. BYE'den fazla bir çıktı varsa ne olur?
JB

Yalnızca "BYE" programı tam olarak sonlandırır.
Michael Kohl,

Yanıtlar:


13

Perl, 85 91

Şununla çalıştırın perl -nE '<code goes there>'( nprogram boyutunda sayılır):

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

Bu sondaki ünlem işareti çok pahalı ...

IK tarafından önerilen düzenlemeler:

  • Bir dizge eşleşmesi yerine bir regexp kullanmak, -lgenel seçeneği ve iki program karakterini korur: -3.
  • Bir değeri kaydetmek için gerçek bir değişkeni kullanmak ve enterpolasyon için daha sonra kullanmak (Genius! Bunun için bir değişken kullanmayı kim düşünebilirdi?): 0.
  • Bu değişkeni yapmak, $=bir tamsayı olarak sınırlandırılmış: -4.

(ve hala toplanmıyor ve nedenini bulmak için çok uykum var. Oh, son sayım en azından doğru)


$="BYE" için bir regexp kötüye kullanma ve kullanma bunu 84 + 1'e indirdi:perl -nE '$==1930+rand 21;say/^BYE$/?last:uc eq$_?"NO, NOT SINCE $=!":"HUH?! SPEAK UP, SONNY!"'
Ilmari Karonen 28:12

@IlmariKaronen Entegre, teşekkürler!
JB

6

Python 120 Karakterler

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

Geliştirmek için herhangi bir ipucu var mı?


Bunun etrafındaki köşeli parantezlere ihtiyacınız yok, ayrıca pitonun özyinelemeli bir tavanı olduğundan da eminim - ama bu büyükannenizin uykuya daldığını taklit edebilir.
Phoshi

Ah! Destekleri çıkarmayı unuttum. Thanks :)
fR0DDY

İlk satırı kaldırırsanız, bazı karakterleri kaydedebilir, ikincisini değiştirebilir, s=''ifadelerinizi while döngüsünde yeniden düzenleyebilir ve while while döngüsünü bir satıra yerleştirebilirsiniz: gist.github.com/3787809 Gerçekten kararlıysanız, python 3 (raw_input () -> input () kullanarak 2 karakter kaydedin, ancak yazdırın -> print ())
Matt

4

PowerShell'de 131 karakter:

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 / boşluk:

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

Joey'in önerisinden 18 karakter sıkılmış.

BTW, 'Programlamayı Öğrenin', kapsayacak kapağı okuduğum ilk programlama kitabıydı.


Burada bir göz atmak isteyebilirsiniz: codegolf.stackexchange.com/questions/191/…
Joey

Bunu if..., for()benzerinin şartlı kontrolüne birinciye bölerek 120'ye çıkarabilirsiniz : for(;($j=read-host)-cne"BYE"){if($j-ceq$j.ToUpper()){...Ayrıca, teknik özellik 1930-1950 diyor.
SpellingD

3

234 Karakter

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

Daha okunabilir:

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

Ah benim birkaç basit olanı kaçırdı ve aptalca hatalar yaptı. Güzel +1
Kyle Rozendo

3

Befunge - 27x6 = 162 karakter

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

EDIT: Tamamen "BYE" bölümünü kaçırdı. Yeni sürüm çok yakında.

EDIT 2: Aslında, bu benim zayıf Befunge yeteneklerim için biraz fazla karmaşık hale getiriyor. Daha sonra tekrar deneyebilirim, ancak şu anda uygulamanın basit bir yolunu düşünemiyorum.


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

Beyaz boşluklarla:

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 ve fR0DDY’den ilham aldı.

Lütfen geliştirilebilirse bana bildirin.


Kısa, ama FWIW, bence bu sızıntı (tekrarlayarak çağırıyor Main()). Ayrıca, ?:ifadedeki parens'in !ikisini de almasını istediğinizi düşünüyorum . Buna ve EOL'ye bir cevap ekledim (ama hala sızıyor).
bw

Gördüğüm gibi parenleri eklediniz ve yorumunuzu kaldırdınız. Aferin. Şimdi ekran görüntüsü eklemek için yaptığım düzenleme parens ile olan ve olmayan cevaplarıma göre. (Ama yine de sızdıran) :-)
bw

@bill Evet, başlangıçta testlerimi bozdum. Sızdıran olmayan sürüm 199 karakter, çok uzun süre beklemek :)
Richard

Ha. Main();Çözümü severim ... Aklı başında hiç kimse bu programı problem yaratacak kadar uzun süre kullanmaz.
bw

Phoshi'nin dediği gibi yorumunda fR0DDY. Büyükannem uykuya daldığında program çöküyor.
Richard,

3

D: 246 Karakterler

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

Daha okunaklı:

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 karakter, 29'u rastgele yıl gerçekleştirir

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 karakter

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

3

Windows PowerShell, 121 117

Görevin doğası gereği, bu, bağımsız bir şekilde yazılmış olmasına rağmen, Ty Auvil'in çözümüyle hemen hemen aynı görünüyor :

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

Öneri için SpellingD teşekkürler,


Regex eşlemenizi beğendim, ancak switch ifadesi çok hantal. Ty'a verdiğim öneriyle birlikte, ifbunun yerine regex kullanarak karakter sayınızı 117'ye düşürebilirsiniz :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

İşin garibi, Haskell kodu genellikle 'ciddi' bir program yazarken karşılaştırılabilir C kodundan çok daha kısa.


Küçük harfleri test etmek için Charkullanarak ithalattan kaçınabilirsiniz any(`elem`['a'..'z'])s.
Hammar

2

APL (76)

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

1

345 Karakter

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

Lanet olası ayrıntılı dil ... :-)


1
Sadece sınıfı arayabilirsin P. Ve bu, büyük harfleri doğru algılamıyor. Buna bağırabilirim ve hala beni duyamıyor. Ana yöntemi kısaltabilirsiniz while(t(Console.ReadLine()));. Sen kullanabilirsiniz using C=System.Console;erişimi kısaltmak başında ReadLine()ve WriteLine()hiç C.ReadLine()ve C.WriteLine().
Joey,

@Joey - İpuçları için teşekkürler!
Kyle Rozendo

1

196 karakter (ancak sızdıran)

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

Bu, @ Richard'ın (sızdıran) iki parenli (aşağıya bakınız) cevabı ve her iki durumda da EOL'yi almak için buraya eklendi. Aksi takdirde " + "sadece boşa harcanır.

biçimlendirilmiş

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

GÜNCELLEME: ihtiyaç duyulan parenler hakkındaki yorumumu açıklığa kavuşturmak için, parens olmadan aldığım (işte @ Richard'ın orijinal çözümüyle):

parens olmadan

Ve parens ile:

parens ile

Bunların hiçbiri benim ek \nolsa kullanın .


Burada sadece 195. Sonunda gereksiz bir satır sonu saydınız mı?
Joey

1

Bash: 136 128 karakter

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

Sınırlı alternatif: 132 123 karakter

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

Sonsuza dek sağırla konuşabilirsiniz, ancak daha sonra bu kodla yapılan konuşma çağrı yığını ile sınırlıdır. (Testimde 4989 çağrıdan sonra sonlandırılıyor.)


1

Javascript - 133 131 130 128 127 121 karakter

www0z0ks çözümünün golf versiyonu

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)+'!');

Düzenleme: Bu harika ipucuyla altı karakter daha kaydetti


Üçlü operatörü yazın ve g=/[a-z]/.test(i)?'Huh?!...':'No...'2 karakter ayırın .
Manat çalışması

İşaretçi için teşekkürler.
codeporn

1
Bulduğum 1 karakter daha: Math.ceil()daha kısa Math.floor(). Sadece aralık değişmeden tutmak için baz yılı değiştirin: Math.ceil(Math.random()*21+1929).
Manatwork

Harika, +1! Süreyi for döngüsüne değiştirerek iki karakter daha kaydettim.
codeporn

0

Clojure - 160 154 Karakterler

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

Biraz daha golf oynamak için çalışıyorum. Önerilerinizi bekliyoruz.

REPL üzerinden koş


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

kullanım

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
'
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.