«Глухая бабушка» Криса Пайна


22

Я наставник в RubyLearning, и одним из упражнений, которое мы даем нашим студентам, является упражнение «Глухая бабушка» из книги Криса Пайна « Учись программировать ». Вот описание:

Написать программу «Глухая бабушка». Что бы вы ни сказали бабушке (что бы вы ни печатали), она должна ответить: «Да ?! Говори, сынок!», Если только ты не кричишь (набери все заглавные буквы). Если вы кричите, она слышит вас (или, по крайней мере, она так думает) и кричит в ответ: «Нет, не с 1938 года!»

Чтобы ваша программа была правдоподобной, каждый раз, когда бабушка кричит по-разному; может быть, любой случайный год между 1930 и 1950 годами. (Эта часть не обязательна, и будет намного проще, если вы прочитаете раздел о генераторе случайных чисел Руби в конце главы, посвященной методам.) Вы не можете перестать разговаривать с бабушкой, пока не кричать "пока".

После нескольких итераций курса я попытался увидеть, насколько маленьким я могу это получить, и теперь я сократил его до 112 символов:

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

Мне любопытно увидеть, как мало символов можно достичь на выбранном вами языке, потому что я думаю, что у Руби уже все хорошо.

Редактировать: решение Perl, опубликованное ниже, привело к

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

что составляет 92 символа для выражения + еще 2 для параметров nи l.


В контексте игры в гольф это требует дополнительных уточнений. Что должно произойти, если есть какой-либо дополнительный вывод после BYE?
JB

Только «BYE» точно завершает программу.
Майкл Коль

Ответы:


13

Perl, 85 91

Запустить с perl -nE '<code goes there>'( nсчитается в размере программы):

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

Этот восклицательный знак очень дорогой ...

Изменения, предложенные IK:

  • Использование регулярного выражения вместо совпадения строк освобождает -lглобальный параметр, а также два символа программы: -3.
  • Использование фактической переменной для сохранения значения и последующего его использования для интерполяции (Genius! Кто бы мог подумать об использовании переменной для этого?): 0.
  • Делаем эту переменную $=, ограниченную целым числом: -4.

(и это все еще не складывается, и я слишком сонный, чтобы выяснить, почему. Ну хорошо, окончательный счет, по крайней мере, правильный)


Злоупотребление $=и использование регулярного выражения для "BYE" приводит к снижению до 84 + 1:perl -nE '$==1930+rand 21;say/^BYE$/?last:uc eq$_?"NO, NOT SINCE $=!":"HUH?! SPEAK UP, SONNY!"'
Илмари Каронен

@IlmariKaronen Комплексная, спасибо!
JB

6

Python 120 символов

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

Любые советы по улучшению?


Вам не нужны скобки вокруг этого оператора if, я также уверен, что python имеет рекурсивный потолок - но это может просто имитировать засыпание вашей бабушки.
Фоши

Ой! Я забыл снять скобки. Спасибо :)
fR0DDY

Вы можете сохранить некоторые символы, если удалите первую строку, замените вторую на s='', переупорядочите свои выражения в цикле while и поместите весь цикл while в одну строку: gist.github.com/3787809 Если вы действительно настроены, вы можете сохранить 2 символа с помощью Python 3 (raw_input () -> input (), но print -> print ())
Matt

4

131 символ в 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!"}}

С пробелами:

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

Выжал 18 символов из предложения Джои.

Кстати, «Учись программировать» была первой книгой по программированию, которую я когда-либо читал на обложке.


Возможно, вы захотите взглянуть сюда: codegolf.stackexchange.com/questions/191/…
Джои,

