Forum: Ruby Learn to Program, by Chris Pine

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Jan_K (Guest)
on 2006-03-30 01:36
(Received via mailing list)
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?
kj WOOLLEY (Guest)
on 2006-03-30 01:45
(Received via mailing list)
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
Chris A. (Guest)
on 2006-03-30 01:54
(Received via mailing list)
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.
Benjohn B. (Guest)
on 2006-03-30 01:57
(Received via mailing list)
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.
Jeppe J. (Guest)
on 2006-03-30 02:00
(Received via mailing list)
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 :)



2006/3/29, Jan_K <removed_email_address@domain.invalid>:
Jeppe J. (Guest)
on 2006-03-30 02:03
(Received via mailing list)
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>:
(Guest)
on 2006-03-30 06:41
(Received via mailing list)
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
Jan_K (Guest)
on 2006-03-30 07:21
(Received via mailing list)
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 :)
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.
Dave B. (Guest)
on 2006-03-30 14:20
(Received via mailing list)
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
Bil K. (Guest)
on 2006-03-30 18:16
(Received via mailing list)
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,
Pistos C. (Guest)
on 2006-03-30 19:48
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.  :)

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
Jan_K (Guest)
on 2006-03-31 01:40
(Received via mailing list)
On Thu, 30 Mar 2006 10:17:55 GMT, "Dave B." 
<removed_email_address@domain.invalid> wrote:

<snip>

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


<snip>

>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 + '!'
Dave B. (Guest)
on 2006-03-31 02:56
(Received via mailing list)
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 :-)

>   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"
JB (Guest)
on 2006-03-31 09:40
(Received via mailing list)
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. <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. :


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.
Dave B. (Guest)
on 2006-03-31 16:59
(Received via mailing list)
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. <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
Jan_K (Guest)
on 2006-03-31 19:24
(Received via mailing list)
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  :)


>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.
Bill G. (Guest)
on 2006-03-31 21:11
(Received via mailing list)
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
Jan_K (Guest)
on 2006-03-31 21:54
(Received via mailing list)
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
Jan_K (Guest)
on 2006-03-31 21:57
(Received via mailing list)
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"
Bill G. (Guest)
on 2006-03-31 22:09
(Received via mailing list)
On 3/31/06, Jan_K <removed_email_address@domain.invalid> wrote:
> >> if, else, elsif, while
> >
> >  end
> >
> >  last_input = input
> >end
>
>
> I'm not really understanding what last_input is exactly doing. Looks
> like nothing.

I may be reading ahead of you, but it doesn't look like it.
http://pine.fm/LearnToProgram/?Chapter=06

It's there to honor this spec:
"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."

It's making sure that it exits when you say:
"BYE", "BYE", "BYE"

but it won't exit if you say:
"BYE", "DOG", "BYE", "BYE"

If that's what you typed, on the third input, last_input would be
"DOG", so 'goodbye' would get reset to '1'.
(Guest)
on 2006-03-31 23:02
(Received via mailing list)
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.
Jan_K (Guest)
on 2006-04-01 01:56
(Received via mailing list)
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.
Dave B. (Guest)
on 2006-04-01 05:29
(Received via mailing list)
Jan K 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  :)
>...
>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
Dave B. (Guest)
on 2006-04-01 06:05
(Received via mailing list)
Jan K wrote:
> 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.

I just looked at the book samples at pragprog and was surprised to see
there
are no solutions. That probably means Chris doesn't intend to do
official
solutions. Ah, well. Your points are all valid, posting solutions is a
good
idea all 'round.

Now, scrutiny and no bad habits. You've only made one mistake, but I'll
point out a couple of things that could be done differently.

> puts ''

That's the same as just "puts" by itself, with no parameters.

> input = input.to_i - 1

You can avoid going backwards here by moving "input = input + 1" to the
end
of the loop. It often makes things simpler to do the increment at the
end
rather than the beginning of a loop.

> if input%4 == 0 || input%400 == 0 && input%100 != 0

Here's the mistake.

1984 and 2004 are leap years. OK.
1800 and 1900 are not leap years. Not OK - this program lists them as
leap
years.
1600 and 2000 are leap years. OK.

In case this info helps, && binds more closely than ||, so what you've
got
is the same as:

if input%4 == 0 || (input%400 == 0 && input%100 != 0)

You should be able to rearrange it to give the correct result for the
1984,
2004, 1800, 1900, 1600 and 2000.

Cheers,
Dave
Christian N. (Guest)
on 2006-04-01 14:08
(Received via mailing list)
"Dave B." <removed_email_address@domain.invalid> writes:

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

And therefore, we write in Ruby:

99.downto(1) { |bottles| ... }
Dave B. (Guest)
on 2006-04-01 17:05
(Received via mailing list)
Christian N. wrote:
>> Let's start again with that one. We need a loop counting down from 99.
>
> And therefore, we write in Ruby:
>
> 99.downto(1) { |bottles| ... }

A good point, Christian, and that syntax is introduced in the very next
chapter after the one we're doing exercises from. It's good to be able
to do
things more than one way.

Cheers,
Dave
Marcus Lunzenauer (Guest)
on 2006-04-01 17:23
(Received via mailing list)
Hello!

To sum the digits of an Integer I have got

class Integer
   def sum_digits()
     sum = 0
     n = self
     begin sum += n % 10; n /= 10 end while n > 0
     sum
   end
end


Is there a more Ruby Way to do this? The above method smells of Java,
doesn't it?

Thanks, Marcus
James G. (Guest)
on 2006-04-01 18:31
(Received via mailing list)
On Apr 1, 2006, at 7:22 AM, Marcus Lunzenauer wrote:

>   end
> end
>
>
> Is there a more Ruby Way to do this? The above method smells of
> Java, doesn't it?

Here is what I thought of when reading this:

 >> class Integer
 >>   def sum_digits
 >>     to_s.split("").inject(0) { |sum, n| sum + n.to_i }
 >>   end
 >> end
