Learn to Program, by Chris Pine


#1

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?


#2

On 29/03/06, Jan_K removed_email_address@domain.invalid wrote:
[snip]

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?

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.

Cheers,

kjw


#3

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.


#4

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?

:slight_smile:

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.


#5

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 = 0

Until (counter == 3)
tell_grandma = gets.chomp
if (tell_grandma == “BYE”)
counter += 1
end
end

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

2006/3/29, Jan_K removed_email_address@domain.invalid:


#6

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

2006/3/29, Jeppe J. removed_email_address@domain.invalid:


#7

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


#8

On Thu, 30 Mar 2006 07:03:17 +0900, “Jeppe J.”
removed_email_address@domain.invalid wrote:

Here is an example:
Just find a way to integrate with your current grandma program :slight_smile:
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

Thanks.


#9

kj WOOLLEY wrote:

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,


#10

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 K wrote:

while
end
input = gets.chomp
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


#11

kj WOOLLEY wrote:

On 29/03/06, Jan_K removed_email_address@domain.invalid wrote:
[snip]

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?

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.

Well, might I say that he’s picked a good language to try out. With
other languages, it would be much, much worse. :slight_smile:

A major reason I moved to Ruby is because it vastly reduces (or
sometimes eliminates) frustration while programming. Something [I]
frequently encountered with other languages (C, C++ (esp. Windows
stuff), Java, Perl, Tcl).

Pistos


#12

On Thu, 30 Mar 2006 10:17:55 GMT, “Dave B.” removed_email_address@domain.invalid wrote:

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.

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 + ‘!’


#13

Jan_K wrote:

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’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.

Here’s what I quit trying at, because no matter how many breaks I took
or
whatever, it just wasn’t making any sense. :

puts ‘99 bottles of beer on the wall, 99 bottles of beer,’
‘take one down, pass it around,’
‘98 bottles of beer on the wall!’
song = ‘99 bottles of beer on the wall, 99 bottles of beer,
take one down, pass it around,’
song = 99
song2 = ‘98 bottles of beer on the wall!’
song2 = 99 - 1
last = ‘1 bottle of beer on the wall’
last = 1

if song2 == last
puts ‘Yay!’
else
if song2 - 1
puts
while song == 1
end
endputs ‘99 bottles of beer on the wall, 99 bottles of beer,’
‘take one down, pass it around,’
‘98 bottles of beer on the wall!’
song = ‘99 bottles of beer on the wall, 99 bottles of beer,
take one down, pass it around,’
song = 99
song2 = ‘98 bottles of beer on the wall!’
song2 = 99 - 1
last = ‘1 bottle of beer on the wall’
last = 1
if song2 == last
puts ‘Yay!’
else
if song2 - 1
puts
while song == 1
end
end

I too wish the author had put examples, say on some pages in the back
or
something.


#14

JB wrote:

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.

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


#15

Jan K wrote:

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 :slight_smile:

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”


#16

On Thu, 30 Mar 2006 22:53:30 GMT, “Dave B.” removed_email_address@domain.invalid wrote:

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 :slight_smile:

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.


#17

On 3/29/06, Jan_K removed_email_address@domain.invalid wrote:
[snip]

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 = ‘’
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


#18

On Fri, 31 Mar 2006 10:22:03 -0500, Jan_K removed_email_address@domain.invalid wrote:

HELLO GRANDMA

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”


#19

On Sat, 1 Apr 2006 02:08:40 +0900, “Bill G.” removed_email_address@domain.invalid
wrote:

Here’s a very simplified example that I believe uses only what’s been
else
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


#20

Benjohn B. wrote:

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.