Learn to Program, by Chris Pine

J

Jan_K

Does anyone know where I can find the solutions to the exercises in
this book:

http://pine.fm/LearnToProgram/


I'm stuck in "Flow Control" chapter, specificailly the "Extend Deaf
Grandma" exercise.

I feel like beating the shit out of some punching bag somewhere. Is
this a normal reaction when one is trying to learn to program for the
first time?
 
K

kj WOOLLEY

T24gMjkvMDMvMDYsIEphbl9LIDxub25Abm9uZS5jb20+IHdyb3RlOgpbc25pcF0KPiBJIGZlZWwg
bGlrZSBiZWF0aW5nIHRoZSBzaGl0IG91dCBvZiBzb21lIHB1bmNoaW5nIGJhZyBzb21ld2hlcmUu
IElzCj4gdGhpcyBhIG5vcm1hbCByZWFjdGlvbiB3aGVuIG9uZSBpcyB0cnlpbmcgdG8gbGVhcm4g
dG8gcHJvZ3JhbSBmb3IgdGhlCj4gZmlyc3QgdGltZT8KCkkndmUgYmVlbiBwcm9ncmFtbWluZyBm
b3Igb3ZlciAyMCB5ZWFycyBhbmQgSSAqc3RpbGwqIGZlZWwgbGlrZSB0aGF0CnNvbWV0aW1lcy4g
IFdoaWxlIEkgY2FuJ3Qgc2F5IHdoYXQgd2F5IGlzIGRlZmluaXRpdmVseSBiZXN0IHRvIGRlYWwK
d2l0aCBpdCwgSSB0ZW5kIHRvIHRha2UgYSBmaXZlIG9yIHRlbiBtaW51dGUgd2FsayB3aGVuIEkg
Z2V0IHRvCmZlZWxpbmcgbGlrZSB0aGF0LiAgT2Z0ZW4sIGJ5IHRpbWUgdGhhdCB0aGF0J3MgZG9u
ZSwgSSd2ZSBnb3QgYSBmcmVzaAppZGVhIGZvciBob3cgdG8gYXBwcm9hY2ggdGhlIHByb2JsZW0s
IG9yIEkndmUgdGhvdWdodCBvZiBzb21ldGhpbmcgSQptYXkgYmUgbWlzc2luZy4KCkNoZWVycywK
Cmtqdwo=
 
C

Chris Alfeld

I recommend dancing. Reading fiction also often works for me.

kj is right, I've been programming for almost 15 years now and
frustration is a frequent companion.
 
B

Benjohn Barnes

On 29 Mar 2006, at 22:33, Jan_K wrote:
*snip*
I'm stuck in "Flow Control" chapter, specificailly the "Extend Deaf
Grandma" exercise.

I feel like beating the shit out of some punching bag somewhere. Is
this a normal reaction when one is trying to learn to program for the
first time?

:)

Fancy describing the problem, and seeing if someone's got some
thoughts on it? Top programming tip - it's amazing how often trying
to explain a problem will suddenly make you realise what the answer
is. Curious, but true.
 
J

Jeppe Jakobsen

------=_Part_10640_16917383.1143669558320
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

You could use until or if (or both). You could make a variable the would
count how many times in a row you said "BYE" to grandma, starting at 0 of
cause, and make it add 1 each times and reset it to 0 if you did not say
"BYE".

Here is an example:

counter =3D 0

Until (counter =3D=3D 3)
tell_grandma =3D gets.chomp
if (tell_grandma =3D=3D "BYE")
counter +=3D 1
end
end

Just find a way to integrate with your current grandma program :)
 
J

Jeppe Jakobsen

------=_Part_10680_27185412.1143669736152
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

forgot to make it set counter to 0 if it wasn't "BYE", but I'm sure you can
figure that out using else.
 
P

paul.denlinger

Sometimes I find myself leaving a problem without trying to analyze it,
and then when I come back again, it works. Most of the time, I can't
figure out why... I just scratch my head and think "What did I do
different _this time_?"

The encouraging thing about this is that as you get better, the time
between the head scratching gets longer.

