ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
def granny_says(str) str.each_byte do |byte| print byte.chr sleep 0.01 STDOUT.flush end puts STDOUT.flush end loop do granny_says("<Intermediary> Got a question for Granny? Make sure to" ) granny_says(" input yo' question in all caps, or else" ) granny_says(" granny can't hear ya'!\n" ) reply = gets.chomp if (reply == reply.upcase) random = rand(21) + 1930 granny_says("\n<Granny> No, not since #{random}! ... that's all the time" ) granny_says(" I've got, child! Hasta la-bye-bye, baby!\n\n" ) granny_says("<Intermediary> Granny's a bit hard of hearing today. I" ) granny_says(" apologize. Ya' may have to say \"bye\" a" ) granny_says(" few times for her to understand y'are" ) granny_says(" leaving, since it's rude to leave with-" ) granny_says(" out biddin' yo' adieus. 3 times just" ) granny_says(" might do it! In a row, even!\n\n" ) goodbyes = 0 while goodbyes != 3 you_say = gets.chomp if (you_say == "BYE") then goodbyes = goodbyes + 1 else goodbyes = 0 end if (goodbyes == 1) granny_says("\n<Intermediary> That's once!\n\n" ) elsif (goodbyes == 2) granny_says("\n<Intermediary> That's twice!\n\n" ) elsif (goodbyes == 3) granny_says("\n<Intermediary> That's thrice! That should do it!\n") else granny_says("\n<Intermediary> That's either not in caps, not an adieu") granny_says(" or neither. How 'bout 'ya try that again?\n") end end granny_says("\n<Granny> I'm not dense, youngin'! I heard you the" ) granny_says(" first time! I... CAN... HEAR... JUST..." ) granny_says(" FINE. The nerve of you, child! I oughta" ) granny_says(" bust your little ass!\n\n" ) granny_says("<Intermediary> Ya' sure did do a fine job of pissin'" ) granny_says(" off yo' granny, didn't 'ya? If 'ya" ) granny_says(" wanna talk with her again, schedule" ) granny_says(" an appointment with me later on in" ) granny_says(" in the week. Give her some time to" ) granny_says(" cool off. Talk to 'ya then!" ) break else granny_says("\n<Intermediary> Granny can't hear 'ya! Wanna know why?" ) granny_says(" 'Cause that wasn't in all caps, yo'!" ) granny_says(" So, I'll repeat what I said before ...\n\n" ) end end
Refactorings
No refactoring yet !
Maciej Piechotka
July 29, 2008, July 29, 2008 20:28, permalink
Only what within the task. You can change puts into whatever you want.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
count_bye = 0 loop do word = gets.chomp if word == "BYE" count_bye += 1 if count_bye == 3 puts "Bye son." break end else count_bye = 0 end if word != "BYE" and word.upcase == word puts "No. Not since #{1930 + rand(21)}." else puts "I cannot hear you son!" end end
Wolfbyte
July 30, 2008, July 30, 2008 01:40, permalink
Hey, welcome to ruby. I'm not sure where the tutorial puts you in the grand scheme of things but the below is a re-imagining of the original problem. It's less conversant that your one but the structure is nice and easy to read.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
def granny_can_hear( message ) message.upcase == message end def ask_user_to_speak_up puts "Huh?! Speak up, sonny!" end consecutive_goodbyes = 0 while consecutive_goodbyes < 3 do print "> " what_you_said = gets.chomp if what_you_said == "BYE" consecutive_goodbyes += 1 if consecutive_goodbyes < 3 ask_user_to_speak_up end else consecutive_goodbyes = 0 if granny_can_hear what_you_said puts "No, not since #{rand(21) + 1930}!" else ask_user_to_speak_up end end end puts "See you later sonny"
Wolfbyte
July 30, 2008, July 30, 2008 01:41, permalink
Hey, welcome to ruby. I'm not sure where the tutorial puts you in the grand scheme of things but the below is a re-imagining of the original problem. It's less conversant that your one but the structure is nice and easy to read.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
def granny_can_hear( message ) message.upcase == message end def ask_user_to_speak_up puts "Huh?! Speak up, sonny!" end consecutive_goodbyes = 0 while consecutive_goodbyes < 3 do print "> " what_you_said = gets.chomp if what_you_said == "BYE" consecutive_goodbyes += 1 if consecutive_goodbyes < 3 ask_user_to_speak_up end else consecutive_goodbyes = 0 if granny_can_hear what_you_said puts "No, not since #{rand(21) + 1930}!" else ask_user_to_speak_up end end end puts "See you later sonny"
houston b-g
July 30, 2008, July 30, 2008 18:37, permalink
@Wolfbyte — That's a whole lot cleaner & easier to read than the original. Only thing is, it's void of the one thing that would set it apart from the next person reading the tutorial & doing the exercise -- expanded dialect. Although, perhaps I should be more worried about /learning/ the fundamentals, rather than spending all my energy making the program "believable", per se.
However, as is, the lack of conversation leaves you wondering what exactly you should be doing. Especially come time to say "BYE" three times. Of course, it's just an example & you could've refactored it to serve as a jumping off point for a complete re-vamp of the entire program.
Regardless, I guess I don't give the people who would sit down & run the program much credit -- I don't think that many people would know to type in all caps when Granny says, "Huh!? Speak up, sonny!" Therefore, I implemented the Intermediary to explain how Granny works. Maybe I put too much thought into it & should've taken the exercise from a different, less expansive angle, but I didn't.
Anyways, thank you! I'll look over the code & implement what I can into the re-vamp of the original. It's appreciated.
@Maciej Piechotka — Thank you for the refactor. Like Wolfbyte's, it's a lot more cleaner & readable than the original, but still lacks a lot of the stuff I spoke about in my spiel to Wolfbyte. I appreciate it, though.
Maciej Piechotka
July 30, 2008, July 30, 2008 18:55, permalink
@Wolfbyte - to keep the ruby convention: 'granny_can_hear' shouldn't be named 'granny_hear?'?
Wolfbyte
July 31, 2008, July 31, 2008 12:55, permalink
@houston b-g - You are correct that our versions are a little terse but I think we probably had different target audiences in mind. Whereas you were coding a solution for an end-user, Maciej Piechotka and I were targeting our response at you (someone who was reading the code). My original solution (which I didn't post) had all of granny's dialogue (and that of the intermediary) separated out into different methods so that you'd retain the whole program with the essence of the structure intact. For the sake of not hiding the forrest (the structure) behind the trees (the prose) a lot of it got excised out. The ask_user_to_speak_up message is all that remains.
I've often found the best thing when trying to deal with a complicated section of program logic is to remove as much of the program from consideration as you can until you have just enough to remind your brain how everything fits together. If appropriate you can add in all of the other stuff later (but you'll usually keep it abstracted away).
houston b-g
July 31, 2008, July 31, 2008 20:08, permalink
@Wolfbyte - You're absolutely correct about removing much of the program to have just enough so I can get my head around how everything fits together as the best way to deal with sections of complicated program logic. I've started doing this (as of mid-day yesterday) & it's helping me out considerably. I've gotta look at the forest as a whole before I work out its specific flora. :-)
Wolfbyte
August 1, 2008, August 01, 2008 03:11, permalink
@Maciej Piechotka - Yep you're right. It's a hazard switching from ruby to C# and back again all the time.
I also had this version which is pretty compact but probably not one I'd use. It rolls the loop slightly so that the Speak Up message is printed at the top based on the last thing said. It does this with the binard heard variable which gets reset to false whenever you say something until granny hears you. To deal with this on the first iteration it fakes granny having heard something. I wouldn't use it in production because I think it's confusing but it does do the job.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
byes, heard = 0, true while byes < 3 do puts "Huh?! Speak up, sonny!" unless heard print "> " what_you_said, heard = gets.chomp, false if what_you_said == "BYE" byes += 1 else byes = 0 heard = what_you_said.upcase == what_you_said puts "No, not since #{rand(21) + 1930}!" if heard end end puts "See you later sonny"
Laurel
August 7, 2008, August 07, 2008 15:05, permalink
Ruby has a ton of different ways to do string literals:
http://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html
For really long or multiline strings "here documents" can be the way to go:
1 2 3 4 5 6 7 8
def ask_user_to_speak_up granny_says <<EOS <Intermediary> Granny can't hear 'ya! Wanna know why? 'Cause that wasn't in all caps, yo'! So, I'll repeat what I said before ... EOS end
Martin
October 8, 2008, October 08, 2008 01:09, permalink
Hey, just started reading this book yesterday. I made the program and googled to see if anyone else had so I could compare :)
This is what I ended up with, how did I do?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
question = "starting question" bye = 0 while bye < 3 puts "Ask granny a question..." question = gets.chomp decade = (3 + rand(2)).to_s year = rand(10).to_s if question == question.upcase && question != "BYE" puts "NO, NOT SINCE 19" + decade + year + "!" bye = 0 else if question == "BYE" bye = bye + 1 else bye = 0 end if bye == 3 puts "OH OK DEARY! BYE BYE X" else puts "HUH!? SPEAK UP, SONNY!" end end end
Martin
October 8, 2008, October 08, 2008 01:32, permalink
After looking at it again after a short break I noticed some obvious improvements for my code, I dont know why I did the random number that way! and the initial question value was because in an earlier attempt I had used question != "BYE" in my while loop. Here is the shortened version...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
bye = 0 while bye < 3 year = rand(21) + 1930 puts "Ask granny a question..." question = gets.chomp if question == question.upcase && question != "BYE" puts "NO, NOT SINCE " + year.to_s + "!" bye = 0 else if question == "BYE" bye = bye + 1 else bye = 0 end if bye == 3 puts "OH OK DEARY! BYE BYE X" else puts "HUH!? SPEAK UP, SONNY!" end end end
I've been working on this program for a few days now. I'm fairly new to Ruby (a little under a week into learning it) & have been following Chris Pine's "Learn to Program" tutorial, which covers various fundamental aspects of Ruby. The following was the exercise the program was written for:
• Write a Deaf Grandma program. Whatever you say to grandma (whatever you type in), she should respond with "Huh?! Speak up, sonny!", unless you shout it (type in all capitals). If you shout, she can hear you (or at least she thinks so) and yells back, "No, not since 1938! To make your program really believable, have grandma shout a different year each time; maybe any year at random between 1930 and 1950. (This part is optional, and would be much easier if you read the section on Ruby's random number generator at the end of the methods chapter.) You can't stop talking to grandma until you shout "BYE".
• Extend your Deaf Grandma program: What if grandma doesn't want you to leave? When you shout "BYE", she could pretend not to hear you. Change your previous program so that you have to shout "BYE" three times in a row. Make sure to test your program: if you shout BYE three times, but not in a row, you should still be talking to grandma.
Now, I've satisfied every requirement the exercise ascertained. But, I've been told that the indentation is funky & that the print statements could be shortened. Most significant is the fact that I seem to have "one loop too many," but I'm unsure of where it is & how to fix it. If anyone can refactor this one for me, & give me a brief explanation as to what you did, I'd appreciate it. Thanks in advance.
—houston b-g