=> nil
 >> 1234.sum_digits
=> 10

Hope that helps.

James Edward G. II
Jan_K (Guest)
on 2006-04-01 18:46
(Received via mailing list)
On Sat, 01 Apr 2006 02:03:13 GMT, "Dave B." 
<removed_email_address@domain.invalid> wrote:

Crap, I knew I should have fully tested my code.

<snip>

>is the same as:
>
>if input%4 == 0 || (input%400 == 0 && input%100 != 0)
>
>You should be able to rearrange it to give the correct result for the 1984,
>2004, 1800, 1900, 1600 and 2000.

Yep.

if input%100 != 0 && input%4 == 0 || input%400 == 0


Fix:

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

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


1 line shorter at the expense of readability and performance:

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

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

I actually did a little benchmark calculating all the leap years for
the next 100 million years (with output going to nul).

Results:

13:26 minutes for the first one.
14:56 minutes for the second one.

The shorter code was 11.16% slower.
unknown (Guest)
on 2006-04-01 19:36
(Received via mailing list)
Jan_K wrote:
> >1984 and 2004 are leap years. OK.
> >2004, 1800, 1900, 1600 and 2000.
> input = gets.chomp
> 		end
> puts 'Please enter the ending year'
> -------------------------------------------------------------------------------
>
> I actually did a little benchmark calculating all the leap years for
> the next 100 million years (with output going to nul).
>
> Results:
>
> 13:26 minutes for the first one.
> 14:56 minutes for the second one.
>
> The shorter code was 11.16% slower.


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

 while input <= input2
     if inputi % 100 != 0 && input % 4 == 0 || input % 400 == 0
 	puts input.to_s
     end
 input = input + 1
 end
Jan_K (Guest)
on 2006-04-01 20:21
(Received via mailing list)
On 1 Apr 2006 07:32:50 -0800, removed_email_address@domain.invalid wrote:

Cool.
Logan C. (Guest)
on 2006-04-02 03:52
(Received via mailing list)
On Apr 1, 2006, at 9:29 AM, James Edward G. II wrote:

>>     begin sum += n % 10; n /= 10 end while n > 0
> >> class Integer
> James Edward G. II
>

num_s =  num.to_s
(0...(num_s.length)).inject(0) { |s, i| s += (num_s[i]  - ?0) }

Just to increase confusion and to rely on the properties of ASCII
Dave B. (Guest)
on 2006-04-02 04:20
(Received via mailing list)
Logan C. wrote:
> num_s =  num.to_s
> (0...(num_s.length)).inject(0) { |s, i| s += (num_s[i]  - ?0) }

require 'enumerator'
num.to_s.enum_for(:each_byte).inject(0) { |sum, c| sum + c - ?0 }

Or, in Ruby 1.9 (I think):
num.to_s.each_byte.inject(0) { |sum, c| sum + c - ?0 }

Cheers,
Dave
Jan_K (Guest)
on 2006-04-02 06:16
(Received via mailing list)
Solution for the 1st exercise in chapter 8:

(I'm skipping the 2nd exercise - just a bunch of busywork)


-----------------------------------------------------------------------
input = []

while input.last != ''
  input.push gets.chomp
end

puts input.sort
Dave B. (Guest)
on 2006-04-02 07:59
(Received via mailing list)
Jan_K wrote:
> Solution for the 1st exercise in chapter 8:

You mean chapter 7.

> puts input.sort
> -----------------------------------------------------------------------
>

Very nice!

For exercise 2, writing a program that does something useful is good
practice, and a sort algorithm's simple and therefore a good candidate
if you can get into it.

Or you could just write a game (Blackjack's simple) after you finish
chapter 8.

Cheers,
Dave
David B. (Guest)
on 2006-04-02 08:18
Jan_K wrote:
>
> 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?

Yes, that is a typical outward manifestation, or projection, of the
initial programming learning process.  And, no, it won't go away.  But
there are a few inner thnings on which one needs to focus, as well.  To
wit: start learning to "think outside of the box", be prepared for your
mind to "play tricks" on you, and don't fight the fact that virtually
all of the difficulties you will face at first will be "logic errors" in
your own thinking and not some anomally of the computer.  Adopting this
attitude will help you maintain calmness and reduce stress.  Programming
is mentally hard work.  But the reward is well worth it.  Plus, we here
in the programming community are available to help you!
Jan_K (Guest)
on 2006-04-02 17:30
(Received via mailing list)
On Sun, 02 Apr 2006 03:57:21 GMT, Dave B. <removed_email_address@domain.invalid> 
wrote:

>Jan_K wrote:
>> Solution for the 1st exercise in chapter 8:
>
>You mean chapter 7.
>

I'm actually reading the book and "Arrays and Iterators" is chapter 8.

The book starts with chapter 1 whereas the online tutorial starts with
chapter 0.

Now that I take a look at both it seems like the book is a cleaned-up
and slightly revised version of the tutorial.


Here's the end of chapter 8 from the book:
----------------------------------------------------------------------------------
8.3 A Few Things to Try

? Write the program we talked about at the beginning of this chapter,
one that asks us to type as many words as we want (one word
per line, continuing until we just press Enter on an empty line)
and then repeats the words back to us in alphabetical order. Make
sure to test your program thoroughly; for example, does hitting
Enter on an empty line always exit your program? Even on the
first line? And the second? Hint: There?s a lovely array method
that will give you a sorted version of an array: sort. Use it!

? Rewrite your table of contents program on page 35. Start the
program with an array holding all of the information for your table
of contents (chapter names, page numbers, etc.). Then print out
the information from the array in a beautifully formatted table of
contents.
----------------------------------------------------------------------------------


This the end of the same chapter from the online tutorial:
----------------------------------------------------------------------------------
A Few Things to Try

? Write the program we talked about at the very beginning of this
chapter.
Hint: There's a lovely array method which will give you a sorted
version of an array: sort. Use it!

? Try writing the above program without using the sort method. A large
part of programming is solving problems, so get all the practice you
can!

? Rewrite your Table of Contents program (from the chapter on
methods). Start the program with an array holding all of the
information for your Table of Contents (chapter names, page numbers,
etc.). Then print out the information from the array in a beautifully
formatted Table of Contents.
----------------------------------------------------------------------------------



Some crucially important differences:


From the online tutorial:
----------------------------------------------------------------------------------
languages = ['English', 'German', 'Ruby']

languages.each do |lang|
  puts 'I love ' + lang + '!'
  puts 'Don\'t you?'
end

puts 'And let\'s hear it for C++!'
puts '...'
----------------------------------------------------------------------------------

From the book:
----------------------------------------------------------------------------------
languages = [' English' , ' Norwegian' , ' Ruby' ]

languages.each do |lang|
  puts ' I love ' + lang + ' !'
  puts ' Don\' t you?'
end

puts ' And let\' s hear it for Java!'
puts ' <crickets chirp in the distance>'
Jan_K (Guest)
on 2006-04-02 18:35
(Received via mailing list)
On Sun, 02 Apr 2006 03:57:21 GMT, Dave B. <removed_email_address@domain.invalid> 
wrote:

Actually, I just flipped through the rest of the book and it starts to
diverge quite a bit from the online tutorial starting with the next
chapter and has 4 additional new chapters.

Here are the table of contents from the book:
http://pragmaticprogrammer.com/titles/fr_ltp/index.html


So if I have any more questions I'll post the exercise instructions
first.

Thanks for your help so far Dave. I was completely stuck in that Flow
Control chapter and pretty much became content that another attempt at
learning programming has successfully failed (just like the previous
half dozen times). It's amazing how hard it is to grasp incredibly
fucking simple concepts for the first time.
Jan_K (Guest)
on 2006-04-03 04:11
(Received via mailing list)
Chapter 9, exercise 1 (page 76)

"Fix up the ask method. That ask method I showed you was alright,
but I bet you could do better. Try to clean it up by removing the
variables good_answer and answer. You?ll have to use return to
exit from the loop. (Well, it will get you out of the whole method,
but it will get you out of the loop in the process.) How do you
like the resulting method? I usually try to avoid using return
(personal preference), but I might make an exception here."


Solution:

--------------------------------------------------------------------------------------
def ask question
  while true
    puts question
    reply = gets.chomp.downcase
    if reply == 'yes'
      return true
    elsif reply == 'no'
      return false
    else
      puts 'Please answer "yes" or "no".'
    end
  end
end

puts 'Hello, and thank you for...'
puts
ask 'Do you like eating tacos?'
ask 'Do you like eating burritos?'
wets_bed = ask 'Do you wet the bed?'
ask 'Do you like eating chimichangas?'
ask 'Do you like eating sopapillas?'
puts 'Just a few more questions...'
ask 'Do you like drinking horchata?'
ask 'Do you like eating flautas?'
puts
puts 'DEBRIEFING:'
puts 'Thank you for...'
puts
puts wets_bed
Marcus Lunzenauer (Guest)
on 2006-04-03 13:16
(Received via mailing list)
Thanks a lot! I will try one of your solutions.

Bye, Marcus
(Guest)
on 2006-04-03 15:42
(Received via mailing list)
Just one more way, since I haven't seen a solution that takes advantage
of the no-parameter inject call:

1234.to_s.split('').map {|c| c.to_i }.inject {|i,j| i+j }
=> 10
Dave B. (Guest)
on 2006-04-03 16:01
(Received via mailing list)
Jan_K wrote:
> So if I have any more questions I'll post the exercise instructions
> first.

Good idea; it's sure to avoid further confusion, and I'm sure Mr. Pine
wouldn't mind this kind of use of his text.

> Thanks for your help so far Dave. I was completely stuck in that Flow
> Control chapter and pretty much became content that another attempt at
> learning programming has successfully failed (just like the previous
> half dozen times). It's amazing how hard it is to grasp incredibly
> fucking simple concepts for the first time.

You're more than welcome. I'm chuffed that you say this, and very glad
to have helped.

I love teaching programming. I learnt the basics of programming QBasic
in a day, back in grade 6, from a friend (probably a little less than
the equivalent of what you're up to now). And it is difficult and
strange, new vocabulary, "strings", "methods", but it's so useful once
you've got it. A lot of repetitive tasks can be reduced to a brain
exercise by automating them. (See thread, "Does Ruby simplify our tasks
and lives?") And knowing some of these things help you understand
computers (and bend them to your every whim bwahahaha... oh, you're
still reading?)

But mostly it's just fun.

Cheers,
Dave
Dave B. (Guest)
on 2006-04-03 16:35
(Received via mailing list)
Jan_K wrote:
> Chapter 9, exercise 1 (page 76)
 > ...

Perfect. I can't see any problems at all.

Let me add something, though. Instead of chomping the string, you can
strip it. String#strip removes all whitespace from the beginning and end
of the string, rather than just a single \n from the end.

Cheers,
Dave
Jan_K (Guest)
on 2006-04-03 22:26
(Received via mailing list)
Chapter 9, exercise 2 (page 76)

Old-school Roman numerals. In the early days of Roman numerals,
the Romans didn?t bother with any of this new-fangled subtraction
IX nonsense. No sir, it was straight addition, biggest to littlest -
so 9 was written VIIII, and so on. Write a method that, when
passed an integer between 1 and 3000 (or so), returns a string
containing the proper old-school Roman numeral. In other words,
old_roman_numeral 4 should return 'IIII'. Make sure to test
your method on a bunch of different numbers. Hint: Use the integer
division and modulus methods on page 36.
For reference, these are the values of the letters used:
I = 1 V = 5 X = 10 L = 50
C = 100 D = 500 M = 1000


Solution:
----------------------------------------------------------------
def old_roman_number input

  while input < 1 || input > 3999
    puts 'Please enter a number between 1 and 3999'
    input = gets.chomp.to_i
  end

  m_mod = input%1000
  d_mod = input%500
  c_mod = input%100
  l_mod = input%50
  x_mod = input%10
  v_mod = input%5

  m_div = input/1000
  d_div = m_mod/500
  c_div = d_mod/100
  l_div = c_mod/50
  x_div = l_mod/10
  v_div = x_mod/5
  i_div = v_mod/1

  m = 'M' * m_div
  d = 'D' * d_div
  c = 'C' * c_div
  l = 'L' * l_div
  x = 'X' * x_div
  v = 'V' * v_div
  i = 'I' * i_div

  puts m + d + c + l + x + v + i

end

number = gets.chomp.to_i
old_roman_number(number)
Jan_K (Guest)
on 2006-04-03 22:44
(Received via mailing list)
Chapter 9, exercise 3 (page 76)

Modern Roman numerals. Eventually, someone thought it would
be terribly clever if putting a smaller number before a larger one
meant you had to subtract the smaller one. As a result of this
development, you must now suffer. Rewrite your previous method
to return the new-style Roman numerals, so when someone calls
roman_numeral 4, it should return 'IV'.


Solution:
----------------------------------------------------------------
def roman_numeral input

  while input < 1 || input > 3999
    puts 'Please enter a number between 1 and 3999'
    input = gets.chomp.to_i
  end

  m_mod = input%1000
  d_mod = input%500
  c_mod = input%100
  l_mod = input%50
  x_mod = input%10
  v_mod = input%5

  m_div = input/1000
  d_div = m_mod/500
  c_div = d_mod/100
  l_div = c_mod/50
  x_div = l_mod/10
  v_div = x_mod/5
  i_div = v_mod/1

  m = 'M' * m_div
  d = 'D' * d_div
  c = 'C' * c_div
  l = 'L' * l_div
  x = 'X' * x_div
  v = 'V' * v_div
  i = 'I' * i_div

  if i == 'IIII' && v != 'V'
    i = 'IV'
  elsif i == 'IIII'
    v = 'IX'
    i = ''
  end

  if x == 'XXXX' && l != 'L'
    x = 'XL'
  elsif x == 'XXXX'
    l = 'XC'
    x = ''
  end

  if c == 'CCCC' && d != 'D'
    c = 'CD'
  elsif c == 'CCCC'
    d = 'CM'
    c = ''
  end

  puts m + d + c + l + x + v + i

end

number = gets.chomp.to_i
roman_numeral(number)
Colin (Guest)
on 2006-04-29 22:38
Hello,

thank you very much for all these good answers
(especially to Jan_K and Dave B. ).

Im learning ruby with the same book and get stuck
in chapter 10.2 Rite of Passage:Sorting
this exercise is about array sort algorithms.
Instead of 'array.sort' i have to program my own sort method.

chris pine gives a few hints:
using < to find the smallest word in a list

take two lists  in the method

and these two empty methods

def sort some_array
  recursive_sort some_array, []

end

def recursive_sort unsorted_array, sorted_array

end


After a lot of trying and searching ...

...I found the quicksort algorithm and this code

def quicksort( array )
    if array.size <= 1
        array
    else
        ls, rest = array.partition { |i| i < array[0] }
	puts 'ls:'+ls.to_s
	puts 'rest:'+rest.to_s
        rs, rest = rest.partition { |i| i > array[0] }
	puts 'rs:'+rs.to_s
	puts 'rest2:'+rest.to_s
        quicksort( ls ) + rest + quicksort( rs )


    end
end

Yes this is a possible solution, but array.partion ,double
assignments(ls,rest)
of variables,arrays and the 'short block' (like { |i| i > array[0] })
are not mentioned in any chapter before.

Although I understand the Code above , I'm looking for an easy solution
that don't leave the scope of chaper 1 to 10 .

Here's my own code, but it doesn't work .


def ownsort unsort, sort
 rest=[]
 rs=[]
 if unsort.size <= 1
   unsort
 else
   unsort.each do |i|
     if i <unsort[0]

       sort.push i
     else
       rest.push i
     end
   end

 end
  rest
end


thanks for reading and hopefully some hints...

colin
Marco Bottaro (Guest)
on 2006-05-03 21:09
(Received via mailing list)
I'm not quite sure there are solutions. However, as a fellow beginning
programmer, I would enjoy discussing our solutions since I finished that
book only one week ago.

Cheers,

Marco
Jeff de Vries (Guest)
on 2006-05-03 21:09
(Received via mailing list)
Restricting to what is covered in chapters 1-10, how about the
following?

def sort some_array
   recursive_sort some_array, []
end

def recursive_sort unsorted_array, sorted_array
   if unsorted_array.size == 0
     return sorted_array
   else
     smallest = unsorted_array[0]
     unsorted_array.each do |x|
       if x < smallest
         smallest = x
       end
     end
     new_unsorted_array = []
     unsorted_array.each do |x|
       if x == smallest
         sorted_array.push(x)
       else
         new_unsorted_array.push(x)
       end
     end
     recursive_sort new_unsorted_array, sorted_array
   end
end
Jeremy T. (Guest)
on 2006-05-03 21:09
(Received via mailing list)
> On Thursday, March 30, 2006, at 6:33 AM, Jan_K wrote:
>> 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?

Not exactly, but I suppose it depends on the person. Perhaps you need
to take a page out of the carpenters handbook and walk away for a
while, then come back to the problem.

>> Jan

--
Jeremy T.
removed_email_address@domain.invalid

"You cannot depend on your eyes, when your imagination is out of
focus." -- Mark Twain
Colin (Guest)
on 2006-05-04 14:30
Jeff de Vries wrote:
> Restricting to what is covered in chapters 1-10, how about the
> following?

Thank you Jeff,
Your Code looks great and I think it is exactly what I'm looking for.

Next I will try to answer your question about the Restriction.

The first ten chapters of the book covers
only a few array methods like each,join,last,length,pop.
no partition, no selection or double assignment.
Futhermore we have  if -else,elsif- end, do-end,while-end,puts, gets
(with chomp,downcase),array=[],times(3.times do...)
we have basics like numbers and strings ,variables assignment,
comparison methods (==,!=,<,>...),writing own methods (def- end)

In Chapter 11-14 the author talks about:

reading and writing files, creating classes,YAML,Blocks and Procs
and a hint to other learning resources like Programming Ruby or this
mailing-list...

The book is a great starting point with many exercises.
It is great to learn programming. It's explains Basic 'Thinking-Skills'
of
programming and  how ruby works.

The author provides only one way to do something. This limitation is
great.
I have no problems with the excercises until chapter 10.
And Chapter 11 should be not so hard to understand (hopefully...)


BTW:
The book is the extended Version of this Tutorial:

http://pine.fm/LearnToProgram/

greetings

Colin
He F. (Guest)
on 2006-08-22 18:03
For interest, before I bought the book I did this exercise for the
online tuorial.  That was before I knew about recursives,  here is what
I came up with... it works, but it's not pretty



words_array = []
puts 'Please enter any word'
word = gets.chomp

while word != ''
  words_array.push word
  puts 'Great, please enter another word'
  word = gets.chomp
end

sorted_array = []

words_array.each do |word|
  if word.to_s.downcase > sorted_array.last.to_s.downcase
    #add word to the end of sorted_array
    sorted_array.push word

  else
    index = (sorted_array.length) - 1
    initial_number = index
    temp_array = []

    #check word against next word in sorted_array and repeat
    while word.to_s.downcase < sorted_array[index].to_s.downcase
      #add the sorted_array to a temp_array up to that point
      temp_array[index] = sorted_array[index]
      #erase words in sorted_array up to that point
      sorted_array.pop
      index = index - 1
    end

    #add the word to sorted_array
    sorted_array.push word

    #add one by one the words from temp_array to sorted_array
    while index < initial_number
      sorted_array.push temp_array[index + 1]
      index = index + 1
    end
  end
end

puts sorted_array
Mike A. (Guest)
on 2006-10-09 06:46
I'm having some issues modifying the Civ continent example from ch. 10
to account for coordinates that are outside the array.  I added the
following line:

if ((y <= 10 && y > 0) && (x <= 10 && x > 0))

before...

  # So, first we count this tile...
  size = 1
  world[y][x] = 'counted land'


    # ...then we count all of the
    # neighboring eigth tiles (and,
    # of course, their neighbors via recursion)
    size = size + continent_size(world, x-1, y-1) #4,4
    size = size + continent_size(world, x  , y-1) #5,4
    size = size + continent_size(world, x+1, y-1) #6,4
    size = size + continent_size(world, x-1, y  ) #4,5
    size = size + continent_size(world, x+1, y  ) #6,5
    size = size + continent_size(world, x-1, y+1) #4,6
    size = size + continent_size(world, x  , y+1) #5,6
    size = size + continent_size(world, x+1, y+1) #6,6
    size
end

As a result, I get the following error:

TypeError: nil can't be coerced into Fixnum

method +	in civilization.rb at line 35
method continent_size	in civilization.rb at line 35
method continent_size	in civilization.rb at line 35
method continent_size	in civilization.rb at line 36
method continent_size	in civilization.rb at line 35
method continent_size	in civilization.rb at line 40
method continent_size	in civilization.rb at line 39
method continent_size	in civilization.rb at line 41
method continent_size	in civilization.rb at line 39
method continent_size	in civilization.rb at line 41
method continent_size	in civilization.rb at line 39
method continent_size	in civilization.rb at line 36
method continent_size	in civilization.rb at line 35
at top level	in civilization.rb at line 48

This error appears regardless of whether the arguments I pass are in 5,5
(as in the example Chris P. wrote out) or something like 10,10 (which
is on the edge of the 'continent').

Is that the right conditional statement?  Could it be in the wrong place
in the method?
Mariano K. (Guest)
on 2006-10-09 23:02
(Received via mailing list)
Hi Mike,

   I don't know the book and that is probably true for a lot of the
people here. Maybe you should include the full source code.
Especially interesting would be to see the line numbers as the
interpreter clearly indicates where the problem occurs.

   As a totally wild guess ... The error message says that the right
side of an addition is nil. So looking at your code, "size" seems to
be set, maybe continent_size does return nil?

   What I also think is strange is that "world" seems to be a two
dimensional array when you first mention it (world[x][y] = 'counted
land'), but later on you pass it to continent size along with two
parameters. This might be ok, if continent_size defines three
parameters, like this:

   def continent_size(world, x, y); end

   and you use x and y to access the array then?!

   I don't know about the conditional. What are you trying to check?
That both x and y are between 1 and 10? That should work ... Even
though you wouldn't need the braces as it all of the conditionals
need to be true for the whole expression to become true. This would
be different if you use "or".

   Hope that helps!

Cheers,
Mariano
Mike A. (Guest)
on 2006-10-10 06:32
here's the whole code...

# These are just to make the map easier to read.  "M" is
# visually more dense than "o".

M = 'land'
o = 'water'

world = [[M,o,o,o,o,o,o,o,o,o,M],
              [o,M,M,o,M,M,o,o,o,M,M],
              [o,o,M,M,o,o,o,o,M,M,o],
              [o,o,o,M,o,o,o,o,o,M,o],
              [o,o,o,M,o,M,M,o,o,o,o],
              [o,o,o,o,M,M,M,M,o,o,o],
              [o,o,o,M,M,M,M,M,M,M,o],
              [o,o,o,M,M,o,M,M,M,o,o],
              [o,o,M,M,o,o,M,M,M,o,o],
              [o,M,M,M,o,M,o,o,o,M,M],
              [M,o,o,o,o,o,o,o,o,o,M]]

def continent_size world, x, y
  if world[y][x] != 'land'
    # either it's water or we've already counted it; we don't want to
count it
    # again
    return 0
  end

  if ((y <= 10 && y > 0) && (x <= 10 && x > 0))
  # So, first we count this tile...
  size = 1
  world[y][x] = 'counted land'


    # ...then we count all of the
    # neighboring eigth tiles (and,
    # of course, their neighbors via recursion)
    size = size + continent_size(world, x-1, y-1)
    size = size + continent_size(world, x  , y-1)
    size = size + continent_size(world, x+1, y-1)
    size = size + continent_size(world, x-1, y  )
    size = size + continent_size(world, x+1, y  )
    size = size + continent_size(world, x-1, y+1)
    size = size + continent_size(world, x  , y+1)
    size = size + continent_size(world, x+1, y+1)
    size
  end
end

puts continent_size(world, 5, 5) #this should be fine; but what about
(11,11)?
Mariano K. (Guest)
on 2006-10-10 10:43
(Received via mailing list)
Hi Mike,

   what your guard should do is prevent the recursion go across the
boundaries of your world, right?

   I would put the guard at the beginning of the method to make sure
that the rest of the method can be sure of handling valid data.

   if x < 0 || x > 10 || y < 0 || y > 10
     return 0 # respect the world's boundaries
   end


> def continent_size world, x, y
>   if world[y][x] != 'land'
>     # either it's water or we've already counted it; we don't want to
> count it
>     # again
>     return 0
>   end
That's a bit of a problem as your code might already call with out of
bounds coordinates.
Put the boundary guard (see above) before that.

>   if ((y <= 10 && y > 0) && (x <= 10 && x > 0))
An array starts to count at zero ... so it needs to be (y <= 10 && y
 >= 0), right?
You have eleven columns and eleven rows. So the array indices are 0..10.

>     size = size + continent_size(world, x+1, y-1)
>     size = size + continent_size(world, x-1, y  )
>     size = size + continent_size(world, x+1, y  )
>     size = size + continent_size(world, x-1, y+1)
>     size = size + continent_size(world, x  , y+1)
>     size = size + continent_size(world, x+1, y+1)
>     size
Ok, you're returning the size here, but

>   end
what are you returning here, if you haven't been in this if-block?

nil. That is a major part of your problem...

> end
Use the code above and put it after the definition of the method.
Remove your own "if" and your method should work.


> puts continent_size(world, 5, 5) #this should be fine; but what about
> (11,11)?
That's up to you. In my code (the guard) it returns 0. So that 11,11
will return 0.
You could also raise an exception that the coordinates are out-of-
bounds, but I guess that will come later in your book and is not that
straight forward applicable here.

Cheers,
Mariano
Mike A. (Guest)
on 2006-10-10 16:03
That worked!  Thanks.

-Mike
Mike A. (Guest)
on 2006-10-15 08:51
He Fa:

Good Job!  However, I don't fully understand how this worked.

> words_array.each do |word|
>   if word.to_s.downcase > sorted_array.last.to_s.downcase
>     #add word to the end of sorted_array
>     sorted_array.push word
>
>   else
>     index = (sorted_array.length) - 1
>     initial_number = index
>     temp_array = []


The second WHILE section was where I got really confused.

>     #check word against next word in sorted_array and repeat
>     while word.to_s.downcase < sorted_array[index].to_s.downcase
>       #add the sorted_array to a temp_array up to that point
>       temp_array[index] = sorted_array[index]
>       #erase words in sorted_array up to that point
>       sorted_array.pop
>       index = index - 1
>     end
>
>     #add the word to sorted_array
>     sorted_array.push word
>
>     #add one by one the words from temp_array to sorted_array
>     while index < initial_number
>       sorted_array.push temp_array[index + 1]
>       index = index + 1
>     end
>   end
> end
>
> puts sorted_array

I've been wrapping my head around my own version of the non-recursive
sort for days and haven't made it work.
T. B. (Guest)
on 2007-06-14 01:04
Hello all. Thanks to all the posters who came before me! You've been
tremendous help. I have a quick question on Chapter 11 - Reading and
Writing, Section 11.3:

<quote>
file_name = 'TestFile.txt'
test_string = 'Nothing!'

File.open file_name, 'w' do |f|
  f.write test_string
end

read_string = File.read file_name
puts(read_string == test_string)
</quote>

I poked around the web, but I can't find out what the 'w' is for. Can
anyone shed any light? Muchas gracias in advance.

-Todd
Ball, Donald A Jr (Library) (Guest)
on 2007-06-14 01:10
(Received via mailing list)
>
> </quote>
>
> I poked around the web, but I can't find out what the 'w' is
> for. Can anyone shed any light? Muchas gracias in advance.

http://dev.rubycentral.com/ref/ref_c_file.html#open

the 'w' option opens the file for writing.

- donald
Bill G. (Guest)
on 2007-06-14 01:15
(Received via mailing list)
On 6/13/07, Tm Bo <removed_email_address@domain.invalid> wrote:
> end
>
> read_string = File.read file_name
> puts(read_string == test_string)
> </quote>
>
> I poked around the web, but I can't find out what the 'w' is for. Can
> anyone shed any light? Muchas gracias in advance.

It's the file 'mode'.  w = write.
http://www.zenspider.com/Languages/Ruby/QuickRef.html#15
Chad P. (Guest)
on 2007-06-14 01:15
(Received via mailing list)
On Thu, Jun 14, 2007 at 06:04:25AM +0900, Tm Bo wrote:
> end
>
> read_string = File.read file_name
> puts(read_string == test_string)
> </quote>
>
> I poked around the web, but I can't find out what the 'w' is for. Can
> anyone shed any light? Muchas gracias in advance.

Check out this page:

  http://www.rubycentral.com/book/ref_c_file.html

Looking at it, I see that File.open is sometimes a synonym for File.new,
so I checked File.new, and that's where I found documentation of the use
of characters in that position in the method call.

The w itself basically means "write".  It refers to how you open the
file
(for reading, writing, or both).  Hopefully this gives you a helpful
start on figuring out the rest of the details of how File.new and
File.open work.

I was surprised to find that File.open isn't in my local ri database,
though.
T. B. (Guest)
on 2007-06-14 01:16
Thanks, donald. I don't know why I missed that before.
Nathan T. (Guest)
on 2007-06-14 18:16
(Received via mailing list)
Probably because it makes more sense to people new to Ruby when the code
is
in a more traditional format;

i.e.

File.open(file_name, 'w')

Personally the openess of Ruby cased problems for me when I first moved
over
(and still does sometimes).  I love the fact that you can do things many
different ways in ruby, but when you're trying to learn the language and
you're given 10 different options with 10 different explanations it
becomes
much more confusing than only having 1 or 2 ways.  :(
John J. (Guest)
on 2007-06-14 18:24
(Received via mailing list)
On Jun 13, 2007, at 4:16 PM, Tm Bo wrote:

> Thanks, donald. I don't know why I missed that before.
>
> --
> Posted via http://www.ruby-forum.com/.
>
You will do well to make notes on File and read/write modes!
The basic implementation of this kind of thing is almost the same in
many lanugages, Ruby's is no exception, the style of this comes
straight from C .
You will see it in PHP too, and a host of other languages.. (all C's
children and relatives.)
Some books fail to document this stuff well for beginners. they
either don't want to go there yet, or they forget about it since they
assume you know it from other languages.
Mr. Pine just isn't going there in his book. He's focusing on other
subjects
Kelly T. (Guest)
on 2008-02-02 21:33
This is my take on the same problem:


def roman_num number
set1 = [ 1, 5, 10, 50, 100, 500, 1000 ]
set2 = [ 'I', 'V', 'X', 'L', 'C', 'D', 'M' ]
numeral = []
  while number > 0
    if (number/(set1.last)) >= 1
      roman = (number/(set1.last))
      numeral.push((set2.pop)*roman)
      number = (number%(set1.pop))
    else
      set2.pop
      set1.pop
    end
  end
  puts 'Old Roman Numeral is ' + numeral.join + '.'
end

puts 'Please enter a number to see what it is in old roman numerals.'
number = gets.chomp.to_i
while number < 1 || number > 3999
  puts 'Please enter a number between 1 and 3999'
  number = gets.chomp.to_i
end
roman_num number



Jan_K wrote:
> Chapter 9, exercise 2 (page 76)
>
> Old-school Roman numerals. In the early days of Roman numerals,
> the Romans didn?t bother with any of this new-fangled subtraction
> IX nonsense. No sir, it was straight addition, biggest to littlest -
> so 9 was written VIIII, and so on. Write a method that, when
> passed an integer between 1 and 3000 (or so), returns a string
> containing the proper old-school Roman numeral. In other words,
> old_roman_numeral 4 should return 'IIII'. Make sure to test
> your method on a bunch of different numbers. Hint: Use the integer
> division and modulus methods on page 36.
> For reference, these are the values of the letters used:
> I = 1 V = 5 X = 10 L = 50
> C = 100 D = 500 M = 1000
>
>
> Solution:
> ----------------------------------------------------------------
> def old_roman_number input
>
>   while input < 1 || input > 3999
>     puts 'Please enter a number between 1 and 3999'
>     input = gets.chomp.to_i
>   end
>
>   m_mod = input%1000
>   d_mod = input%500
>   c_mod = input%100
>   l_mod = input%50
>   x_mod = input%10
>   v_mod = input%5
>
>   m_div = input/1000
>   d_div = m_mod/500
>   c_div = d_mod/100
>   l_div = c_mod/50
>   x_div = l_mod/10
>   v_div = x_mod/5
>   i_div = v_mod/1
>
>   m = 'M' * m_div
>   d = 'D' * d_div
>   c = 'C' * c_div
>   l = 'L' * l_div
>   x = 'X' * x_div
>   v = 'V' * v_div
>   i = 'I' * i_div
>
>   puts m + d + c + l + x + v + i
>
> end
>
> number = gets.chomp.to_i
> old_roman_number(number)
Todd B. (Guest)
on 2008-02-03 03:47
(Received via mailing list)
On Feb 2, 2008 1:33 PM, Kelly T. <removed_email_address@domain.invalid> wrote:
>       numeral.push((set2.pop)*roman)
> number = gets.chomp.to_i
> while number < 1 || number > 3999
>   puts 'Please enter a number between 1 and 3999'
>   number = gets.chomp.to_i
> end
> roman_num number

Just for fun. Certainly not great for speed for large numbers, but the
integer max was low so...

H = Hash[*(([1,5,10,50,100,500,1000].zip %w|I V X L C D M|).flatten)]
def roman(n, s="")
  H.keys.sort.reverse.each do |k|
    s << (H[k] * (n / k))
    n %= k
  end
  s
end
puts roman(ARGV[0].to_i)

The usage would simply be "ruby <filename>.rb <number>"

I'm sure someone could come up with a one-liner, though.

Todd
Todd B. (Guest)
on 2008-02-03 04:50
(Received via mailing list)
On Feb 2, 2008 7:47 PM, Todd B. <removed_email_address@domain.invalid> wrote:

>   s
> end
> puts roman(ARGV[0].to_i)
>
> The usage would simply be "ruby <filename>.rb <number>"
>
> I'm sure someone could come up with a one-liner, though.

Actually, better production code that keeps in line with OO concepts
would be...

class Integer
  ROMAN = {
    1 => "I",
    5 => "V",
    10 => "X",
    50 => "L",
    100 => "C",
    500 => "D",
    1000 => "M"
  }

  def roman
    number, roman_string = self, ""
    ROMAN.keys.sort.reverse.each do |key|
      roman_string << (ROMAN[n] * (number/key)
      n %= key
    end
    roman_string
  end
end

#usage
puts 2137.roman
# => "MMCCCXVII"

I'm pretty sure there were better and more thorough examples at
http://www.rubyquiz.com/quiz22.html.

Todd
Todd B. (Guest)
on 2008-02-03 08:03
(Received via mailing list)
On Feb 2, 2008 8:49 PM, Todd B. <removed_email_address@domain.invalid> wrote:
>     1000 => "M"
> end
>
> #usage
> puts 2137.roman
> # => "MMCCCXVII"
>
> I'm pretty sure there were better and more thorough examples at
> http://www.rubyquiz.com/quiz22.html.

gsub('number', 'n') on that code...and there's a missing parenthesis
")" number/key line

Yeah, yeah

That's what I get for not using cut and paste :-)

Todd
Robert H. (Guest)
on 2008-02-03 15:45
BTW a little trick for later, if you i.e. have an array, and find
yourself using a counter, you can stop using the counter and instead use
array.size and check on that value.


I like "Learn to Program" but I never bothered to make the examples.
Like with homework in school many years ago - I did this in school. Not
at home... :-)
Moises T. (Guest)
on 2008-02-04 20:22
(Received via mailing list)
actually ROMAN[key] and not working with numbers having a 9.
Todd B. (Guest)
on 2008-02-04 22:19
(Received via mailing list)
On Feb 4, 2008 12:20 PM, Moises T. <removed_email_address@domain.invalid> wrote:
>  actually ROMAN[key] and not working with numbers having a 9.

Here's the copy and pasted code...

class Integer
 ROMAN = {
   1 => "I",
   5 => "V",
   10 => "X",
   50 => "L",
   100 => "C",
   500 => "D",
   1000 => "M"
 }

 def roman
   n, roman_string = self, ""
   ROMAN.keys.sort.reverse.each do |key|
     roman_string << (ROMAN[key] * (n/key))
     n %= key
   end
   roman_string
 end
end

#usage
puts 2319.roman
# => "MMCCCXVIIII"


cheers,
Todd
Patrick H. (Guest)
on 2008-05-28 21:02
Hey everyone I was having a slight problem with one of the examples in
the book.  I was doing the '99 beers' example and ran into a problem at
the end.  The task asks you to create a prog that will recite the lyrics
for '99 beers on the wall' which seemed fairly easy to do but I wanted
to make it more challenging for myself and make it more grammatically
correct.  So I tried to create an if statement to change the word
'bottles' to 'bottle' when bottles = 1.  I have seen another example
creating a working solution but requires many more lines of code and I
was trying to do it in a more clever way (maybe it is backfiring).  I
just can't figure out why it is not working properly.  Anyway here is
the code:

[code]
bottles = 99
bword = ' bottles'
while bottles != 0
  puts(bottles.to_s + bword + " of beer on the wall!")
  puts(bottles.to_s + bword + " of beer!")
  puts("Take one down and pass it around!")
  bottles = bottles - 1
  puts(bottles.to_s + bword + " of beer on the wall!")
  puts ''
  if bottles == 1
    bword = ' bottle'
  else
    bword = ' bottles'
  end
end
[/code]

and here is the output that isn't showing up as planned:

2 bottles of beer on the wall!
2 bottles of beer!
Take one down and pass it around!
1 bottles of beer on the wall!

1 bottle of beer on the wall!
1 bottle of beer!
Take on down and pass it around!
0 bottle of beer on the wall!

It doesn't work for the first line with a 1 on it and I wanted it to
switch back to 'bottles' with the zero on the last line.  Any thoughts?
Eleanor McHugh (Guest)
on 2008-05-28 21:41
(Received via mailing list)
On 28 May 2008, at 18:05, Patrick Hummer wrote:
>    bword = ' bottle'
>  else
>    bword = ' bottles'
>  end
> end

You need to reorder your logic slightly so that bword is changed as
soon as the bottle count is decremented:

bottle = 99
bword = 'bottles'
while bottles != 0
  puts(bottles.to_s + bword + " of beer on the wall!")
  puts(bottles.to_s + bword + " of beer!")
  puts("Take one down and pass it around!")
  bottles = bottles - 1
  if bottles == 1
    bword = ' bottle'
  else
    bword = ' bottles'
  end
  puts(bottles.to_s + bword + " of beer on the wall!")
  puts ''
end


Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net
----
raise ArgumentError unless @reality.responds_to? :reason
Vickie C. (Guest)
on 2012-08-09 11:44
Jan_K wrote in post #55253:
> 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?

Hi: I googled the book and answers and here's where they are:

http://learntoprogramanswers.blogspot.com/2008/01/...
Alex M. (Guest)
on 2012-08-09 22:05
(Received via mailing list)
Pine's book is, for it's price, rubbish! You can find better on the web
for free. And this applies to most of the  Ruby books out there
See how many actually create a full program with an interface?
Martin A. (Guest)
on 2013-01-23 19:41
Hi! I'm newbie and this are my first steps. This is my solution for
Modern Roman numerals using arrays and each.

<!-- Code -->

romans =
[1000,'M'],[900,'CM'],[500,'D'],[400,'CD'],[100,'C'],[90,'XC'],[50,'L'],[40,'XL'],[10,'X'],[9,'IX'],[5,'V'],[4,'IV'],[1,'I']
result = []

puts "Please enter a number"
num = gets.chomp.to_i

print "\n" + num.to_s + " in Modern Roman Numerals is: "

romans.each do |nroman|
  number  = nroman[0]
  letter  = nroman[1]

  while num >= number
    result.push letter
    num -= number
  end

end

print result.join

<!-- #Code -->


cheers!!

Martin
Ryan D. (Guest)
on 2013-01-23 23:46
(Received via mailing list)
On Jan 23, 2013, at 09:41 , Martin A. <removed_email_address@domain.invalid>
wrote:

> romans.each do |nroman|
>  number  = nroman[0]
>  letter  = nroman[1]

can become:

> romans.each do |nroman|
>   number, letter = nroman

can become:

> romans.each do | (number, letter) |

can become:
This topic is locked and can not be replied to.