Another resource you can try Ruby on when you get frustrated with Pine
is http://tryruby.hobix.com/
This is interactive and fun, and was written by someone who is
certifiably insane. (He wrote Poignant's Guide.)

Paul
 
J

Jan_K

forgot to make it set counter to 0 if it wasn't "BYE", but I'm sure you can
figure that out using else.


I can't use "Until" because it wasn't covered in the book so far (even
though it seems pretty straightforward what it does). Ditto for "+-"

What was covered so far up until this chapter:

if, else, elsif, while

The first thing I tried was nesting IF's and WHILE's in different
combinations without using a variable to track the "BYE"s. I thought
that this would be the elegant solution, but really couldn't come up
with a way to do it.

So then I falled back to my first idea of "use variable to track
BYE's." But it looks like I'm not understanding the rules of nesting
and when/how a branch finishes and kicks you back to the previous
branch.

Here's what I had when I gave up:

------------------------------------------
input = gets.chomp
number = rand(21)

number2 = 0
keep_count = 0

if keep_count != 3
while
input != 'BYE'
puts 'HUH?! SPEAK UP, SONNY!'
keep_count = 0
input = gets.chomp
while
input == 'BYE'
puts 'HUH?! SPEAK UP, SONNY!'
number2 = (keep_count + 1)
keep_count = number2
input = gets.chomp
end
end
else
puts 'NO, NOT SINCE ' + (1930 + number).to_s + '!'
end
-----------------------------------------


And here's the regular Deaf Grandma solution that I used:

----------------------------------------
input = gets.chomp
number = rand(21)

if
while
input != 'BYE'
puts 'HUH?! SPEAK UP, SONNY!'
input = gets.chomp
end
else
puts 'NO, NOT SINCE ' + (1930 + number).to_s + '!'
end
 
D

Dave Burt

Hi Jan,

Have you been typing his examples into IRB and running them as you go? I
found that technique really useful learning Perl - try variations on the
example code until you understand it. Try reading Chapter 6 again with IRB,
including the mini exercise in the Looping section.

But let's unpack your code while it's here:

Jan said:
Here's what I had when I gave up:

------------------------------------------
input = gets.chomp
number = rand(21)

number2 = 0
keep_count = 0

if keep_count != 3
while
input != 'BYE'
puts 'HUH?! SPEAK UP, SONNY!'
keep_count = 0
input = gets.chomp
while
input == 'BYE'
puts 'HUH?! SPEAK UP, SONNY!'
number2 = (keep_count + 1)
keep_count = number2
input = gets.chomp
end
end
else
puts 'NO, NOT SINCE ' + (1930 + number).to_s + '!'
end
-----------------------------------------


And here's the regular Deaf Grandma solution that I used:

----------------------------------------
input = gets.chomp
number = rand(21)

if
while
input != 'BYE'
puts 'HUH?! SPEAK UP, SONNY!'
input = gets.chomp
end
else
puts 'NO, NOT SINCE ' + (1930 + number).to_s + '!'
end
-------------------------------------

When you start dealing with flow control, you'll find that indenting makes a
big difference to how easy it is to read and understand your code. Let's
start by indenting your Grandma code:

if
while
input != 'BYE'
puts 'HUH?! SPEAK UP, SONNY!'
input = gets.chomp
end
else
puts 'NO, NOT SINCE ' + (1930 + number).to_s + '!'
end

Note in all Chris' examples, "if" and "while" are always followed by a
condition. If Ruby expects something, but doesn't get it, it'll wait until
the following line. That's what's happening with your if and while. It's the
same as this:

if (while input != 'BYE'
puts 'HUH?! SPEAK UP, SONNY!'
input = gets.chomp
end)
else
....

See, while's condition is "input != 'BYE'", and if's condition is the result
of the whole while loop. The result of a while loop is always nil, so the
condition is always false, so you get 'NO, NOT SINCE'...

That means this section of your program is the same as this:

while input != 'BYE'
puts 'HUH?! SPEAK UP, SONNY!'
input = gets.chomp
end
puts 'NO, NOT SINCE ' + (1930 + number).to_s + '!'

Indenting and putting the condition on the same line as the "if" or "while"
make the flow of your other program a little easier to see, too.

if keep_count != 3
while input != 'BYE'
puts 'HUH?! SPEAK UP, SONNY!'
keep_count = 0
input = gets.chomp
while input == 'BYE'
puts 'HUH?! SPEAK UP, SONNY!'
number2 = (keep_count + 1)
keep_count = number2
input = gets.chomp
end
end
else
puts 'NO, NOT SINCE ' + (1930 + number).to_s + '!'
end

Note you've got a loop inside a loop. To get out of that, the inside loop
has to exit, and then the outside loop, and if you look at their respective
conditions (input == 'BYE') and (input != 'BYE'), that will never happen.

Try going back to the example in the Looping section, and modifying that
little bits at a time. Indent lines inside control structures to help you
see at a glance where they begin and end.

Cheers,
Dave
 
B

Bil Kleb

kj said:
I've been programming for over 20 years and I *still* feel like that
sometimes. While I can't say what way is definitively best to deal
with it, I tend to take a five or ten minute walk when I get to
feeling like that. Often, by time that that's done, I've got a fresh
idea for how to approach the problem, or I've thought of something I
may be missing.

Good advice.

See also the Programming and Development episodes of Ward's "EPISODES:
A Pattern Language of Competitive Development" available
at http://c2.com/ppr/titles.html and the episode failure notes from
his Seattle XP talk: http://www.seapig.org/WardCunningham

Regards,
 
J

Jan_K

When you start dealing with flow control, you'll find that indenting makes a
big difference to how easy it is to read and understand your code.

It is indented. Must be your client.

Try this:

Tools --> Options --> Read tab

Check "Read all messages in plain text"


Note you've got a loop inside a loop. To get out of that, the inside loop
has to exit, and then the outside loop, and if you look at their respective
conditions (input == 'BYE') and (input != 'BYE'), that will never happen.

<snip>

The problem was that I didn't realize that I messed up the first
Grandma program (which reinforced some misconceptions because the
program was working ok). Then I sort of got this idea that I had to
use a loop inside a loop and really couldn't get out of that box.

Everything is obvious now.

Agony of defeat, ecstacy of success.


Anyway, here's the final program:

(hopefully I don't have any superfluous code this time around)


-----------------------------------------------------------------
number = rand(21)
number2 = 0
keep_count = 0

while keep_count != 3
input = gets.chomp
if input != 'BYE'
keep_count = 0
puts 'HUH?! SPEAK UP, SONNY!'
else
number2 = (keep_count + 1)
keep_count = number2
if keep_count != 3
puts 'HUH?! SPEAK UP, SONNY!'
end
end
end

puts 'NO, NOT SINCE ' + (1930 + number).to_s + '!'
 
D

Dave Burt

Jan said:
It is indented. Must be your client.

Wow, my client's not displaying tabs. That really kinda sucks. Thanks for
the heads-up!
The problem was that I didn't realize that I messed up the first
Grandma program (which reinforced some misconceptions because the
program was working ok). Then I sort of got this idea that I had to
use a loop inside a loop and really couldn't get out of that box.

Everything is obvious now.

Agony of defeat, ecstacy of success.

Yay!

Once you've got Flow Control, now you can write programs to do real-life
useful tasks!
Anyway, here's the final program:

(hopefully I don't have any superfluous code this time around)

That might be a little much to expect this early in the game :)
-----------------------------------------------------------------
number = rand(21)
number2 = 0
keep_count = 0

while keep_count != 3
input = gets.chomp
if input != 'BYE'
keep_count = 0
puts 'HUH?! SPEAK UP, SONNY!'
else
number2 = (keep_count + 1)
keep_count = number2
if keep_count != 3
puts 'HUH?! SPEAK UP, SONNY!'
end
end
end

puts 'NO, NOT SINCE ' + (1930 + number).to_s + '!'
-----------------------------------------------------------------

The line is "number2 = 0" is superfluous, because the first thing you do is
assign to it, but it does serve to make it obvious to the programmer the
variable exists.

If it was my program, though, I'd drop the variables "number" and "number2",
and just use the formula directly place - they're only used once each. Like
this:
keep_count = keep_count + 1
And like this:
puts 'NO, NOT SINCE ' + (1930 + rand(21)).to_s + '!'

Note you don't need parentheses around the formula on the right-hand side of
an assignment: + is done before =.

Finally, I prefer not to use the negative "if x != y then foo else bar"
because I find easier to understand "if x == y then bar else foo". Another
alternative is to use "unless", which Chris seems not to have introduced in
Chapter 6, but it means "if not". Same for while - "while keep_count != 3"
is the same as "until keep_count == 3".

So here are my changes to your program all together:

keep_count = 0
until keep_count == 3
input = gets.chomp
if input == 'BYE'
keep_count = keep_count + 1
unless keep_count == 3
puts 'HUH?! SPEAK UP, SONNY!'
end
else
keep_count = 0
puts 'HUH?! SPEAK UP, SONNY!'
end
end
puts 'NO, NOT SINCE ' + (1930 + number).to_s + '!'

But, my understanding of the question must be different to yours. I
understand the original should behave like this:
Hello Grandma HUH?! SPEAK UP, SONNY!
HELLO GRANDMA NO, NOT SINCE 1938!
WHAT HASN'T BEEN SINCE 1938? NO, NOT SINCE 1945!
BYE
BYE, BYE

And the 3-times one should be something like:
Hello Grandma HUH?! SPEAK UP, SONNY!
HELLO GRANDMA NO, NOT SINCE 1938!
BYE HUH?! SPEAK UP, SONNY!
BYE HUH?! SPEAK UP, SONNY!
BYE
BYE, BYE

I've written my solutions to these after some whitespace at the end of this
message.

Cheers,
Dave










































# Deaf Grandma
input = gets.chomp
until input == "BYE"
if input == input.upcase
puts "NO, NOT SINCE " + (1930 + rand(21)).to_s + "!"
else
puts "HUH!? SPEAK UP, SONNY!"
end
input = gets.chomp
end
puts "BYE, BYE"

# Extra Deaf Grandma
byes = 0
input = gets.chomp
until byes == 3
if input == "BYE"
byes = byes + 1
else
byes = 0
end
if input == input.upcase
puts "NO, NOT SINCE " + (1930 + rand(21)).to_s + "!"
else
puts "HUH!? SPEAK UP, SONNY!"
end
input = gets.chomp
end
puts "BYE, BYE"
 
D

Dave Burt

JB said:
I'm stuck trying to do the part to make it do '99 bottles of beer on the
wall' song. I get started in what I hope will work and next thing I know I
have way too many variables and nothing makes sense. I even did something
that made it loop the integer 0. I had to Ctrl-c on that one. <sigh>

Here's what I quit trying at, because no matter how many breaks I took or
whatever, it just wasn't making any sense. :
...
I too wish the author had put examples, say on some pages in the back or
something.

But if you ask this group, you can get interactive answers!

Let's start again with that one. We need a loop counting down from 99. So
first, we need a counter.

beer = 99

Now, we need to count it down.

beer = beer - 1

But we need to do that repeatedly - it goes in a loop.

beer = 99
while (something to end the loop?)
beer = beer - 1
end

How long should we keep looping? We don't want to go past zero. In other
words, we loop while our counter is zero or more.

beer = 99
while beer >= 0
beer = beer - 1
end

OK, now we've got the basic structure of the program - one loop, beer starts
at 99, and decreases until it gets to 0. But there's no output yet.

See how you go putting some flesh on that skeleton, JB - post back when
you're done. (I found learning to program it was better to write than read,
so put aside Herr Froelich's solution and make your own!)

Cheers,
Dave
 
J

Jan_K

You're right, I didn't implement one of the features after reading the
exercise instructions again. Oh well. I'll do it tomorrow.

But I just ran your solution and it doesn't work :)

Hello Grandma HUH!? SPEAK UP, SONNY!
HELLO GRANDMA NO, NOT SINCE 1938!
BYE NO, NOT SINCE 1941!
BYE NO, NOT SINCE 1945!
BYE NO, NOT SINCE 1941!
BYE
BYE, BYE


I needed 4 BYE's to get out, not 3.
 
B

Bill Guindon

On 3/29/06 said:
I can't use "Until" because it wasn't covered in the book so far (even
though it seems pretty straightforward what it does). Ditto for "+-"

What was covered so far up until this chapter:

if, else, elsif, while

Here's a very simplified example that I believe uses only what's been
covered up to that point.

last_input =3D ''
goodbye =3D 1

while goodbye < 3
input =3D gets.chomp

if input =3D=3D input.upcase
puts "NO, NOT SINCE " + (1930 + rand(21)).to_s
else
puts "HUH?! SPEAK UP, SONNY!"
end

if input =3D=3D 'BYE' and last_input =3D=3D 'BYE'
goodbye =3D goodbye + 1
else
goodbye =3D 1
end

last_input =3D input
end
 
J

Jan_K

You're right, I didn't implement one of the features after reading the
exercise instructions again. Oh well. I'll do it tomorrow.

But I just ran your solution and it doesn't work :)


BYE, BYE


I needed 4 BYE's to get out, not 3.

Here's the fix:


byes = 0

until byes == 3
input = gets.chomp

if input == "BYE"
byes = byes + 1
else
byes = 0
end
if input == input.upcase
puts "NO, NOT SINCE " + (1930 + rand(21)).to_s + "!"
else
puts "HUH!? SPEAK UP, SONNY!"
end
end
puts "BYE, BYE"
 
J

Jan_K

Here's a very simplified example that I believe uses only what's been
covered up to that point.

last_input = ''
goodbye = 1

while goodbye < 3
input = gets.chomp

if input == input.upcase
puts "NO, NOT SINCE " + (1930 + rand(21)).to_s
else
puts "HUH?! SPEAK UP, SONNY!"
end

if input == 'BYE' and last_input == 'BYE'
goodbye = goodbye + 1
else
goodbye = 1
end

last_input = input
end


I'm not really understanding what last_input is exactly doing. Looks
like nothing.

This works without any problems:


goodbye = 1

while goodbye < 4
input = gets.chomp

if input == input.upcase
puts "NO, NOT SINCE " + (1930 + rand(21)).to_s
else
puts "HUH?! SPEAK UP, SONNY!"
end

if input == 'BYE'
goodbye = goodbye + 1
else
goodbye = 1
end
end
 
B

baumanj

Benjohn said:
Top programming tip - it's amazing how often trying
to explain a problem will suddenly make you realise what the answer
is. Curious, but true.

This is incredibly true. I often will describe my programming problems
to non-programmers who would have essentially no chance of helping me,
but end up doing so just by listening.

An interesting anecdote:

I've been told that there is (or used to be) a rule at the MIT
programming help desk that before you could talk to any of the techs,
you had to fully describe your problem to a stuffed animal called the
"problem bear". It turned out that more than half of the people's
problems were solved by the bear.
 
J

Jan_K

Here's the solution to the Leap Years exercise in the same chapter:

(everything looks OK to me)

------------------------------------------------------------
puts 'Please enter the starting year'
input = gets.chomp
puts 'Please enter the ending year'
input2 = gets.chomp
puts ''
puts 'The following are leap years:'

input = input.to_i - 1

while input < input2.to_i
input = input + 1
if input%4 == 0 || input%400 == 0 && input%100 != 0
puts input.to_s
end
end
---------------------------------------------------------

I might continue posting the solutions for the rest of the book if I
decide to keep on reading.

This way I won't develop any bad habits (because hopefully the
solutions will be scrutinized by at least one other person) and it'll
help anyone else reading the book who gets stuck. I doubt the author
of the book will ever get around to publishing the "official"
solutions.
 
D

Dave Burt

Jan said:
You're right, I didn't implement one of the features after reading the
exercise instructions again. Oh well. I'll do it tomorrow.

But I just ran your solution and it doesn't work :)
...
I needed 4 BYE's to get out, not 3.

You're absolutely right. I should claim that I put the error in deliberately
so you could debug it, but I didn't. So the lesson (for me) is: TEST your
code, Dave!
Here's the fix:
...

Great work. You fixed it without making it longer; in fact, you made it
shorter!

Sounds to me like you'll be fine, but of course you can ask the list here
any questions you have along the way, we love to help.

Cheers,
Dave
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top