Вы можете уменьшить это значение до 120, дав первое if...в условную проверку, for()например, так: for(;($j=read-host)-cne"BYE"){if($j-ceq$j.ToUpper()){...в спецификации написано 1930-1950.
SpellingD

3

C # - 234 символа

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

Более читабельно:

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

Ах пропустил несколько простых в моей, и сделал несколько глупых ошибок. Ницца +1
Кайл Розендо

3

Befunge - 27x6 = 162 персонажа

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

РЕДАКТИРОВАТЬ: Полностью пропустил "BYE" часть. Скоро выйдет новая версия.

РЕДАКТИРОВАТЬ 2: На самом деле, это делает его слишком сложным для моих скудных навыков Befunge. Я мог бы попробовать позже, но я не могу придумать какой-либо простой способ реализовать это в данный момент.


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

С пробелами:

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

С вдохновением от Неллиуса и fR0DDY.

Пожалуйста, дайте мне знать, если это можно улучшить.


Короче говоря, но FWIW, я думаю, что это утечка (рекурсивный вызов Main()). Кроме того, я думаю, что вы хотите, чтобы в ?:выражении присутствовали символы «паренс» !. Я добавил ответ с этим и EOL (но все еще утечки).
м.т.

я вижу, вы добавили парены и удалили свой комментарий. Отличная работа. Теперь мое изменение, чтобы добавить скриншоты к моему ответу с и без паренов, является спорным. (Но все еще дырявый) :-)
bw

@ билл Да, я сначала провалил тестирование. Версия без утечек будет 199 символов, очень долго :)
Ричард

га. Мне нравится Main();решение ... ни один здравомыслящий человек не использовал бы эту программу достаточно долго, чтобы она стала проблемой.
м.т.

Как сказал Фоши в комментарии к fR0DDY. Программа вылетает, когда бабушка засыпает.
Ричард

3

D: 246 символов

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

Более разборчиво:

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 символа, 29 из них выполняют произвольный год

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 символов

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

3

Windows PowerShell, 121 117

Из-за характера задачи это выглядит в значительной степени идентично решению Ty Auvil , хотя оно было написано независимо:

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

Спасибо SpellingD за предложение,


Мне нравится ваше соответствие регулярному выражению, но оператор switch довольно громоздкий. Наряду с предложением, которое я дал Тай, вы можете уменьшить количество своих персонажей до 117, используя регулярное выражение ifвместо этого: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

Хаскелл (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

Странно то, что при написании «серьезной» программы код на Haskell обычно намного короче, чем сопоставимый код на C.


Вы можете избежать импорта Char, используя any(`elem`['a'..'z'])sдля проверки строчных букв.
Хаммар


1

C # - 345 символов

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

Чертовски многословный язык ... :-)


1
Вы можете позвонить в класс просто P. И это не правильно определяет прописные буквы. Я могу кричать на это, и он все еще не слышит меня. Вы можете сократить основной метод до while(t(Console.ReadLine()));. Вы можете использовать using C=System.Console;в начале , чтобы сократить доступ к ReadLine()и WriteLine()к C.ReadLine()и C.WriteLine().
Джои

@Joey - Спасибо за советы!
Кайл Розендо

1

C # - 196 символов (но дырявый)

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

Это ответ Ричарда (прохудившийся) с двумя паренами (см. Ниже) и добавлением \ n, чтобы получить EOL в обоих случаях. В противном случае " + "это просто пустое пространство.

отформатирован

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

ОБНОВЛЕНИЕ: чтобы уточнить мой комментарий о необходимых паренонах, вот что я получаю без паренов (то есть с оригинальным решением @ Richard):

без паренов

И с парнями:

с паренс

Ни один из них не использует мой дополнительный \nхотя.


Здесь только 195. Вы посчитали ненужный разрыв строки в конце?
Джои

1

Баш: 136 128 символов

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

Ограниченная альтернатива: 132 123 символа

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

Вы можете общаться с глухими бесконечно, но разговор с этим более поздним кодом ограничен стеком вызовов. (В моем тесте он завершается после 4989 звонков.)


1

Javascript - 133 131 130 128 127 121 символов

версия решения 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)+'!');

Редактировать: Сохранено еще шесть символов с этим большим советом


Напишите троичный оператор как g=/[a-z]/.test(i)?'Huh?!...':'No...'и вы сэкономите 2 символа.
Манатур

Отредактировано, спасибо за указатель.
codeporn

1
Еще 1 символ, который я нашел: Math.ceil()короче Math.floor(). Просто измените базовый год, чтобы сохранить интервал без изменений Math.ceil(Math.random()*21+1929).
manatwork

Отлично, +1! Я сохранил еще два символа, изменив цикл while.
codeporn

0

Clojure - 160 154 персонажа

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

Работать над гольфом это немного больше. Предложения приветствуются.

Запустить через 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!"]]}

использование

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
'
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.